diff --git a/tests/audit-highlight.cjs b/tests/audit-highlight.cjs new file mode 100644 index 0000000..9b98d3f --- /dev/null +++ b/tests/audit-highlight.cjs @@ -0,0 +1,60 @@ +const {chromium}=require('playwright'); +const assert=require('node:assert/strict'); +const fs=require('node:fs/promises'); +const path=require('node:path'); +const out=path.resolve(__dirname,'../test-results'); +(async()=>{ + const browser=await chromium.launch({headless:true,...(process.env.PLAYWRIGHT_CHANNEL?{channel:process.env.PLAYWRIGHT_CHANNEL}:{})}); + const page=await browser.newPage({viewport:{width:1440,height:1000}}); + const errors=[];page.on('pageerror',e=>errors.push(e.message)); + const report={status:'failed'}; + await fs.mkdir(out,{recursive:true}); + const state=()=>page.evaluate(async()=>{ + const {app}=await import('./app.js');const r=app.renderer; + r.draw();const gl=r.gl,b=new Uint8Array(r.canvas.width*r.canvas.height*4); + gl.readPixels(0,0,r.canvas.width,r.canvas.height,gl.RGBA,gl.UNSIGNED_BYTE,b); + let red=0,hash=0;for(let i=0;i220&&b[i+1]<80&&b[i+2]<120)red++;hash=(hash+b[i]*3+b[i+1]*5+b[i+2]*7)>>>0;} + return {phase:r.auditPhase,enabled:r.auditEnabled,timer:r.auditTimer!==null,red,hash, + targetCount:r.auditPickIds.size,targets:r.facilities.filter(f=>r.auditPickIds.has(f.pickId)).map(f=>f.id)}; + }); + try{ + await page.clock.install({time:new Date('2026-10-28T00:00:00Z')}); + await page.goto(process.env.VIEWER_URL||'http://127.0.0.1:8081/',{waitUntil:'networkidle'}); + await page.waitForFunction(()=>document.querySelector('#loading').hidden); + await page.clock.pauseAt(new Date('2026-10-28T00:01:00Z')); + const before=await state();assert.equal(before.enabled,false); + const data=await (await page.request.get(new URL('data/network.json',page.url()).href)).json(); + const ids=new Set(data.issues.filter(i=>['length_mismatch','adverse_slope'].includes(i.code)).flatMap(i=>i.ids)); + const expected=data.links.filter(l=>l.type==='conduit'&&l.renderable&&ids.has(l.id)).map(l=>l.id).sort(); + assert.deepEqual(before.targets.sort(),expected); + await page.locator('#audit-highlight').check({force:true}); + const on=await state();assert.equal(on.phase,1);assert.ok(on.red>before.red+20); + await page.screenshot({path:path.join(out,'audit-red.png'),fullPage:true}); + await page.clock.runFor(1000); + const normal=await state();assert.equal(normal.red,before.red);assert.equal(normal.hash,before.hash); + await page.clock.runFor(1000);assert.equal((await state()).phase,1); + await page.locator('#audit-highlight').uncheck({force:true});const stopped=await state(); + assert.equal(stopped.timer,false);assert.equal(stopped.hash,before.hash); + await page.locator('#audit-highlight').check({force:true});await page.locator('#audit-steady').check({force:true}); + const fixed=await state();assert.equal(fixed.timer,false);assert.equal(fixed.phase,1); + await page.clock.runFor(1150);assert.equal((await state()).phase,1); + await page.locator('#show-conduit').uncheck({force:true});assert.equal((await state()).red,0);await page.locator('#show-conduit').check({force:true}); + const target=expected[0];await page.locator('#search').fill(target);await page.locator('#search-results button').first().click({force:true}); + assert.ok((await page.locator('#details').textContent()).includes('점검 필요 · 오류 확정 아님')); + await page.locator('#audit-unplaced').click({force:true}); + for(const id of ['OUT_PUMP','C_OUT_PUMP','UHR1-01411'])assert.ok((await page.locator('#audit-list').textContent()).includes(id)); + await page.locator('#audit-dialog .close-dialog').click({force:true}); + await page.locator('#reset').click({force:true});assert.equal((await state()).enabled,false); + await page.emulateMedia({reducedMotion:'reduce'});await page.locator('#audit-highlight').check({force:true}); + const reduced=await state();assert.equal(reduced.timer,false);assert.equal(reduced.phase,1); + assert.equal(await page.locator('#audit-steady').isDisabled(),true); + await page.clock.resume();await page.waitForTimeout(150); + await page.locator('#audit-highlight').scrollIntoViewIfNeeded(); + await page.screenshot({path:path.join(out,'audit-fixed.png'),fullPage:true}); + assert.deepEqual(errors,[]);Object.assign(report,{status:'passed',target_conduits:expected.length, + red_pixels_on:on.red,red_pixels_off:normal.red,original_colors_restored:true, + checks:['target IDs','red pixels','1 second phases','exact original pixel restoration','timer cancellation', + 'steady mode','layer visibility','selection reasons','3 unplaced facilities','reset','reduced motion','no page errors']}); + }catch(e){report.error=e.stack;process.exitCode=1;await page.screenshot({path:path.join(out,'audit-failure.png'),fullPage:true}).catch(()=>{});} + finally{await fs.writeFile(path.join(out,'audit-highlight-validation.json'),JSON.stringify(report,null,2));console.log(JSON.stringify(report,null,2));await browser.close();} +})().catch(e=>{console.error(e);process.exitCode=1;});