Files
meguri/tests/browser-site-admin.cjs
T
Ultradesu 5260c2828b
Checks / test (push) Failing after 2m25s
NEXT
2026-10-07 15:30:31 +01:00

66 lines
5.7 KiB
JavaScript

const assert=require('node:assert/strict');
const fs=require('node:fs');
const {launchBrowser}=require('./support/browser.cjs');
const base=process.env.MEGURI_BROWSER_URL||'http://127.0.0.1:3011';
const username=process.env.MEGURI_BROWSER_SITE_USERNAME;
assert(username,'Set MEGURI_BROWSER_SITE_USERNAME to a dedicated test administrator');
assert(['localhost','127.0.0.1'].includes(new URL(base).hostname));
(async()=>{
const browser=await launchBrowser();
try{
const context=await browser.newContext({locale:'en-US',viewport:{width:1400,height:1050}});
const page=await context.newPage();const errors=[];page.on('pageerror',e=>errors.push(e.message));page.on('dialog',d=>d.accept());
await page.goto(base+'/?view=site');
await page.getByLabel('Username',{exact:true}).fill(username);
await page.getByLabel('Password',{exact:true}).fill(process.env.MEGURI_BROWSER_SITE_PASSWORD||'local-browser-test-password');
await page.getByRole('button',{name:'Sign in',exact:true}).click();
await page.getByRole('link',{name:'Site administration',exact:true}).click();
await page.waitForFunction(()=>Alpine.$data(document.body).siteData);
const root=page.locator('.site-admin');
await root.getByLabel('Search',{exact:true}).fill(username);
await root.getByRole('button',{name:'Edit',exact:true}).click();
await root.getByLabel('Display name',{exact:true}).fill('Administration browser test');
await root.getByRole('button',{name:'Save changes',exact:true}).click();
await page.waitForFunction(()=>!Alpine.$data(document.body).busy&&!Alpine.$data(document.body).siteEdit);
await root.getByRole('button',{name:'Authentication',exact:true}).click();
assert(await root.getByText(/Configuration draft only/).isVisible());
await root.getByLabel('Enable OIDC single sign-on',{exact:true}).check();
await root.getByLabel('Allow password login',{exact:true}).uncheck();
await root.getByLabel('Issuer URL',{exact:true}).fill('https://identity.example.com/realms/company');
await root.getByLabel('Client ID',{exact:true}).fill('meguri-browser-test');
await root.getByLabel('Login button label',{exact:true}).fill('Company SSO');
await root.getByRole('button',{name:'Save configuration draft',exact:true}).click();
await page.waitForFunction(()=>!Alpine.$data(document.body).busy);
assert.equal(await page.locator('.error:visible').count(),0);
await page.reload();await page.waitForFunction(()=>Alpine.$data(document.body).siteData);
await root.getByRole('button',{name:'Authentication',exact:true}).click();
assert.equal(await root.getByLabel('Login button label',{exact:true}).inputValue(),'Company SSO');
assert.equal(await root.getByLabel('Allow password login',{exact:true}).isChecked(),false);
fs.mkdirSync('test-results',{recursive:true});await page.screenshot({path:'test-results/site-admin-desktop.png',fullPage:true});
await page.setViewportSize({width:390,height:844});await page.screenshot({path:'test-results/site-admin-mobile.png',fullPage:true});
assert(await page.evaluate(()=>document.documentElement.scrollWidth<=innerWidth));
// Current password authentication stays active despite the saved draft.
const guest=await browser.newContext({locale:'en-US'});const other=await guest.newPage();await other.goto(base);
await other.getByLabel('Username',{exact:true}).fill(username);await other.getByLabel('Password',{exact:true}).fill(process.env.MEGURI_BROWSER_SITE_PASSWORD||'local-browser-test-password');await other.getByRole('button',{name:'Sign in',exact:true}).click();await other.waitForFunction(()=>Alpine.$data(document.body).user);
// Non-admins cannot enumerate the site, even with direct requests.
const ordinary=await browser.newContext();const userPage=await ordinary.newPage();await userPage.goto(base);
const denied=await userPage.evaluate(async()=>{const username='site-member-'+Date.now();const r=await fetch('/api/register',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({username,email:username+'@example.com',display_name:'Ordinary user',password:'local-browser-test-password'})});if(!r.ok)throw new Error('signup');return (await fetch('/api/site')).status;});assert.equal(denied,403);
const created=await userPage.evaluate(async()=>{const session=await (await fetch('/api/session')).json();const result=await fetch('/api/workspaces',{method:'POST',headers:{'Content-Type':'application/json','X-CSRF-Token':session.csrf},body:JSON.stringify({name:'Site UI workspace '+Date.now()})});if(!result.ok)throw new Error('workspace');return {workspace:await result.json(),user:session.user};});
await page.setViewportSize({width:1400,height:1050});
await root.getByRole('button',{name:'Refresh',exact:true}).click();
await page.waitForFunction(()=>!Alpine.$data(document.body).siteLoading);
await root.getByRole('button',{name:'Workspaces',exact:true}).click();
await root.getByLabel('Search',{exact:true}).fill('Site UI workspace');
await root.getByRole('button',{name:'Edit',exact:true}).last().click();
await root.getByLabel('Name',{exact:true}).fill('Site UI renamed workspace');
await root.getByLabel('Grant owner access to',{exact:true}).selectOption({label:username});
await root.getByRole('button',{name:'Save changes',exact:true}).click();
await page.waitForFunction(()=>!Alpine.$data(document.body).busy&&!Alpine.$data(document.body).siteEdit);
assert.equal(await page.locator('.error:visible').count(),0);
assert(await page.evaluate(()=>Alpine.$data(document.body).directoryState.workspaces.some(w=>w.name==='Site UI renamed workspace')));
assert.deepEqual(errors,[]);
await context.close();await guest.close();await ordinary.close();
console.log('PASS: site navigation, profile editing, persisted OIDC draft, unchanged password login, denied non-admin access, desktop/mobile');
}finally{await browser.close();}
})().catch(e=>{console.error(e);process.exitCode=1;});