- Redesign PreJoin component and CSS for improved template compatibility and deterministic rendering - Remove mock studio toggle and related runtime logic; update useStudioLauncher to always use real backend - Add README-MOCK.md to document mock studio deprecation - Add mock-studio.html for manual popup emulation - Update environment variable resolution in route.ts for backend API - Add visual regression test scripts (capture, compare, visual_test_prejoin) using Playwright, Puppeteer, pixelmatch, and pngjs - Update package.json scripts and devDependencies for visual testing - Simplify PreJoin.stories.tsx for robust Storybook usage
66 lines
2.8 KiB
JavaScript
66 lines
2.8 KiB
JavaScript
import fs from 'fs';
|
|
import path from 'path';
|
|
import { chromium } from 'playwright';
|
|
import { PNG } from 'pngjs';
|
|
import pixelmatch from 'pixelmatch';
|
|
|
|
async function capture(url, outPath, width = 1280, height = 720) {
|
|
const browser = await chromium.launch({ headless: true, args: ['--no-sandbox'] });
|
|
const page = await browser.newPage({ viewport: { width, height } });
|
|
await page.goto(url, { waitUntil: 'networkidle' });
|
|
await page.waitForTimeout(500);
|
|
await page.screenshot({ path: outPath, fullPage: false });
|
|
await browser.close();
|
|
}
|
|
|
|
function compare(imgAPath, imgBPath, diffOut) {
|
|
const imgA = PNG.sync.read(fs.readFileSync(imgAPath));
|
|
const imgB = PNG.sync.read(fs.readFileSync(imgBPath));
|
|
if (imgA.width !== imgB.width || imgA.height !== imgB.height) {
|
|
throw new Error('Images must have same dimensions');
|
|
}
|
|
const { width, height } = imgA;
|
|
const diff = new PNG({ width, height });
|
|
const mismatched = pixelmatch(imgA.data, imgB.data, diff.data, width, height, { threshold: 0.1 });
|
|
fs.writeFileSync(diffOut, PNG.sync.write(diff));
|
|
return { mismatched, total: width * height, ratio: mismatched / (width * height) };
|
|
}
|
|
|
|
async function main() {
|
|
try {
|
|
const arg = process.argv[2] || `file://${path.resolve(process.cwd(), 'docs/prejoin_template.html')}`;
|
|
const outDir = '/tmp';
|
|
const outFile = path.join(outDir, 'prejoin_playwright_1280x720.png');
|
|
console.log('Capturing', arg, '->', outFile);
|
|
await capture(arg, outFile, 1280, 720);
|
|
console.log('Saved capture to', outFile);
|
|
|
|
const baselineA = path.resolve(process.cwd(), 'baselines/prejoin_regen_1280x720.png');
|
|
const baselineB = path.resolve(process.cwd(), 'baselines/prejoin_browserless_1280x720.png');
|
|
const report = { captured: outFile, compared: false };
|
|
|
|
if (fs.existsSync(baselineA)) {
|
|
const diffOut = path.join(outDir, 'prejoin_diff_1280x720.png');
|
|
const metrics = compare(outFile, baselineA, diffOut);
|
|
report.compared = true; report.baseline = baselineA; report.diff = diffOut; report.metrics = metrics;
|
|
console.log('Compared with', baselineA, 'metrics=', metrics);
|
|
} else if (fs.existsSync(baselineB)) {
|
|
const diffOut = path.join(outDir, 'prejoin_diff_1280x720.png');
|
|
const metrics = compare(outFile, baselineB, diffOut);
|
|
report.compared = true; report.baseline = baselineB; report.diff = diffOut; report.metrics = metrics;
|
|
console.log('Compared with', baselineB, 'metrics=', metrics);
|
|
} else {
|
|
console.log('No baseline found (checked baselines/prejoin_regen_1280x720.png and baselines/prejoin_browserless_1280x720.png)');
|
|
}
|
|
|
|
fs.writeFileSync(path.join(outDir, 'prejoin_playwright_report.json'), JSON.stringify(report, null, 2));
|
|
console.log('Report written to /tmp/prejoin_playwright_report.json');
|
|
} catch (e) {
|
|
console.error('Error:', e);
|
|
process.exit(2);
|
|
}
|
|
}
|
|
|
|
main();
|
|
|