const fs = require("fs");
const path = require("path");
const pixelmatch = (require("pixelmatch").default || require("pixelmatch"));
const sharp = require("sharp");
const BASELINES_DIR = path.join(__dirname, "..", "tests", "figma-baselines");
const SCREENSHOTS_DIR = path.join(__dirname, "..", "tests", "figma-screenshots");
const comparisons = [
{ name: "buttons", viewport: { width: 1200, height: 2372 }, background: "#ffffff" },
{ name: "alerts", viewport: { width: 1200, height: 1363 }, background: "#ffffff" },
{ name: "badges", viewport: { width: 1200, height: 743 }, background: "#ffffff" },
{ name: "forms", viewport: { width: 1200, height: 2648 }, background: "#ffffff" },
{ name: "breadcrumbs", viewport: { width: 1200, height: 567 }, background: "#000000" },
{ name: "divider", viewport: { width: 1200, height: 120 }, background: "#ffffff" },
{ name: "attached-file", viewport: { width: 560, height: 2000 }, background: "#000000" },
];
async function normalizeToCanvas(imagePath, targetWidth, targetHeight, padColor) {
const { data, info } = await sharp(imagePath)
.ensureAlpha()
.resize(targetWidth, targetHeight, { fit: "inside" })
.raw()
.toBuffer({ resolveWithObject: true });
const { width, height } = info;
const canvas = Buffer.alloc(targetWidth * targetHeight * 4);
const hex = padColor.replace("#", "");
const pr = parseInt(hex.substring(0, 2), 16);
const pg = parseInt(hex.substring(2, 4), 16);
const pb = parseInt(hex.substring(4, 6), 16);
for (let i = 0; i < targetWidth * targetHeight; i++) {
canvas[i * 4] = pr;
canvas[i * 4 + 1] = pg;
canvas[i * 4 + 2] = pb;
canvas[i * 4 + 3] = 255;
}
const offsetX = Math.round((targetWidth - width) / 2);
const offsetY = Math.round((targetHeight - height) / 2);
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
const srcIdx = (y * width + x) * 4;
const dstIdx = ((y + offsetY) * targetWidth + (x + offsetX)) * 4;
const srcA = data[srcIdx + 3] / 255;
const invA = 1 - srcA;
canvas[dstIdx] = Math.round(pr * invA + data[srcIdx] * srcA);
canvas[dstIdx + 1] = Math.round(pg * invA + data[srcIdx + 1] * srcA);
canvas[dstIdx + 2] = Math.round(pb * invA + data[srcIdx + 2] * srcA);
canvas[dstIdx + 3] = 255;
}
}
return canvas;
}
async function main() {
for (const c of comparisons) {
const screenshotPath = path.join(SCREENSHOTS_DIR, `${c.name}.png`);
const baselinePath = path.join(BASELINES_DIR, c.baseline || `${c.name}-baseline.png`);
if (!fs.existsSync(screenshotPath) || !fs.existsSync(baselinePath)) {
console.log(`${c.name}: missing files`);
continue;
}
const tw = c.viewport.width;
const th = c.viewport.height;
const screenshot = await normalizeToCanvas(screenshotPath, tw, th, c.background);
const baseline = await normalizeToCanvas(baselinePath, tw, th, c.background);
const diff = Buffer.alloc(tw * th * 4);
const mismatched = pixelmatch(screenshot, baseline, diff, tw, th, { threshold: 0.1, includeAA: false });
console.log(`${c.name}: ${(mismatched / (tw * th) * 100).toFixed(2)}%`);
}
}
main().catch(err => { console.error(err); process.exit(1); });