1 parent
5b56b4a4cc
commit
7fdf4803ed
21 files changed
+49
-35
No files matched your search
@@ -1,10 +1,10 @@
|
||||
const {openSetup}=require('./support/browser.cjs');
|
||||
const {chromium}=require('playwright');
|
||||
|
||||
const assert=require('node:assert/strict');
|
||||
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 chromium.launch({...(process.env.MEGURI_BROWSER_CHANNEL==='chromium'?{}:{channel:process.env.MEGURI_BROWSER_CHANNEL || 'chrome'}),headless:true});
|
||||
const browser=await require('./support/browser.cjs').launchBrowser();
|
||||
const page=await browser.newPage({viewport:{width:1440,height:1100}});page.setDefaultTimeout(10000);
|
||||
const errors=[];page.on('pageerror',e=>errors.push(e.message));
|
||||
const dialog=()=>page.getByRole('dialog');
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
const {chromium}=require('playwright'),assert=require('node:assert/strict');
|
||||
(async()=>{const browser=await chromium.launch({channel:'chrome',headless:true});try{
|
||||
const assert=require('node:assert/strict');
|
||||
(async()=>{const browser=await require('./support/browser.cjs').launchBrowser();try{
|
||||
for(const [user,names] of [['alice',['Acme Engineering','Customer Support','Regional Platform','Commerce Operations']],['bob',['Acme Engineering','Regional Platform']],['carol',['Acme Engineering','Customer Support','Commerce Operations']],['dave',['Acme Engineering']],['erin',['Acme Engineering']]]){
|
||||
const page=await browser.newPage();const errors=[];page.on('pageerror',e=>errors.push(e.message));await page.goto('http://127.0.0.1:3000/');await page.getByLabel('Username',{exact:true}).fill(user);await page.getByLabel('Password',{exact:true}).fill('meguri-demo-only');await page.getByRole('button',{name:'Sign in',exact:true}).click();await page.waitForFunction(()=>window.Alpine&&Alpine.$data(document.body).workspace);
|
||||
const teams=await page.evaluate(()=>Alpine.$data(document.body).directoryState.workspaces);assert.deepEqual(teams.map(t=>t.name).filter(n=>['Acme Engineering','Customer Support','Regional Platform','Commerce Operations'].includes(n)).sort(),names.sort());
|
||||
|
||||
@@ -1 +1 @@
|
||||
const {chromium}=require('playwright'),assert=require('node:assert/strict');(async()=>{const b=await chromium.launch({channel:'chrome',headless:true});try{const p=await b.newPage({viewport:{width:1440,height:1000}}),errors=[];p.on('pageerror',e=>errors.push(e.message));await p.goto('http://127.0.0.1:3000/?view=configuration');await p.getByLabel('Username',{exact:true}).fill('alice');await p.getByLabel('Password',{exact:true}).fill('meguri-demo-only');await p.getByRole('button',{name:'Sign in',exact:true}).click();await p.getByRole('button',{name:'Edit rule Weekly Time off',exact:true}).click();const dialog=p.getByRole('dialog'),popup=p.locator('.binding-popover');await dialog.getByLabel('Delay in minutes',{exact:true}).fill('7');assert.equal(await p.evaluate(()=>Alpine.$data(document.body).form.blocks.find(b=>b.kind==='escalation').steps[0].delay.value),7);await dialog.getByRole('button',{name:'Bind Delay in minutes',exact:true}).click();await popup.waitFor();assert.equal(await popup.getByLabel('Fixed number',{exact:true}).inputValue(),'7');await popup.getByLabel('Value source',{exact:true}).selectOption('lookup');await p.waitForTimeout(50);assert.equal(await popup.getByLabel('Value source',{exact:true}).count(),2);const box=await popup.boundingBox();assert(box.y>=0&&box.y+box.height<=1000);await p.screenshot({path:'test-results/inline-binding-context.png'});await popup.getByLabel('Value source',{exact:true}).first().selectOption('literal');await popup.getByLabel('Fixed number',{exact:true}).fill('10');await popup.press('Escape');await popup.waitFor({state:'detached'});assert(await dialog.isVisible());assert.equal(await dialog.getByLabel('Delay in minutes',{exact:true}).inputValue(),'10');await dialog.getByRole('button',{name:'Bind Delay in minutes',exact:true}).click();await popup.waitFor();await dialog.getByLabel('Rule name',{exact:true}).click();await popup.waitFor({state:'detached'});const preview=dialog.locator('.compact-preview');assert.equal(await preview.getAttribute('open'),null);await preview.locator('summary').click();await preview.screenshot({path:'test-results/compact-preview.png'});assert.deepEqual(errors,[]);console.log('PASS inline delay, anchored nested sources, context, Escape/outside dismissal and collapsed preview');}finally{await b.close();}})().catch(e=>{console.error(e);process.exitCode=1;});
|
||||
const assert=require('node:assert/strict');(async()=>{const b=await require('./support/browser.cjs').launchBrowser();try{const p=await b.newPage({viewport:{width:1440,height:1000}}),errors=[];p.on('pageerror',e=>errors.push(e.message));await p.goto('http://127.0.0.1:3000/?view=configuration');await p.getByLabel('Username',{exact:true}).fill('alice');await p.getByLabel('Password',{exact:true}).fill('meguri-demo-only');await p.getByRole('button',{name:'Sign in',exact:true}).click();await p.getByRole('button',{name:'Edit rule Weekly Time off',exact:true}).click();const dialog=p.getByRole('dialog'),popup=p.locator('.binding-popover');await dialog.getByLabel('Delay in minutes',{exact:true}).fill('7');assert.equal(await p.evaluate(()=>Alpine.$data(document.body).form.blocks.find(b=>b.kind==='escalation').steps[0].delay.value),7);await dialog.getByRole('button',{name:'Bind Delay in minutes',exact:true}).click();await popup.waitFor();assert.equal(await popup.getByLabel('Fixed number',{exact:true}).inputValue(),'7');await popup.getByLabel('Value source',{exact:true}).selectOption('lookup');await p.waitForTimeout(50);assert.equal(await popup.getByLabel('Value source',{exact:true}).count(),2);const box=await popup.boundingBox();assert(box.y>=0&&box.y+box.height<=1000);await p.screenshot({path:'test-results/inline-binding-context.png'});await popup.getByLabel('Value source',{exact:true}).first().selectOption('literal');await popup.getByLabel('Fixed number',{exact:true}).fill('10');await popup.press('Escape');await popup.waitFor({state:'detached'});assert(await dialog.isVisible());assert.equal(await dialog.getByLabel('Delay in minutes',{exact:true}).inputValue(),'10');await dialog.getByRole('button',{name:'Bind Delay in minutes',exact:true}).click();await popup.waitFor();await dialog.getByLabel('Rule name',{exact:true}).click();await popup.waitFor({state:'detached'});const preview=dialog.locator('.compact-preview');assert.equal(await preview.getAttribute('open'),null);await preview.locator('summary').click();await preview.screenshot({path:'test-results/compact-preview.png'});assert.deepEqual(errors,[]);console.log('PASS inline delay, anchored nested sources, context, Escape/outside dismissal and collapsed preview');}finally{await b.close();}})().catch(e=>{console.error(e);process.exitCode=1;});
|
||||
@@ -1,7 +1,7 @@
|
||||
// Read-only draft checks: actual values remain visible alongside server type errors.
|
||||
const {chromium}=require('playwright'),assert=require('node:assert/strict');
|
||||
const assert=require('node:assert/strict');
|
||||
(async()=>{
|
||||
const browser=await chromium.launch({channel:process.env.MEGURI_BROWSER_CHANNEL||'chrome',headless:true});
|
||||
const browser=await require('./support/browser.cjs').launchBrowser();
|
||||
try{
|
||||
const page=await browser.newPage({viewport:{width:1280,height:950}}),errors=[];
|
||||
page.on('pageerror',e=>errors.push(e.message));
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
const {openSetup}=require('./support/browser.cjs');
|
||||
// End-to-end coverage for scheduling contacts, country imports, working hours, and display timezones.
|
||||
const {chromium}=require('playwright');
|
||||
|
||||
const assert=require('node:assert/strict');
|
||||
const fs=require('node:fs');
|
||||
const base=process.env.MEGURI_BROWSER_URL || 'http://127.0.0.1:3000';
|
||||
assert(['localhost','127.0.0.1'].includes(new URL(base).hostname));
|
||||
fs.mkdirSync('test-results',{recursive:true});
|
||||
(async()=>{
|
||||
const browser=await chromium.launch({...(process.env.MEGURI_BROWSER_CHANNEL==='chromium'?{}:{channel:process.env.MEGURI_BROWSER_CHANNEL || 'chrome'}),headless:true});
|
||||
const browser=await require('./support/browser.cjs').launchBrowser();
|
||||
const page=await browser.newPage({viewport:{width:1440,height:1100},timezoneId:'America/Los_Angeles'});
|
||||
page.setDefaultTimeout(10000);const errors=[];page.on('pageerror',e=>errors.push(e.message));
|
||||
const dialog=()=>page.getByRole('dialog');
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
const {openSetup}=require('./support/browser.cjs');
|
||||
// Regression for dependency-aware removal and routing precedence through the real UI/API.
|
||||
const {chromium}=require('playwright');
|
||||
|
||||
const assert=require('node:assert/strict');
|
||||
const fs=require('node:fs');
|
||||
const base=process.env.MEGURI_BROWSER_URL || 'http://127.0.0.1:3000';
|
||||
assert(['localhost','127.0.0.1'].includes(new URL(base).hostname));
|
||||
fs.mkdirSync('test-results',{recursive:true});
|
||||
(async()=>{
|
||||
const browser=await chromium.launch({...(process.env.MEGURI_BROWSER_CHANNEL==='chromium'?{}:{channel:process.env.MEGURI_BROWSER_CHANNEL || 'chrome'}),headless:true});
|
||||
const browser=await require('./support/browser.cjs').launchBrowser();
|
||||
const page=await browser.newPage({viewport:{width:1440,height:1100}});
|
||||
page.setDefaultTimeout(10000);const errors=[];page.on('pageerror',e=>errors.push(e.message));
|
||||
const dialog=()=>page.getByRole('dialog');
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
const {chromium}=require('playwright');
|
||||
|
||||
const assert=require('node:assert/strict');
|
||||
const fs=require('node:fs');
|
||||
const base=process.env.MEGURI_BROWSER_URL||'http://127.0.0.1:3000';
|
||||
assert(['127.0.0.1','localhost'].includes(new URL(base).hostname));
|
||||
fs.mkdirSync('test-results',{recursive:true});
|
||||
(async()=>{
|
||||
const browser=await chromium.launch({channel:process.env.MEGURI_BROWSER_CHANNEL||'chrome',headless:true});
|
||||
const browser=await require('./support/browser.cjs').launchBrowser();
|
||||
const errors=[];
|
||||
async function login(name){const page=await browser.newPage({viewport:{width:1440,height:1050},timezoneId:'America/New_York'});page.setDefaultTimeout(10000);page.on('pageerror',e=>errors.push(e.message));await page.goto(base);await page.getByLabel('Username',{exact:true}).fill(name);await page.getByLabel('Password',{exact:true}).fill('meguri-demo-only');await page.getByRole('button',{name:'Sign in',exact:true}).click();await page.locator('.day').first().waitFor();return page;}
|
||||
async function refresh(page){await page.reload();await page.locator('.day').first().waitFor();}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
const {chromium}=require('playwright');
|
||||
|
||||
const assert=require('node:assert/strict');
|
||||
(async()=>{const b=await chromium.launch({channel:'chrome',headless:true});try{
|
||||
(async()=>{const b=await require('./support/browser.cjs').launchBrowser();try{
|
||||
const p=await b.newPage({viewport:{width:1280,height:950}});await p.goto('http://127.0.0.1:3000');await p.getByLabel('Username',{exact:true}).fill('alice');await p.getByLabel('Password',{exact:true}).fill('meguri-demo-only');await p.getByRole('button',{name:'Sign in',exact:true}).click();await p.waitForFunction(()=>Alpine.$data(document.body).workspace);
|
||||
await p.evaluate(()=>{const a=Alpine.$data(document.body),alice=a.user.id,bob=a.people.find(x=>x.display_name==='Bob Chen').id,schedule=a.doc.schedules[0].id; a.doc.requests=[{id:'test',status:'pending',required_approvers:[alice,bob],approvals:[alice],legs:[{schedule_id:schedule,from_user:alice,to_user:bob,start:'2026-10-08T11:00:00+03:00',end:'2026-10-10T08:00:00.000Z'}]}];a.detail.coverage={total:1,issues:[{schedule_id:schedule,user_id:alice,start:'2026-10-08T08:00:00Z',end:'2026-10-11T08:00:00Z'}]};});
|
||||
const box=p.locator('.coverage-problems');await box.waitFor({state:'visible'});assert.equal(await box.locator('.coverage-issue').count(),2);await box.getByText('Waiting for: Bob Chen',{exact:true}).waitFor();assert.equal(await box.getByText('No substitute assigned',{exact:true}).count(),1);assert.equal(await box.getByText('Awaiting approval',{exact:true}).count(),1);
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
const {chromium}=require('playwright'),assert=require('node:assert/strict');
|
||||
(async()=>{const b=await chromium.launch({channel:'chrome',headless:true});try{const p=await b.newPage({viewport:{width:1280,height:950}}),errors=[];p.on('pageerror',e=>errors.push(e.message));await p.goto('http://127.0.0.1:3000/?view=configuration');await p.getByLabel('Username',{exact:true}).fill('alice');await p.getByLabel('Password',{exact:true}).fill('meguri-demo-only');await p.getByRole('button',{name:'Sign in',exact:true}).click();await p.getByRole('button',{name:'Edit variable on_call',exact:true}).click();const dialog=p.getByRole('dialog'),status=dialog.locator('.modal-footer:visible .validation-toggle');await status.waitFor();assert.equal(await status.getAttribute('aria-expanded'),'false');const original=await p.evaluate(()=>{const a=Alpine.$data(document.body),n=a.form.node.entries[0],v={...n};n.kind='date';n.value='2026-09-24';return v;});await p.waitForFunction(()=>{const a=Alpine.$data(document.body);return !a.generationLoading&&a.generationResult?.issues.some(i=>i.rule_id);});assert.match(await status.innerText(),/Issues to resolve/);assert.equal(await dialog.locator('.generation-errors').count(),0);await status.click();await dialog.getByRole('button',{name:'Edit rule: Weekly Time off',exact:true}).click();await p.waitForFunction(()=>Alpine.$data(document.body).modal==='generation-rule');assert.equal(await p.evaluate(()=>Alpine.$data(document.body).generationDraft.variables.find(v=>v.name==='on_call').node.entries[0].value),'2026-09-24');await p.waitForFunction(()=>!Alpine.$data(document.body).generationLoading);await status.click();await dialog.getByRole('button',{name:'Edit variable: on_call',exact:true}).click();await p.waitForFunction(()=>Alpine.$data(document.body).modal==='variable');await p.evaluate(original=>Object.assign(Alpine.$data(document.body).form.node.entries[0],original),original);await p.waitForFunction(()=>{const a=Alpine.$data(document.body);return !a.generationLoading&&a.generationResult&&!a.generationResult.issues.length;});assert.match(await status.innerText(),/Draft checked/);await p.setViewportSize({width:390,height:844});await p.screenshot({path:'test-results/diagnostics-mobile.png'});assert(await p.evaluate(()=>document.documentElement.scrollWidth<=innerWidth));assert.deepEqual(errors,[]);console.log('PASS persistent diagnostics, primary source links, draft preservation and recovery');}finally{await b.close();}})().catch(e=>{console.error(e);process.exitCode=1;});
|
||||
const assert=require('node:assert/strict');
|
||||
(async()=>{const b=await require('./support/browser.cjs').launchBrowser();try{const p=await b.newPage({viewport:{width:1280,height:950}}),errors=[];p.on('pageerror',e=>errors.push(e.message));await p.goto('http://127.0.0.1:3000/?view=configuration');await p.getByLabel('Username',{exact:true}).fill('alice');await p.getByLabel('Password',{exact:true}).fill('meguri-demo-only');await p.getByRole('button',{name:'Sign in',exact:true}).click();await p.getByRole('button',{name:'Edit variable on_call',exact:true}).click();const dialog=p.getByRole('dialog'),status=dialog.locator('.modal-footer:visible .validation-toggle');await status.waitFor();assert.equal(await status.getAttribute('aria-expanded'),'false');const original=await p.evaluate(()=>{const a=Alpine.$data(document.body),n=a.form.node.entries[0],v={...n};n.kind='date';n.value='2026-09-24';return v;});await p.waitForFunction(()=>{const a=Alpine.$data(document.body);return !a.generationLoading&&a.generationResult?.issues.some(i=>i.rule_id);});assert.match(await status.innerText(),/Issues to resolve/);assert.equal(await dialog.locator('.generation-errors').count(),0);await status.click();await dialog.getByRole('button',{name:'Edit rule: Weekly Time off',exact:true}).click();await p.waitForFunction(()=>Alpine.$data(document.body).modal==='generation-rule');assert.equal(await p.evaluate(()=>Alpine.$data(document.body).generationDraft.variables.find(v=>v.name==='on_call').node.entries[0].value),'2026-09-24');await p.waitForFunction(()=>!Alpine.$data(document.body).generationLoading);await status.click();await dialog.getByRole('button',{name:'Edit variable: on_call',exact:true}).click();await p.waitForFunction(()=>Alpine.$data(document.body).modal==='variable');await p.evaluate(original=>Object.assign(Alpine.$data(document.body).form.node.entries[0],original),original);await p.waitForFunction(()=>{const a=Alpine.$data(document.body);return !a.generationLoading&&a.generationResult&&!a.generationResult.issues.length;});assert.match(await status.innerText(),/Draft checked/);await p.setViewportSize({width:390,height:844});await p.screenshot({path:'test-results/diagnostics-mobile.png'});assert(await p.evaluate(()=>document.documentElement.scrollWidth<=innerWidth));assert.deepEqual(errors,[]);console.log('PASS persistent diagnostics, primary source links, draft preservation and recovery');}finally{await b.close();}})().catch(e=>{console.error(e);process.exitCode=1;});
|
||||
@@ -1,5 +1,5 @@
|
||||
const {chromium}=require('playwright');const assert=require('node:assert/strict');
|
||||
(async()=>{const browser=await chromium.launch({channel:'chrome',headless:true});try{const page=await browser.newPage({viewport:{width:1500,height:1050}});page.setDefaultTimeout(10000);const errors=[];page.on('pageerror',e=>errors.push(e.message));await page.goto('http://127.0.0.1:3000/?view=configuration');await page.getByLabel('Username',{exact:true}).fill('alice');await page.getByLabel('Password',{exact:true}).fill('meguri-demo-only');await page.getByRole('button',{name:'Sign in',exact:true}).click();await page.getByRole('button',{name:'Map',exact:true}).click();const d=page.locator('dialog.generation-map');await d.waitFor();await page.waitForFunction(()=>Alpine.$data(document.body).mapNodes.length>0&&!Alpine.$data(document.body).mapBusy);assert.equal(await d.locator('canvas').count()>0,true);await d.getByLabel('Selected node',{exact:true}).selectOption({label:'Off hours and unmatched alerts'});await page.waitForFunction(()=>document.querySelector('.map-source-list')?.textContent.includes('Time off'));await d.getByLabel('Iteration pass',{exact:true}).selectOption('0');await page.waitForFunction(()=>document.querySelector('.map-input-content')?.innerText.includes('Otherwise'));const inputs=await d.locator('.map-input-content').innerText();assert(inputs.includes('Time off'));assert(inputs.includes('All alerts'));assert(!/[0-9a-f]{8}-[0-9a-f-]{27}/i.test(inputs));assert(!inputs.includes('iteration'));assert(!inputs.includes('null'));assert(await d.locator('.map-input-content .map-reference').count()>0);await d.getByLabel('Selected node',{exact:true}).selectOption({label:'Project owners during working hours'});await page.waitForFunction(()=>document.querySelectorAll('.map-source-card').length===2);const sources=await d.locator('.map-source-list').innerText();assert(sources.includes('projects'));assert(sources.includes('Time off'));assert(sources.includes('responsible'));assert(!sources.includes('Alice'));assert(!sources.includes('different values'));await page.screenshot({path:'test-results/generation-map-inputs.png'});const layout=await page.evaluate(()=>{const a=Alpine.$data(document.body),rules=a.mapNodes.filter(n=>n.step);return {rules,children:a.mapNodes.filter(n=>n.rule&&!n.step)};});assert(layout.rules.every((n,i)=>n.step===i+1 && (!i || n.position.x>layout.rules[i-1].position.x)));for(const n of layout.children){const r=layout.rules.find(r=>r.rule===n.rule);assert.equal(n.position.x,r.position.x);assert(n.position.y>r.position.y);}assert.equal(await d.locator('.map-canvas').evaluate(el=>el._cyreg.cy.edges('[role="order"]').length),layout.rules.length-1);const stack=await d.locator('.map-canvas').evaluate(el=>{const cy=el._cyreg.cy,n=cy.nodes('[kind="batch"]').first();n.position({x:n.position('x')+20,y:n.position('y')+30});const p=n.position(),sheet=cy.getElementById(n.id()+':sheet:2').position();return {x:sheet.x-p.x,y:sheet.y-p.y};});assert.deepEqual(stack,{x:16,y:-16});const canvas=d.locator('.map-canvas'),box=await canvas.boundingBox();const point=await canvas.evaluate(el=>el._cyreg.cy.nodes().filter(n=>n.data('kind')==='variable').first().renderedPosition());await page.mouse.click(box.x+point.x,box.y+point.y);await page.waitForFunction(()=>!!Alpine.$data(document.body).mapCurrent()?.variable);const before=await canvas.evaluate(el=>el._cyreg.cy.pan());await page.mouse.move(box.x+20,box.y+20);await page.mouse.down();await page.mouse.move(box.x+70,box.y+65,{steps:6});await page.mouse.up();const after=await canvas.evaluate(el=>el._cyreg.cy.pan());assert.notDeepEqual(after,before);await d.getByLabel('Selected node',{exact:true}).selectOption({label:'Project · Iteration · 6 passes'});assert.equal(await d.locator('.map-resource').count(),18);const owners=d.locator('.map-resource').filter({has:page.locator('summary > strong').filter({hasText:/^Payments · owners$/})});await owners.locator('summary').click();const ownerFields=owners.locator('.map-resource-fields');await ownerFields.waitFor();const ownerText=await ownerFields.innerText();assert(/Alice Morgan[\s\S]*Bob Chen[\s\S]*Dave Wilson/.test(ownerText));assert(ownerText.includes('Time off'));assert(ownerText.includes('11:00'));assert(!/[0-9a-f]{8}-[0-9a-f-]{27}/i.test(ownerText));assert.equal(await owners.locator('pre').count(),0);await page.screenshot({path:'test-results/generation-map-resource-fields.png'});await d.getByLabel('Iteration pass',{exact:true}).selectOption('0');await page.waitForFunction(()=>Alpine.$data(document.body).mapResources().length===3);await d.getByRole('button',{name:'Expand outputs',exact:true}).click();assert(await d.getByLabel('Selected node',{exact:true}).locator('option').count()>10);await d.getByRole('button',{name:'Zoom in',exact:true}).click();await d.getByRole('button',{name:'Fit all',exact:true}).click();await page.screenshot({path:'test-results/generation-map-desktop.png'});await page.setViewportSize({width:390,height:844});await d.getByRole('button',{name:'Fit all',exact:true}).click();await page.screenshot({paLine truncated
|
||||
const assert=require('node:assert/strict');
|
||||
(async()=>{const browser=await require('./support/browser.cjs').launchBrowser();try{const page=await browser.newPage({viewport:{width:1500,height:1050}});page.setDefaultTimeout(10000);const errors=[];page.on('pageerror',e=>errors.push(e.message));await page.goto('http://127.0.0.1:3000/?view=configuration');await page.getByLabel('Username',{exact:true}).fill('alice');await page.getByLabel('Password',{exact:true}).fill('meguri-demo-only');await page.getByRole('button',{name:'Sign in',exact:true}).click();await page.getByRole('button',{name:'Map',exact:true}).click();const d=page.locator('dialog.generation-map');await d.waitFor();await page.waitForFunction(()=>Alpine.$data(document.body).mapNodes.length>0&&!Alpine.$data(document.body).mapBusy);assert.equal(await d.locator('canvas').count()>0,true);await d.getByLabel('Selected node',{exact:true}).selectOption({label:'Off hours and unmatched alerts'});await page.waitForFunction(()=>document.querySelector('.map-source-list')?.textContent.includes('Time off'));await d.getByLabel('Iteration pass',{exact:true}).selectOption('0');await page.waitForFunction(()=>document.querySelector('.map-input-content')?.innerText.includes('Otherwise'));const inputs=await d.locator('.map-input-content').innerText();assert(inputs.includes('Time off'));assert(inputs.includes('All alerts'));assert(!/[0-9a-f]{8}-[0-9a-f-]{27}/i.test(inputs));assert(!inputs.includes('iteration'));assert(!inputs.includes('null'));assert(await d.locator('.map-input-content .map-reference').count()>0);await d.getByLabel('Selected node',{exact:true}).selectOption({label:'Project owners during working hours'});await page.waitForFunction(()=>document.querySelectorAll('.map-source-card').length===2);const sources=await d.locator('.map-source-list').innerText();assert(sources.includes('projects'));assert(sources.includes('Time off'));assert(sources.includes('responsible'));assert(!sources.includes('Alice'));assert(!sources.includes('different values'));await page.screenshot({path:'test-results/generation-map-inputs.png'});const layout=await page.evaluate(()=>{const a=Alpine.$data(document.body),rules=a.mapNodes.filter(n=>n.step);return {rules,children:a.mapNodes.filter(n=>n.rule&&!n.step)};});assert(layout.rules.every((n,i)=>n.step===i+1 && (!i || n.position.x>layout.rules[i-1].position.x)));for(const n of layout.children){const r=layout.rules.find(r=>r.rule===n.rule);assert.equal(n.position.x,r.position.x);assert(n.position.y>r.position.y);}assert.equal(await d.locator('.map-canvas').evaluate(el=>el._cyreg.cy.edges('[role="order"]').length),layout.rules.length-1);const stack=await d.locator('.map-canvas').evaluate(el=>{const cy=el._cyreg.cy,n=cy.nodes('[kind="batch"]').first();n.position({x:n.position('x')+20,y:n.position('y')+30});const p=n.position(),sheet=cy.getElementById(n.id()+':sheet:2').position();return {x:sheet.x-p.x,y:sheet.y-p.y};});assert.deepEqual(stack,{x:16,y:-16});const canvas=d.locator('.map-canvas'),box=await canvas.boundingBox();const point=await canvas.evaluate(el=>el._cyreg.cy.nodes().filter(n=>n.data('kind')==='variable').first().renderedPosition());await page.mouse.click(box.x+point.x,box.y+point.y);await page.waitForFunction(()=>!!Alpine.$data(document.body).mapCurrent()?.variable);const before=await canvas.evaluate(el=>el._cyreg.cy.pan());await page.mouse.move(box.x+20,box.y+20);await page.mouse.down();await page.mouse.move(box.x+70,box.y+65,{steps:6});await page.mouse.up();const after=await canvas.evaluate(el=>el._cyreg.cy.pan());assert.notDeepEqual(after,before);await d.getByLabel('Selected node',{exact:true}).selectOption({label:'Project · Iteration · 6 passes'});assert.equal(await d.locator('.map-resource').count(),18);const owners=d.locator('.map-resource').filter({has:page.locator('summary > strong').filter({hasText:/^Payments · owners$/})});await owners.locator('summary').click();const ownerFields=owners.locator('.map-resource-fields');await ownerFields.waitFor();const ownerText=await ownerFields.innerText();assert(/Alice Morgan[\s\S]*Bob Chen[\s\S]*Dave Wilson/.test(ownerText));assert(ownerText.includes('Time off'));assert(ownerText.includes('11:00'));assert(!/[0-9a-f]{8}-[0-9a-f-]{27}/i.test(ownerText));assert.equal(await owners.locator('pre').count(),0);await page.screenshot({path:'test-results/generation-map-resource-fields.png'});await d.getByLabel('Iteration pass',{exact:true}).selectOption('0');await page.waitForFunction(()=>Alpine.$data(document.body).mapResources().length===3);await d.getByRole('button',{name:'Expand outputs',exact:true}).click();assert(await d.getByLabel('Selected node',{exact:true}).locator('option').count()>10);await d.getByRole('button',{name:'Zoom in',exact:true}).click();await d.getByRole('button',{name:'Fit all',exact:true}).click();await page.screenshot({path:'test-results/generation-map-desktop.png'});await page.setViewportSize({width:390,height:844});await d.getByRole('button',{name:'Fit all',exact:true}).click();await page.screenshot({patLine truncated
|
||||
const revision=await page.evaluate(()=>Alpine.$data(document.body).workspace.revision);
|
||||
await page.evaluate(()=>{const a=Alpine.$data(document.body);a.generationDraft.rules[1].enabled=false;});
|
||||
await page.getByRole('button',{name:'Map',exact:true}).click();await page.waitForFunction(()=>!Alpine.$data(document.body).mapBusy);await d.getByLabel('Selected node',{exact:true}).selectOption({label:'Project owners during working hours'});await page.waitForFunction(()=>document.querySelectorAll('dialog.generation-map .map-resource').length===0);await d.getByRole('button',{name:'Close dialog',exact:true}).click();
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
const {chromium}=require('playwright'),assert=require('node:assert/strict');
|
||||
(async()=>{const browser=await chromium.launch({channel:'chrome',headless:true});try{const page=await browser.newPage({viewport:{width:1200,height:850}}),errors=[];page.on('pageerror',e=>errors.push(e.message));await page.goto('http://127.0.0.1:3000/?view=configuration');await page.getByLabel('Username',{exact:true}).fill('alice');await page.getByLabel('Password',{exact:true}).fill('meguri-demo-only');await page.getByRole('button',{name:'Sign in',exact:true}).click();await page.getByRole('button',{name:'Edit rule Project owners during working hours',exact:true}).click();for(const width of [1200,390]){await page.setViewportSize({width,height:850});const button=page.locator('.binding-tweak').last();await button.scrollIntoViewIfNeeded();await button.click();const saved=await page.evaluate(()=>Alpine.$data(document.body).editorScroll);assert(saved>0);const popup=page.locator('.binding-popover');await popup.waitFor();const bounds=await popup.boundingBox();assert(bounds.x>=0&&bounds.x+bounds.width<=width&&bounds.y>=0&&bounds.y+bounds.height<=850);assert(await page.locator('.rule-constructor').isVisible());await popup.screenshot({path:'test-results/binding-popover-'+width+'.png'});await page.getByRole('button',{name:'Done',exact:true}).click();await page.waitForFunction(top=>Math.abs(document.querySelector('[role=dialog]').scrollTop-top)<2,saved);assert.equal(await page.locator('select.template-token,input.template-token,button.template-token').count(),0);assert(await page.locator('.template-token').count()>0);}await page.getByLabel('Iteration collection',{exact:true}).scrollIntoViewIfNeeded();await page.screenshot({path:'test-results/standard-template-controls.png'});assert.deepEqual(errors,[]);console.log('PASS standard controls; template notation retained; modal scroll restored desktop/mobile');}finally{await browser.close();}})().catch(e=>{console.error(e);process.exitCode=1;});
|
||||
const assert=require('node:assert/strict');
|
||||
(async()=>{const browser=await require('./support/browser.cjs').launchBrowser();try{const page=await browser.newPage({viewport:{width:1200,height:850}}),errors=[];page.on('pageerror',e=>errors.push(e.message));await page.goto('http://127.0.0.1:3000/?view=configuration');await page.getByLabel('Username',{exact:true}).fill('alice');await page.getByLabel('Password',{exact:true}).fill('meguri-demo-only');await page.getByRole('button',{name:'Sign in',exact:true}).click();await page.getByRole('button',{name:'Edit rule Project owners during working hours',exact:true}).click();for(const width of [1200,390]){await page.setViewportSize({width,height:850});const button=page.locator('.binding-tweak').last();await button.scrollIntoViewIfNeeded();await button.click();const saved=await page.evaluate(()=>Alpine.$data(document.body).editorScroll);assert(saved>0);const popup=page.locator('.binding-popover');await popup.waitFor();const bounds=await popup.boundingBox();assert(bounds.x>=0&&bounds.x+bounds.width<=width&&bounds.y>=0&&bounds.y+bounds.height<=850);assert(await page.locator('.rule-constructor').isVisible());await popup.screenshot({path:'test-results/binding-popover-'+width+'.png'});await page.getByRole('button',{name:'Done',exact:true}).click();await page.waitForFunction(top=>Math.abs(document.querySelector('[role=dialog]').scrollTop-top)<2,saved);assert.equal(await page.locator('select.template-token,input.template-token,button.template-token').count(),0);assert(await page.locator('.template-token').count()>0);}await page.getByLabel('Iteration collection',{exact:true}).scrollIntoViewIfNeeded();await page.screenshot({path:'test-results/standard-template-controls.png'});assert.deepEqual(errors,[]);console.log('PASS standard controls; template notation retained; modal scroll restored desktop/mobile');}finally{await browser.close();}})().catch(e=>{console.error(e);process.exitCode=1;});
|
||||
@@ -1,12 +1,12 @@
|
||||
const {openSetup}=require('./support/browser.cjs');
|
||||
const {chromium}=require('playwright');
|
||||
|
||||
const assert=require('node:assert/strict');
|
||||
const fs=require('node:fs');
|
||||
const base=process.env.MEGURI_BROWSER_URL||'http://127.0.0.1:3000';
|
||||
assert(['127.0.0.1','localhost'].includes(new URL(base).hostname));
|
||||
fs.mkdirSync('test-results',{recursive:true});
|
||||
(async()=>{
|
||||
const browser=await chromium.launch({...(process.env.MEGURI_BROWSER_CHANNEL==='chromium'?{}:{channel:process.env.MEGURI_BROWSER_CHANNEL||'chrome'}),headless:true});
|
||||
const browser=await require('./support/browser.cjs').launchBrowser();
|
||||
const page=await browser.newPage({viewport:{width:1440,height:1100}});page.setDefaultTimeout(10000);
|
||||
const errors=[];page.on('pageerror',e=>errors.push(e.message));
|
||||
const dialog=()=>page.getByRole('dialog');
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
const {chromium}=require('playwright'),assert=require('node:assert/strict'),fs=require('node:fs');
|
||||
const assert=require('node:assert/strict'),fs=require('node:fs');
|
||||
const base=process.env.MEGURI_BROWSER_URL||'http://127.0.0.1:3000';assert(['127.0.0.1','localhost'].includes(new URL(base).hostname));
|
||||
(async()=>{const browser=await chromium.launch({channel:process.env.MEGURI_BROWSER_CHANNEL||'chrome',headless:true});const errors=[];let page;try{
|
||||
(async()=>{const browser=await require('./support/browser.cjs').launchBrowser();const errors=[];let page;try{
|
||||
const context=await browser.newContext({locale:'en-US',viewport:{width:1440,height:1000}});page=await context.newPage();page.setDefaultTimeout(12000);page.on('pageerror',e=>errors.push(e.message));
|
||||
await page.goto(base+'/?view=policies');await page.getByLabel('Username',{exact:true}).fill('alice');await page.getByLabel('Password',{exact:true}).fill('meguri-demo-only');await page.getByRole('button',{name:'Sign in',exact:true}).click();await page.waitForFunction(()=>Alpine.$data(document.body).workspace);await page.getByRole('heading',{name:'Schedule setup',exact:true}).waitFor();
|
||||
const matrix=await page.evaluate(()=>Alpine.$data(document.body).selected);const support=await page.evaluate(()=>Alpine.$data(document.body).directoryState.workspaces.find(t=>t.id!==Alpine.$data(document.body).selected).id);
|
||||
|
||||
@@ -1 +1 @@
|
||||
const {chromium}=require('playwright'),assert=require('node:assert/strict');(async()=>{const b=await chromium.launch({channel:'chrome',headless:true});try{const p=await b.newPage({viewport:{width:1440,height:1000}}),errors=[];p.on('pageerror',e=>errors.push(e.message));await p.goto('http://127.0.0.1:3000/?view=configuration');await p.getByLabel('Username',{exact:true}).fill('alice');await p.getByLabel('Password',{exact:true}).fill('meguri-demo-only');await p.getByRole('button',{name:'Sign in',exact:true}).click();await p.getByRole('button',{name:'Edit rule Weekly Time off',exact:true}).click();const d=p.getByRole('dialog');assert.equal(await d.getByLabel('Repeat count · Fixed value',{exact:true}).inputValue(),'0');assert.equal(await d.getByLabel('Minutes between repeats · Fixed value',{exact:true}).inputValue(),'0');await d.getByLabel('Repeat count · Fixed value',{exact:true}).fill('2');await d.getByLabel('Minutes between repeats · Fixed value',{exact:true}).fill('10');await p.waitForFunction(()=>{const a=Alpine.$data(document.body);return !a.generationLoading&&a.generationResult;});assert.deepEqual(await p.evaluate(()=>Alpine.$data(document.body).generationResult.issues),[]);await d.locator('.generation-block').nth(1).screenshot({path:'test-results/repeat-defaults.png'});await d.getByRole('button',{name:'Use in draft',exact:true}).click();await p.getByRole('button',{name:'Edit rule Weekly Time off',exact:true}).click();assert.equal(await d.getByLabel('Repeat count · Fixed value',{exact:true}).inputValue(),'2');assert.equal(await d.getByLabel('Minutes between repeats · Fixed value',{exact:true}).inputValue(),'10');await d.getByRole('button',{name:'Cancel',exact:true}).click();const team=await p.evaluate(()=>Alpine.$data(document.body).directoryState.workspaces.find(t=>t.name==='Commerce Operations').id);await p.goto('http://127.0.0.1:3000/?view=configuration&workspace='+team);await p.getByRole('button',{name:'Edit rule Product → service tier',exact:true}).click();assert.equal(await p.evaluate(()=>Alpine.$data(document.body).form.blocks.find(b=>b.kind==='escalation').fields.repeat_count.kind),'lookup');assert.deepEqual(errors,[]);console.log('PASS optional repeat defaults, editing and draft reopening, explicit lookup preservation');}finally{await b.close();}})().catch(e=>{console.error(e);process.exitCode=1;});
|
||||
const assert=require('node:assert/strict');(async()=>{const b=await require('./support/browser.cjs').launchBrowser();try{const p=await b.newPage({viewport:{width:1440,height:1000}}),errors=[];p.on('pageerror',e=>errors.push(e.message));await p.goto('http://127.0.0.1:3000/?view=configuration');await p.getByLabel('Username',{exact:true}).fill('alice');await p.getByLabel('Password',{exact:true}).fill('meguri-demo-only');await p.getByRole('button',{name:'Sign in',exact:true}).click();await p.getByRole('button',{name:'Edit rule Weekly Time off',exact:true}).click();const d=p.getByRole('dialog');assert.equal(await d.getByLabel('Repeat count · Fixed value',{exact:true}).inputValue(),'0');assert.equal(await d.getByLabel('Minutes between repeats · Fixed value',{exact:true}).inputValue(),'0');await d.getByLabel('Repeat count · Fixed value',{exact:true}).fill('2');await d.getByLabel('Minutes between repeats · Fixed value',{exact:true}).fill('10');await p.waitForFunction(()=>{const a=Alpine.$data(document.body);return !a.generationLoading&&a.generationResult;});assert.deepEqual(await p.evaluate(()=>Alpine.$data(document.body).generationResult.issues),[]);await d.locator('.generation-block').nth(1).screenshot({path:'test-results/repeat-defaults.png'});await d.getByRole('button',{name:'Use in draft',exact:true}).click();await p.getByRole('button',{name:'Edit rule Weekly Time off',exact:true}).click();assert.equal(await d.getByLabel('Repeat count · Fixed value',{exact:true}).inputValue(),'2');assert.equal(await d.getByLabel('Minutes between repeats · Fixed value',{exact:true}).inputValue(),'10');await d.getByRole('button',{name:'Cancel',exact:true}).click();const team=await p.evaluate(()=>Alpine.$data(document.body).directoryState.workspaces.find(t=>t.name==='Commerce Operations').id);await p.goto('http://127.0.0.1:3000/?view=configuration&workspace='+team);await p.getByRole('button',{name:'Edit rule Product → service tier',exact:true}).click();assert.equal(await p.evaluate(()=>Alpine.$data(document.body).form.blocks.find(b=>b.kind==='escalation').fields.repeat_count.kind),'lookup');assert.deepEqual(errors,[]);console.log('PASS optional repeat defaults, editing and draft reopening, explicit lookup preservation');}finally{await b.close();}})().catch(e=>{console.error(e);process.exitCode=1;});
|
||||
@@ -1 +1 @@
|
||||
const {chromium}=require('playwright'),assert=require('node:assert/strict');(async()=>{const b=await chromium.launch({channel:'chrome',headless:true});try{const p=await b.newPage({viewport:{width:1440,height:1050}}),errors=[];p.on('pageerror',e=>errors.push(e.message));await p.goto('http://127.0.0.1:3000/?view=configuration');await p.getByLabel('Username',{exact:true}).fill('alice');await p.getByLabel('Password',{exact:true}).fill('meguri-demo-only');await p.getByRole('button',{name:'Sign in',exact:true}).click();await p.locator('.resource-row').first().waitFor();await p.getByRole('heading',{name:'Schedule setup',exact:true}).click();for(const [kind,index] of [['schedules',0],['schedules',1],['escalations',0],['routes',0]]){const row=p.locator('[data-resource-kind='+kind+']').nth(index);await row.locator('summary').click();await row.locator('.resource-widget').waitFor();assert(await row.locator('.widget-node').count()>0);await row.screenshot({path:'test-results/resource-'+kind+'-'+index+'.png'});await p.setViewportSize({width:390,height:844});await row.screenshot({path:'test-results/resource-'+kind+'-'+index+'-mobile.png'});assert((await row.boundingBox()).width<390);await p.setViewportSize({width:1440,height:1050});await row.locator('summary').click();}assert.deepEqual(errors,[]);console.log('PASS shared resource rows, schedule variants, escalation, routing, desktop and mobile');}finally{await b.close();}})().catch(e=>{console.error(e);process.exitCode=1;});
|
||||
const assert=require('node:assert/strict');(async()=>{const b=await require('./support/browser.cjs').launchBrowser();try{const p=await b.newPage({viewport:{width:1440,height:1050}}),errors=[];p.on('pageerror',e=>errors.push(e.message));await p.goto('http://127.0.0.1:3000/?view=configuration');await p.getByLabel('Username',{exact:true}).fill('alice');await p.getByLabel('Password',{exact:true}).fill('meguri-demo-only');await p.getByRole('button',{name:'Sign in',exact:true}).click();await p.locator('.resource-row').first().waitFor();await p.getByRole('heading',{name:'Schedule setup',exact:true}).click();for(const [kind,index] of [['schedules',0],['schedules',1],['escalations',0],['routes',0]]){const row=p.locator('[data-resource-kind='+kind+']').nth(index);await row.locator('summary').click();await row.locator('.resource-widget').waitFor();assert(await row.locator('.widget-node').count()>0);await row.screenshot({path:'test-results/resource-'+kind+'-'+index+'.png'});await p.setViewportSize({width:390,height:844});await row.screenshot({path:'test-results/resource-'+kind+'-'+index+'-mobile.png'});assert((await row.boundingBox()).width<390);await p.setViewportSize({width:1440,height:1050});await row.locator('summary').click();}assert.deepEqual(errors,[]);console.log('PASS shared resource rows, schedule variants, escalation, routing, desktop and mobile');}finally{await b.close();}})().catch(e=>{console.error(e);process.exitCode=1;});
|
||||
@@ -1,5 +1,5 @@
|
||||
const {chromium}=require('playwright'),assert=require('node:assert/strict');
|
||||
(async()=>{const browser=await chromium.launch({channel:'chrome',headless:true});try{
|
||||
const assert=require('node:assert/strict');
|
||||
(async()=>{const browser=await require('./support/browser.cjs').launchBrowser();try{
|
||||
const page=await browser.newPage({viewport:{width:1440,height:1000}}),errors=[];page.on('pageerror',e=>errors.push(e.message));
|
||||
await page.goto('http://127.0.0.1:3000/?view=configuration');await page.getByLabel('Username',{exact:true}).fill('alice');await page.getByLabel('Password',{exact:true}).fill('meguri-demo-only');await page.getByRole('button',{name:'Sign in',exact:true}).click();
|
||||
await page.getByRole('button',{name:'Edit rule Project owners during working hours',exact:true}).click();
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
const {chromium}=require('playwright'),assert=require('node:assert/strict');
|
||||
(async()=>{const browser=await chromium.launch({channel:'chrome',headless:true});try{const page=await browser.newPage({viewport:{width:1440,height:1050}}),errors=[];page.on('pageerror',e=>errors.push(e.message));await page.goto('http://127.0.0.1:3000/?view=configuration');await page.getByLabel('Username',{exact:true}).fill('alice');await page.getByLabel('Password',{exact:true}).fill('meguri-demo-only');await page.getByRole('button',{name:'Sign in',exact:true}).click();await page.getByRole('button',{name:'Edit rule Weekly Time off',exact:true}).waitFor();await page.waitForFunction(()=>{const a=Alpine.$data(document.body);return a.generationResult&&!a.generationLoading;});assert.deepEqual(await page.evaluate(()=>Alpine.$data(document.body).generationResult.issues),[]);assert.equal(await page.locator('.generation-review').getAttribute('open'),null);assert.equal(await page.locator('#public-holidays').getAttribute('open'),null);assert.equal((await page.locator('#public-holidays > .widget-heading .badge').innerText()).trim(),'33');assert.equal(await page.locator('.setup-jumps').count(),0);assert.equal(await page.getByText('Start with projects & responsible example',{exact:true}).count(),0);assert.equal(await page.locator('.resource-row[open]').count(),0);assert(await page.locator('.resource-row.generated-resource').count()>0);assert.equal(await page.locator('.resource-create > button').count(),2);assert(await page.locator('#availability').evaluate(el=>el.getBoundingClientRect().left > document.querySelector('.generation-panel:nth-child(2)').getBoundingClientRect().left));const placement=page.locator('.generated-routing-placement');assert(!await placement.isVisible());await page.evaluate(()=>{const a=Alpine.$data(document.body);a.doc.routes.push({id:'placement-test-b',name:'Catch all',order:200,conditions:[]},{id:'placement-test-a',name:'Critical alerts',order:100,conditions:[]});});await placement.waitFor({state:'visible'});assert.deepEqual(await placement.locator('option').allTextContents(),['Before manual rules','After “Critical alerts”','After “Catch all”']);await placement.locator('select').selectOption('1');assert.equal(await page.evaluate(()=>Alpine.$data(document.body).generationDraft.route_position),1);await page.evaluate(()=>{const a=Alpine.$data(document.body);a.doc.routes=a.doc.routes.filter(r=>!r.id.startsWith('placement-test-'));a.generationDraft.route_position=0;});await placement.waitFor({state:'hidden'});const row=page.locator('.resource-row').first();await row.locator('summary').click();await row.locator('.resource-body').waitFor();await row.locator('summary').click();await page.locator('.schedule-create > summary').click();await page.getByRole('button',{name:'+ Rotation',exact:true}).click();await page.getByRole('dialog').waitFor();await page.getByRole('dialog').getByRole('button',{name:'Cancel',exact:true}).click();const overview=await page.evaluate(()=>{const a=Alpine.$data(document.body);return a.generationDraft.rules.map(r=>a.ruleOverview(r));});assert(overview.some(t=>t.includes('{ var.projects }')&&t.includes('Escalation')));assert(!overview[0].includes('Iterations'));for(const kind of ['schedules','escalations','routes']){const resource=page.locator('[data-resource-kind="'+kind+'"] .resource-summary').first();assert((await resource.locator('.resource-brief').innerText()).length>10);await resource.click();const link=resource.locator('..').locator('.source-rule-link');const name=(await link.innerText()).replace('Generated by: ','');await link.click();await page.waitForFunction(name=>Alpine.$data(document.body).form.name===name,name);await page.getByRole('dialog').getByRole('button',{name:'Cancel',exact:true}).click();await resource.click();}await page.evaluate(()=>window.scrollTo(0,0));await page.screenshot({path:'test-results/setup-desktop.png',fullPage:true});const japan=page.locator('.holiday-group').filter({has:page.locator('summary').filter({hasText:'Japan'})});assert.equal(await japan.getAttribute('open'),null);assert.equal((await japan.locator('.badge').innerText()).trim(),'18');await japan.locator('summary').click();await japan.getByText('Coming of Age Day',{exact:true}).waitFor();await page.locator('#public-holidays').screenshot({path:'test-results/setup-holidays.png'});await page.getByRole('button',{name:'Import CSV',exact:true}).click();await page.getByRole('dialog').waitFor();await page.getByRole('dialog').getByRole('button',{name:'Cancel',exact:true}).click();await page.setViewportSize({width:390,height:844});await page.evaluate(()=>window.scrollTo(0,0));await page.screenshot({path:'test-results/setup-mobile.png',fullPage:true});assert(await page.evaluate(()=>document.documentElement.scrollWidth<=innerWidth));assert.deepEqual(errors,[]);console.log('PASS setup layout, collapsed review, 33 country holidays, CSV modal and mobile');}finally{await browser.close();}})().catch(e=>{console.error(e);process.exitCode=1;});
|
||||
const assert=require('node:assert/strict');
|
||||
(async()=>{const browser=await require('./support/browser.cjs').launchBrowser();try{const page=await browser.newPage({viewport:{width:1440,height:1050}}),errors=[];page.on('pageerror',e=>errors.push(e.message));await page.goto('http://127.0.0.1:3000/?view=configuration');await page.getByLabel('Username',{exact:true}).fill('alice');await page.getByLabel('Password',{exact:true}).fill('meguri-demo-only');await page.getByRole('button',{name:'Sign in',exact:true}).click();await page.getByRole('button',{name:'Edit rule Weekly Time off',exact:true}).waitFor();await page.waitForFunction(()=>{const a=Alpine.$data(document.body);return a.generationResult&&!a.generationLoading;});assert.deepEqual(await page.evaluate(()=>Alpine.$data(document.body).generationResult.issues),[]);assert.equal(await page.locator('.generation-review').getAttribute('open'),null);assert.equal(await page.locator('#public-holidays').getAttribute('open'),null);assert.equal((await page.locator('#public-holidays > .widget-heading .badge').innerText()).trim(),'33');assert.equal(await page.locator('.setup-jumps').count(),0);assert.equal(await page.getByText('Start with projects & responsible example',{exact:true}).count(),0);assert.equal(await page.locator('.resource-row[open]').count(),0);assert(await page.locator('.resource-row.generated-resource').count()>0);assert.equal(await page.locator('.resource-create > button').count(),2);assert(await page.locator('#availability').evaluate(el=>el.getBoundingClientRect().left > document.querySelector('.generation-panel:nth-child(2)').getBoundingClientRect().left));const placement=page.locator('.generated-routing-placement');assert(!await placement.isVisible());await page.evaluate(()=>{const a=Alpine.$data(document.body);a.doc.routes.push({id:'placement-test-b',name:'Catch all',order:200,conditions:[]},{id:'placement-test-a',name:'Critical alerts',order:100,conditions:[]});});await placement.waitFor({state:'visible'});assert.deepEqual(await placement.locator('option').allTextContents(),['Before manual rules','After “Critical alerts”','After “Catch all”']);await placement.locator('select').selectOption('1');assert.equal(await page.evaluate(()=>Alpine.$data(document.body).generationDraft.route_position),1);await page.evaluate(()=>{const a=Alpine.$data(document.body);a.doc.routes=a.doc.routes.filter(r=>!r.id.startsWith('placement-test-'));a.generationDraft.route_position=0;});await placement.waitFor({state:'hidden'});const row=page.locator('.resource-row').first();await row.locator('summary').click();await row.locator('.resource-body').waitFor();await row.locator('summary').click();await page.locator('.schedule-create > summary').click();await page.getByRole('button',{name:'+ Rotation',exact:true}).click();await page.getByRole('dialog').waitFor();await page.getByRole('dialog').getByRole('button',{name:'Cancel',exact:true}).click();const overview=await page.evaluate(()=>{const a=Alpine.$data(document.body);return a.generationDraft.rules.map(r=>a.ruleOverview(r));});assert(overview.some(t=>t.includes('{ var.projects }')&&t.includes('Escalation')));assert(!overview[0].includes('Iterations'));for(const kind of ['schedules','escalations','routes']){const resource=page.locator('[data-resource-kind="'+kind+'"] .resource-summary').first();assert((await resource.locator('.resource-brief').innerText()).length>10);await resource.click();const link=resource.locator('..').locator('.source-rule-link');const name=(await link.innerText()).replace('Generated by: ','');await link.click();await page.waitForFunction(name=>Alpine.$data(document.body).form.name===name,name);await page.getByRole('dialog').getByRole('button',{name:'Cancel',exact:true}).click();await resource.click();}await page.evaluate(()=>window.scrollTo(0,0));await page.screenshot({path:'test-results/setup-desktop.png',fullPage:true});const japan=page.locator('.holiday-group').filter({has:page.locator('summary').filter({hasText:'Japan'})});assert.equal(await japan.getAttribute('open'),null);assert.equal((await japan.locator('.badge').innerText()).trim(),'18');await japan.locator('summary').click();await japan.getByText('Coming of Age Day',{exact:true}).waitFor();await page.locator('#public-holidays').screenshot({path:'test-results/setup-holidays.png'});await page.getByRole('button',{name:'Import CSV',exact:true}).click();await page.getByRole('dialog').waitFor();await page.getByRole('dialog').getByRole('button',{name:'Cancel',exact:true}).click();await page.setViewportSize({width:390,height:844});await page.evaluate(()=>window.scrollTo(0,0));await page.screenshot({path:'test-results/setup-mobile.png',fullPage:true});assert(await page.evaluate(()=>document.documentElement.scrollWidth<=innerWidth));assert.deepEqual(errors,[]);console.log('PASS setup layout, collapsed review, 33 country holidays, CSV modal and mobile');}finally{await browser.close();}})().catch(e=>{console.error(e);process.exitCode=1;});
|
||||
@@ -1,3 +1,3 @@
|
||||
const {chromium}=require('playwright');const assert=require('node:assert/strict');
|
||||
(async()=>{const browser=await chromium.launch({channel:'chrome',headless:true});try{const page=await browser.newPage({viewport:{width:1440,height:1000}});const errors=[];page.on('pageerror',e=>errors.push(e.message));await page.goto('http://127.0.0.1:3000/?view=configuration');await page.getByLabel('Username',{exact:true}).fill('alice');await page.getByLabel('Password',{exact:true}).fill('meguri-demo-only');await page.getByRole('button',{name:'Sign in',exact:true}).click();await page.getByRole('button',{name:'Edit variable projects',exact:true}).click();const d=page.getByRole('dialog');assert.equal(await d.locator('.data-row').count(),7);assert.equal(await d.getByLabel('Value type',{exact:true}).filter({visible:true}).count(),0);await page.screenshot({path:'test-results/compact-variables.png'});await d.getByRole('button',{name:'Expand or collapse Payments',exact:true}).click();await d.getByLabel('Text value',{exact:true}).fill('Payments edited');await d.getByRole('button',{name:'Expand or collapse responsible',exact:true}).click();assert.equal(await d.getByLabel('Registered person',{exact:true}).count(),3);const verifyIndent=async()=>{const geometry=await d.locator('.data-row').evaluateAll(es=>es.slice(0,4).map(e=>({depth:Number([...e.classList].find(c=>c.startsWith('data-depth-')).slice(11)),padding:parseFloat(getComputedStyle(e).paddingLeft)})));assert(geometry[0].padding>=12);assert(geometry[1].padding>geometry[0].padding);assert(geometry[2].padding>geometry[1].padding);};await verifyIndent();await d.getByRole('button',{name:'Structure',exact:true}).click();await d.getByLabel('Value type',{exact:true}).first().waitFor({state:'visible'});await d.getByRole('button',{name:'Values',exact:true}).click();assert.equal(await d.getByLabel('Text value',{exact:true}).inputValue(),'Payments edited');await d.getByRole('button',{name:'Duplicate entry',exact:true}).first().click();const ids=await page.evaluate(()=>{const root=Alpine.$data(document.body).form.node,out=[];const walk=n=>{out.push(n.id);n.entries.forEach(walk)};walk(root);return out});assert.equal(ids.length,new Set(ids).size);await page.setViewportSize({width:390,height:844});await verifyIndent();await page.screenshot({path:'test-results/compact-variables-mobile.png'});assert(await page.evaluate(()=>document.documentElement.scrollWidth<=innerWidth));assert.deepEqual(errors,[]);console.log('PASS compact nested editor, retained values, schema controls, fresh duplicate IDs, mobile');}finally{await browser.close()}})().catch(e=>{console.error(e);process.exitCode=1});
|
||||
const assert=require('node:assert/strict');
|
||||
(async()=>{const browser=await require('./support/browser.cjs').launchBrowser();try{const page=await browser.newPage({viewport:{width:1440,height:1000}});const errors=[];page.on('pageerror',e=>errors.push(e.message));await page.goto('http://127.0.0.1:3000/?view=configuration');await page.getByLabel('Username',{exact:true}).fill('alice');await page.getByLabel('Password',{exact:true}).fill('meguri-demo-only');await page.getByRole('button',{name:'Sign in',exact:true}).click();await page.getByRole('button',{name:'Edit variable projects',exact:true}).click();const d=page.getByRole('dialog');assert.equal(await d.locator('.data-row').count(),7);assert.equal(await d.getByLabel('Value type',{exact:true}).filter({visible:true}).count(),0);await page.screenshot({path:'test-results/compact-variables.png'});await d.getByRole('button',{name:'Expand or collapse Payments',exact:true}).click();await d.getByLabel('Text value',{exact:true}).fill('Payments edited');await d.getByRole('button',{name:'Expand or collapse responsible',exact:true}).click();assert.equal(await d.getByLabel('Registered person',{exact:true}).count(),3);const verifyIndent=async()=>{const geometry=await d.locator('.data-row').evaluateAll(es=>es.slice(0,4).map(e=>({depth:Number([...e.classList].find(c=>c.startsWith('data-depth-')).slice(11)),padding:parseFloat(getComputedStyle(e).paddingLeft)})));assert(geometry[0].padding>=12);assert(geometry[1].padding>geometry[0].padding);assert(geometry[2].padding>geometry[1].padding);};await verifyIndent();await d.getByRole('button',{name:'Structure',exact:true}).click();await d.getByLabel('Value type',{exact:true}).first().waitFor({state:'visible'});await d.getByRole('button',{name:'Values',exact:true}).click();assert.equal(await d.getByLabel('Text value',{exact:true}).inputValue(),'Payments edited');await d.getByRole('button',{name:'Duplicate entry',exact:true}).first().click();const ids=await page.evaluate(()=>{const root=Alpine.$data(document.body).form.node,out=[];const walk=n=>{out.push(n.id);n.entries.forEach(walk)};walk(root);return out});assert.equal(ids.length,new Set(ids).size);await page.setViewportSize({width:390,height:844});await verifyIndent();await page.screenshot({path:'test-results/compact-variables-mobile.png'});assert(await page.evaluate(()=>document.documentElement.scrollWidth<=innerWidth));assert.deepEqual(errors,[]);console.log('PASS compact nested editor, retained values, schema controls, fresh duplicate IDs, mobile');}finally{await browser.close()}})().catch(e=>{console.error(e);process.exitCode=1});
|
||||
|
||||
+2
-2
@@ -1,13 +1,13 @@
|
||||
const {openSetup}=require('./support/browser.cjs');
|
||||
// Run against an explicitly seeded localhost development instance.
|
||||
const { chromium } = require('playwright');
|
||||
|
||||
const assert = require('node:assert/strict');
|
||||
const fs = require('node:fs');
|
||||
const base = process.env.MEGURI_BROWSER_URL || 'http://127.0.0.1:3000';
|
||||
assert(['127.0.0.1','localhost'].includes(new URL(base).hostname), 'Browser tests require a disposable local instance');
|
||||
fs.mkdirSync('test-results', { recursive: true });
|
||||
(async () => {
|
||||
const browser = await chromium.launch({ ...(process.env.MEGURI_BROWSER_CHANNEL==='chromium'?{}:{channel:process.env.MEGURI_BROWSER_CHANNEL || 'chrome'}), headless: true });
|
||||
const browser = await require('./support/browser.cjs').launchBrowser();
|
||||
const errors = [];
|
||||
async function signIn(name) {
|
||||
const context = await browser.newContext({ viewport: { width: 1440, height: 1100 } });
|
||||
|
||||
@@ -1,3 +1,15 @@
|
||||
const { chromium } = require('playwright');
|
||||
|
||||
function launchBrowser() {
|
||||
const channel = process.env.MEGURI_BROWSER_CHANNEL || 'chrome';
|
||||
return chromium.launch({
|
||||
headless: true,
|
||||
...(channel === 'chromium' ? {} : { channel }),
|
||||
});
|
||||
}
|
||||
|
||||
exports.launchBrowser = launchBrowser;
|
||||
|
||||
exports.openSetup = async (page, name) => {
|
||||
await page.waitForFunction(()=>window.Alpine && Alpine.$data(document.body).ready && Alpine.$data(document.body).workspace);
|
||||
const combined=['Schedules','Escalations & routing','Variables & rules'].includes(name);
|
||||
|
||||
Reference in new issue
Block a user