import fs from 'node:fs'; import path from 'node:path'; import { pathToFileURL } from 'node:url'; import { createRequire } from 'node:module'; const require = createRequire(import.meta.url); const nodePathEntries = (process.env.NODE_PATH || '') .split(path.delimiter) .filter(Boolean); const resolveOptions = nodePathEntries.length > 0 ? { paths: nodePathEntries } : undefined; const { default: pixelmatch } = await import(pathToFileURL(require.resolve('pixelmatch', resolveOptions))); const { PNG } = require(require.resolve('pngjs', resolveOptions)); const [expectedPath, actualPath, diffPath = 'docs/ui-baseline/login-diff.png'] = process.argv.slice(2); if (!expectedPath || !actualPath) { console.error('Usage: node tools/compare_ui_baseline.mjs [diff.png]'); process.exit(2); } const expected = PNG.sync.read(fs.readFileSync(expectedPath)); const actual = PNG.sync.read(fs.readFileSync(actualPath)); if (expected.width !== actual.width || expected.height !== actual.height) { console.error(JSON.stringify({ ok: false, error: 'Image dimensions differ.', expected: { width: expected.width, height: expected.height }, actual: { width: actual.width, height: actual.height }, }, null, 2)); process.exit(1); } const diff = new PNG({ width: expected.width, height: expected.height }); const mismatchedPixels = pixelmatch( expected.data, actual.data, diff.data, expected.width, expected.height, { threshold: 0.1, includeAA: true } ); fs.mkdirSync(path.dirname(diffPath), { recursive: true }); fs.writeFileSync(diffPath, PNG.sync.write(diff)); const totalPixels = expected.width * expected.height; const result = { ok: mismatchedPixels === 0, expected: expectedPath, actual: actualPath, diff: diffPath, width: expected.width, height: expected.height, mismatchedPixels, totalPixels, mismatchRatio: Number((mismatchedPixels / totalPixels).toFixed(6)), }; console.log(JSON.stringify(result, null, 2)); process.exit(result.ok ? 0 : 1);