Files
HMDesign/examples/org-chart/verify-p9-5-arrowhead.mjs
T

55 lines
6.3 KiB
JavaScript

import fs from 'node:fs/promises';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { launchChromium } from '../../scripts/orgchart-browser-runtime.mjs';
const root=fileURLToPath(new URL('../../',import.meta.url));
const output=path.join(root,process.env.ORGCHART_ARROW_OUTPUT??'test-results/org-chart-p9-5-arrowhead');
const phase=process.argv[2]??'after', origin=process.env.ORGCHART_STORY_ORIGIN??'http://127.0.0.1:6064';
const browser=await launchChromium({headless:true}),page=await browser.newPage({viewport:{width:1920,height:1080}});
const checks=[],measurements=[],errors=[];
page.on('pageerror',e=>errors.push(e.message));page.on('console',m=>{if(m.type()==='error')errors.push(m.text());});
await fs.mkdir(output,{recursive:true});
const check=(pass,name,detail)=>{checks.push({name,status:pass?'PASS':'FAIL',detail});if(!pass)console.log('FAIL',name,JSON.stringify(detail));};
const settle=()=>page.evaluate(async()=>{await document.fonts.ready;for(let i=0;i<20;i++)await new Promise(requestAnimationFrame);});
const before=phase==='after'?JSON.parse(await fs.readFile(path.join(output,'before.json'),'utf8')):null;
const reference=await fs.readFile('D:/디자인시스템/gpd-workdesk/sample/조직도_v1.3/org-dashboard-data.js','utf8');
const originalD=reference.match(/id:\s*"jang-arrow-head",[\s\S]*?\bd:\s*"([^"]+)"/)[1];
try{
for(const size of [{width:1920,height:1080},{width:1920,height:1440},{width:390,height:844}]){
await page.setViewportSize(size);await page.goto(`${origin}/iframe.html?id=orgchart--full-composition&viewMode=story`);
await page.waitForFunction(()=>{const s=document.querySelector('.hm-orgchart-host')?.shadowRoot;return s?.querySelector('.hm-orgchart-stage[data-workdesk-artwork]')&&!s.querySelector('[aria-busy="true"]')&&[...s.querySelectorAll('link[rel="stylesheet"]')].every(l=>l.sheet);});await settle();
const snapshot=await page.evaluate(()=>{
const s=document.querySelector('.hm-orgchart-host').shadowRoot,stage=s.querySelector('.hm-orgchart-stage'),overlay=s.querySelector('.hm-orgchart-workdesk-overlay');
const r=e=>{const b=e.getBoundingClientRect();return{x:b.left,y:b.top,width:b.width,height:b.height,right:b.right,bottom:b.bottom};};
const o=r(overlay),scale=o.width/1920,local=e=>{const b=r(e);return{x:(b.x-o.x)/scale,y:(b.y-o.y)/scale,width:b.width/scale,height:b.height/scale};};
const card=s.querySelector('.hm-orgchart-top-leaders .hm-orgchart-employee'),hub=s.querySelector('.hm-orgchart-hub'),head=s.querySelector('[data-arrow-head="representative"]'),line=s.querySelector('[data-connector="representative-to-hub"]');
return{scale,offset:Number(s.querySelector('.hm-orgchart-composition').dataset.centerOffset),card:local(card),hub:local(hub),crop:{card:r(card),hub:r(hub)},head:head?{d:head.getAttribute('d'),fill:getComputedStyle(head).fill,stroke:getComputedStyle(head).stroke,transform:head.getAttribute('transform'),box:local(head),screen:r(head)}:null,headCount:s.querySelectorAll('[data-arrow-head="representative"]').length,
line:{d:line.getAttribute('d'),transform:line.getAttribute('transform'),start:line.getPointAtLength(0),end:line.getPointAtLength(line.getTotalLength())},team:[...s.querySelectorAll('image[data-arrow]')].map(e=>({id:e.dataset.arrow,box:local(e),href:e.getAttribute('href')})),
connections:s.querySelectorAll('[data-connector]').length,cards:s.querySelectorAll('.hm-orgchart-employee').length,scroll:[document.documentElement.scrollWidth,document.documentElement.scrollHeight]};
});
const name=`${size.width}x${size.height}`; measurements.push({name,...snapshot});
const clip={x:Math.max(0,Math.floor(snapshot.crop.card.x-30)),y:Math.max(0,Math.floor(snapshot.crop.card.y-10)),width:Math.ceil(snapshot.crop.card.width+60),height:Math.ceil(snapshot.crop.hub.bottom-snapshot.crop.card.y+25)};
await page.screenshot({path:path.join(output,`${phase}-${name}-detail.png`),clip,animations:'disabled'});
if(phase==='after'){
const old=before.measurements.find(m=>m.name===name),h=snapshot.head;
check(snapshot.headCount===1&&h?.d===originalD&&h.fill==='rgb(69, 99, 159)'&&h.stroke==='none',`${name}: exact original solid chevron restored once`,h);
if(!h)continue;
const gap=h.box.y-(snapshot.card.y+snapshot.card.height);
check(Math.abs(gap)<.01,`${name}: upward tip attaches to representative bottom edge`,gap);
check(Math.abs(h.box.x+h.box.width/2-(snapshot.card.x+snapshot.card.width/2))<.1,`${name}: arrow aligned to card/connector axis`,h.box);
const headBottom=h.box.y+h.box.height,lineStart=Number(snapshot.line.d.match(/M[^ ]+ ([^V]+)/)[1])-17;
check(Math.abs(lineStart-headBottom)<.2,`${name}: chevron meets existing dashed stem`,{headBottom,lineStart});
check(snapshot.connections===5&&snapshot.cards===old.cards&&snapshot.team.length===5&&snapshot.team.every((a,i)=>a.id===old.team[i].id&&a.href===old.team[i].href&&['x','y','width','height'].every(k=>Math.abs(a.box[k]-old.team[i].box[k])<.05)),`${name}: five team arrows/relations and cards unchanged`);
check(['card','hub'].every(key=>['x','y','width','height'].every(k=>Math.abs(snapshot[key][k]-old[key][k])<.05)),`${name}: representative/hub placement preserved`);
const target=page.locator('[data-arrow-head="representative"]');
const shown=await page.screenshot({clip,animations:'disabled'});await target.evaluate(e=>e.style.visibility='hidden');
const hidden=await page.screenshot({clip,animations:'disabled'});await target.evaluate(e=>e.style.removeProperty('visibility'));
check(!shown.equals(hidden),`${name}: restored arrow actually paints visible pixels`,{shownBytes:shown.length,hiddenBytes:hidden.length});
check(snapshot.scroll[0]<=size.width+1&&snapshot.scroll[1]<=size.height+1,`${name}: no new document scroll`,snapshot.scroll);
}
}
}catch(e){check(false,'Targeted arrow check completed',{message:e.message,stack:e.stack});}
check(!errors.length,'Console/page errors zero',errors);
const result={phase,origin,measurements,checks,errors,pass:checks.filter(c=>c.status==='PASS').length,fail:checks.filter(c=>c.status==='FAIL').length};
await fs.writeFile(path.join(output,`${phase}.json`),JSON.stringify(result,null,2));await browser.close();console.log(JSON.stringify({phase,pass:result.pass,fail:result.fail,measurements:measurements.map(m=>({name:m.name,head:m.head?.box,card:m.card,connections:m.connections}))}));if(result.fail)process.exitCode=1;