ความคืบหน้างาน ไฟล์ต้นฉบับ

tracker/e2e/workflow-review-check.mjs

// Writes only to the isolated test server data, never use on the shared tracker.
import {pathToFileURL} from 'node:url';
const [chrome,base,out,modulePath]=process.argv.slice(2);
const {chromium}=await import(pathToFileURL(modulePath).href);
const browser=await chromium.launch({executablePath:chrome,headless:true,args:['--no-sandbox']});
const page=await browser.newPage({viewport:{width:1600,height:1000}}),errors=[];page.on('pageerror',e=>errors.push(e.message));
await page.route('https://fonts.googleapis.com/**',r=>r.abort());await page.route('https://fonts.gstatic.com/**',r=>r.abort());
let passed=0;const check=(ok,msg)=>{if(!ok)throw Error(msg);passed++;console.log('PASS '+msg)};
try {
 for(const id of ['W-41','W-77','W-147','W-14','W-152']){
  await page.goto(base+'/use-cases/'+id,{waitUntil:'domcontentloaded'});await page.waitForFunction(()=>document.querySelectorAll('.uc-node').length>0&&!document.querySelector('#uc-reload').disabled);
  const result=await page.evaluate(()=>{
   const source=JSON.parse(document.querySelector('#uc-source-diagram').textContent),nodes=[...document.querySelectorAll('.uc-node')],canvas=document.querySelector('#uc-canvas').getBoundingClientRect(),box=document.querySelector('.uc-graph').getBoundingClientRect();
   const rects=nodes.map(n=>n.getBoundingClientRect());
   return {count:nodes.length,expected:source.nodes.length,decisions:nodes.filter(n=>n.dataset.type==='decision').length,labels:document.querySelectorAll('.uc-edge text').length,fit:box.left>=canvas.left&&box.right<=canvas.right&&box.top>=canvas.top&&box.bottom<=canvas.bottom,overlap:rects.some((a,i)=>rects.some((b,j)=>i<j&&a.left<b.right-0.1&&a.right>b.left+0.1&&a.top<b.bottom-0.1&&a.bottom>b.top+0.1)),note:document.body.textContent.includes('ข้อสังเกตจากการทบทวน')};
  });
  check(result.count===result.expected&&result.decisions>0,id+' renders canonical decision graph');
  check(result.labels>=2,id+' displays branch labels');check(result.fit&&!result.overlap,id+' fits the whole scene without overlapping shapes');check(result.note,id+' exposes pending review note');
  if(id==='W-41'){
   check(await page.locator('.uc-edge text').allTextContents().then(x=>x.includes('ไม่จำเป็น — สมัครด้วยตนเอง')),'university applicant has explicit guardian bypass');
   const sourceCount=result.count;await page.selectOption('#uc-add-type','process');await page.click('#uc-add');
   await page.locator('.uc-more summary').click();page.once('dialog',d=>d.accept());await page.click('#uc-reset');
   check(await page.locator('.uc-node').count()===sourceCount&&await page.locator('[data-type=decision]').count()===2,'Reset to source retains canonical decisions');
   await page.click('#uc-save');await page.waitForFunction(()=>document.querySelector('#uc-status').textContent.includes('บันทึกแล้ว'));
   const saved=await page.evaluate(async()=>await(await fetch('/api/use-cases/W-41/diagram')).json());check(saved.revision===1&&saved.nodes.some(n=>n.type==='decision'),'saving preserves source branch draft in revision history');
  }
  await page.screenshot({path:out+'/audit-'+id+'.png'});
 }
 await page.setViewportSize({width:390,height:844});await page.goto(base+'/use-cases/W-41');await page.waitForFunction(()=>document.querySelectorAll('.uc-node').length>0);check(await page.evaluate(()=>document.documentElement.scrollWidth<=innerWidth+2),'review notes and branch graph fit mobile page');
 check(errors.length===0,'no browser exceptions');console.log(passed+' workflow review checks passed');
}finally{await browser.close()}