NEXT predates the access work, so the identity layer follows master: access comes from configured groups, instance administrators replace the site administration, and accounts are created by SSO or by an administrator. Kept from NEXT: manual publication with the Review changes panel and shared generator drafts, portable import/export (meguri/v2), the layered generation map with binding provenance, JSM provider changes, contact/approval semantics and the account-owned Person. Dropped: site administration, local sign-up, and the mandatory unique email with its contact/account migrations. The manual-publication migration is renumbered m_0010 after m_0009_access. Accounts without an email still get a Person in every workspace they reach, a changed sign-in email updates the account's person, and an account that loses access keeps its linked person so schedules stay valid. Instance administrators may use Sync and shared drafts. Co-Authored-By: Claude <noreply@anthropic.com>
41 lines
3.1 KiB
JavaScript
41 lines
3.1 KiB
JavaScript
const assert=require('node:assert/strict');
|
|
const fs=require('node:fs');
|
|
const {launchBrowser,isolatedUser,signIn}=require('./support/browser.cjs');
|
|
const base=process.env.MEGURI_BROWSER_URL||'http://127.0.0.1:3000';
|
|
assert(['localhost','127.0.0.1'].includes(new URL(base).hostname));
|
|
(async()=>{
|
|
const browser=await launchBrowser();
|
|
try {
|
|
const page=await browser.newPage({locale:'en-US',viewport:{width:1280,height:900}});
|
|
const errors=[];page.on('pageerror',e=>errors.push(e.message));
|
|
// Sandbox 11 belongs to this suite; workspaces cannot be created, so it starts empty.
|
|
const tester=await isolatedUser({sandbox:11,prefix:'generation-team',display:'Path tester'});
|
|
await signIn(page,tester.username,tester.password);
|
|
await page.getByLabel('Workspace',{exact:true}).waitFor();
|
|
const dialog=page.getByRole('dialog');
|
|
|
|
await page.evaluate(()=>{const a=Alpine.$data(document.body);a.editGenerationRule();a.form.name='Team escalation';a.form.blocks=[a.newBlock('escalation')];});
|
|
await dialog.getByLabel('Recipient type',{exact:true}).selectOption('team_all');
|
|
await dialog.getByLabel('Delay in minutes',{exact:true}).fill('30');
|
|
await page.waitForFunction(()=>{const a=Alpine.$data(document.body);return !a.generationLoading && a.generationResult?.result?.escalations.some(e=>e.steps.some(s=>s.recipient.type==='team_all' && s.delay_minutes===30));});
|
|
assert.equal(await dialog.locator('.generation-step .binding-button.grow:visible').count(),0);
|
|
await dialog.getByLabel('Recipient type',{exact:true}).selectOption('team_random');
|
|
await page.waitForFunction(()=>{const a=Alpine.$data(document.body);return !a.generationLoading && a.generationResult?.result?.escalations.some(e=>e.steps.some(s=>s.recipient.type==='team_random' && s.delay_minutes===30));});
|
|
assert.equal(await dialog.locator('.generation-step .binding-button.grow:visible').count(),0);
|
|
await dialog.getByRole('button',{name:'Use in draft',exact:true}).click();
|
|
await dialog.waitFor({state:'hidden'});
|
|
await page.waitForFunction(()=>{const a=Alpine.$data(document.body);return !a.generationSaving && !a.generationUnsaved();});
|
|
await page.reload();
|
|
await page.waitForFunction(()=>Alpine.$data(document.body).generationDraft?.rules.length);
|
|
await page.evaluate(()=>{const a=Alpine.$data(document.body);a.editGenerationRule(a.generationDraft.rules[0]);});
|
|
assert.equal(await dialog.getByLabel('Recipient type',{exact:true}).inputValue(),'team_random');
|
|
assert.equal(await dialog.getByLabel('Delay in minutes',{exact:true}).inputValue(),'30');
|
|
await page.setViewportSize({width:390,height:844});
|
|
await dialog.getByLabel('Recipient type',{exact:true}).scrollIntoViewIfNeeded();
|
|
fs.mkdirSync('test-results',{recursive:true});await page.screenshot({path:'test-results/generation-team-mobile.png'});
|
|
assert(await page.evaluate(()=>document.documentElement.scrollWidth<=innerWidth));
|
|
assert.deepEqual(errors,[]);
|
|
console.log('PASS: generated team recipient, 30-minute delay, server expansion, shared persistence and mobile');
|
|
}finally{await browser.close();}
|
|
})().catch(e=>{console.error(e);process.exitCode=1;});
|