Files
HMDesign/examples/org-chart/verify-p9-4-preservation.mjs
T

39 lines
5.4 KiB
JavaScript

// Compare protected source hashes to the captured pre-P9.4 state and one Fixed
// screen to existing P9.2 evidence. No full historical regression suite replay.
import fs from 'node:fs/promises';
import path from 'node:path';
import { createHash } from 'node:crypto';
import { launchChromium } from '../../scripts/orgchart-browser-runtime.mjs';
const output = path.resolve('test-results/org-chart-p9-4'), origin = (process.env.ORGCHART_STORY_ORIGIN ?? 'http://127.0.0.1:6064').replace(/\/$/, '');
const results = [],errors = [],startedAt = new Date().toISOString();
const check = (pass,name,detail) => { results.push({ name,status:pass ? 'PASS':'FAIL', ...(detail === undefined ? {} : { detail }) }); if (!pass) console.log('FAIL',name,JSON.stringify(detail)); };
const fixedOnly = process.argv.includes('--fixed-only');
const baseline = fixedOnly ? { files:[] } : JSON.parse(await fs.readFile(path.join(output,'baseline.json'),'utf8'));
const protectedPath = name => /^examples\/org-chart\/data.*\.json$/.test(name) || /^packages\/org-chart\/src\/assets\//.test(name)
|| ['packages/org-chart/src/company-color-presets.ts','packages/org-chart/src/core/style-presets.ts','packages/org-chart/src/core/employee-card.ts',
'packages/org-chart/src/styles/employee-card.css','packages/org-chart/src/core/workdesk-artwork.ts','packages/org-chart/src/core/workdesk-layout.ts',
'src/org-chart/center-composition-preview.ts','src/org-chart/org-chart-full-composition.stories.tsx','src/org-chart/org-chart-department-colors.stories.tsx',
'src/org-chart/org-chart-overview-internal.stories.tsx'].includes(name);
const protectedFiles = baseline.files.filter(file => protectedPath(file.path));
const changed = [];
for (const file of protectedFiles) { const actual = createHash('sha256').update(await fs.readFile(path.resolve(file.path))).digest('hex').toUpperCase(); if (actual !== file.sha256.toUpperCase()) changed.push({ path:file.path,before:file.sha256,after:actual }); }
if (!fixedOnly) check(protectedFiles.length > 20 && changed.length === 0,'Pre-P9.4 fixtures, approved SVG/images, card renderer/styles, company/department presets and Fixed source hashes preserved',{ checked:protectedFiles.length,changed });
const browser = await launchChromium({ headless:true }), page = await browser.newPage({ viewport:{ width:1440,height:900 } });
page.on('pageerror',error => errors.push(error.message)); page.on('console',message => { if (message.type() === 'error') errors.push(message.text()); });
await page.goto(`${origin}/iframe.html?id=orgchart--full-composition&viewMode=story`);
await page.waitForFunction(() => { const shadow = document.querySelector('.hm-orgchart-host')?.shadowRoot; return shadow?.querySelector('.hm-orgchart-stage[data-workdesk-artwork]') && !shadow.querySelector('[aria-busy="true"]') && [...shadow.querySelectorAll('link[rel="stylesheet"]')].every(link => link.sheet); });
await page.evaluate(async () => { await document.fonts.ready; await Promise.all([...document.querySelector('.hm-orgchart-host').shadowRoot.querySelectorAll('img')].map(async image => { image.loading = 'eager'; await image.decode(); })); for (let i = 0; i < 12; i++) await new Promise(requestAnimationFrame); });
const priorSource = await fs.readFile('examples/org-chart/verify-p9-2-composition.mjs','utf8');
const from = priorSource.indexOf('async function snapshot()'),to = priorSource.indexOf('async function stability()',from);
const snapshot = await new Function('page',priorSource.slice(from,to) + '; return snapshot();')(page);
const previous = JSON.parse(await fs.readFile('test-results/org-chart-p9-2/browser-composition.json','utf8')).snapshots['1440'];
const same = (a,b) => JSON.stringify(a) === JSON.stringify(b);
const normalizedEqual = snapshot.elements.every((element,index) => { const old = previous.elements[index]; return old?.key === element.key && old.hash === element.hash && same(old.style,element.style) && Object.keys(element.box).every(key => Math.abs(element.box[key] - old.box[key]) < .15); });
check(previous.htmlHash === snapshot.htmlHash && same(previous.assets,snapshot.assets) && normalizedEqual,'Fixed DOM, 139 asset hashes and 152 styles/geometry match preserved P9.2 evidence',{ previous:previous.htmlHash,current:snapshot.htmlHash,elements:snapshot.elements.length,assets:snapshot.assets.length });
check(Math.abs(snapshot.centerDifference) < 1 && snapshot.collisions.length === 0 && snapshot.counts.cards === 43 && snapshot.counts.paths === 5,'Fixed minimal center/cards/connectors regression',{ centerDifference:snapshot.centerDifference,counts:snapshot.counts,collisions:snapshot.collisions });
check(await page.evaluate(() => !document.querySelector('.hm-orgchart-host').shadowRoot.querySelector('[data-drag-drop-enabled],[data-edit-dragging],[data-drop-state],.hm-orgchart-move-feedback')),'Fixed has no ON/OFF or editing UI');
await page.screenshot({ path:path.join(output,'fixed-preserved-1440.png'),fullPage:true });
check(errors.length === 0,'Preservation browser console/page errors: zero',errors);
const result = { startedAt,completedAt:new Date().toISOString(),origin,results,errors,protectedFiles:protectedFiles.map(file => file.path),fixedSnapshot:snapshot,pass:results.filter(item => item.status === 'PASS').length,fail:results.filter(item => item.status === 'FAIL').length };
await fs.writeFile(path.join(output,'fixed-preservation.json'),JSON.stringify(result,null,2)); await browser.close(); console.log(JSON.stringify({ pass:result.pass,fail:result.fail })); if (result.fail) process.exitCode = 1;