2026-09-24 16:10:08 +03:00
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 ( ow
2026-09-24 14:35:05 +03:00
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 ();
await page . evaluate (()=>{ const a = Alpine . $data ( document . body ); a . generationDraft . rules [ 1 ]. enabled = true ; a . generationDraft . variables . find ( v => v . name === 'projects' ). node . entries [ 0 ]. entries . find ( n => n . key === 'responsible' ). entries [ 0 ]. value = 'not-an-email' ;});
await page . getByRole ( 'button' ,{ name : 'Map' , exact : true }). click (); await page . waitForFunction (()=> ! Alpine . $data ( document . body ). mapBusy ); assert ( await d . locator ( '.map-status-error' ). count ()); await page . waitForFunction (()=> document . querySelectorAll ( 'dialog.generation-map .map-resource' ). length === 0 ); await d . getByRole ( 'button' ,{ name : 'Close dialog' , exact : true }). click (); assert . equal ( await page . evaluate ( async ()=>{ const a = Alpine . $data ( document . body ); return ( await a . api ( a . endpoint ())). workspace . revision }), revision );
await page . getByLabel ( 'Workspace' ,{ exact : true }). selectOption ({ label : 'Regional Platform' }); 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 : 'Service · Iteration · 4 passes' }); const rows = await page . evaluate (()=> Alpine . $data ( document . body ). mapRows ()); const filtered = rows . findIndex ( r => r . status === 'filtered' ); assert ( filtered >= 0 ); await d . getByLabel ( 'Iteration pass' ,{ exact : true }). selectOption ( String ( filtered )); await page . waitForFunction (()=> Alpine . $data ( document . body ). mapResources (). length === 0 ); await page . screenshot ({ path : 'test-results/generation-map-filtered.png' }); await d . getByRole ( 'button' ,{ name : 'Close dialog' , exact : true }). click ();
assert . deepEqual ( errors ,[]); console . log ( 'PASS generation map, actual iteration outputs, pass filtering, group expansion, zoom, source editor, mobile' );} finally { await browser . close ();}})(). catch ( e =>{ console . error ( e ); process . exitCode = 1 });