visual-diff-tool
Version:
Visual regression testing tool for comparing two URLs of the same app by capturing screenshots, performing pixel-by-pixel image comparisons, and highlighting visual differences. Ideal for detecting UI changes after deployments or updates.
67 lines (57 loc) • 2.45 kB
JavaScript
// screenshotComparison.js
const fs = require('fs');
const path = require('path');
const { PNG } = require('pngjs');
const pixelmatch = require('pixelmatch');
class ScreenshotComparison {
static async captureScreenshot(page, outputDir, label, suffix) {
let retries = 3;
while(retries--) {
try {
const timestamp = Date.now();
const imgPath = path.join(outputDir, `${label}-${suffix}-${timestamp}.png`);
console.log(suffix + ' taking screenshot');
await new Promise(resolve => setTimeout(resolve, 5000));
console.log('timeout done!');
await page.waitForSelector('body', { visible: true, timeout: 5000 });
console.log('waiting done!');
await page.screenshot({ path: imgPath, fullPage: true });
console.log(suffix + ' taking screenshot done');
return imgPath;
} catch (err) {
console.error('Screenshot failed:', err);
await new Promise(resolve => setTimeout(resolve, 1000));
}
}
}
static async compareScreenshots(imgPath1, imgPath2, label, threshold = 0.1) {
const img1 = PNG.sync.read(fs.readFileSync(imgPath1));
const img2 = PNG.sync.read(fs.readFileSync(imgPath2));
const width = Math.min(img1.width, img2.width);
const height = Math.min(img1.height, img2.height);
// Crop both images to shared size
const croppedImg1 = this._cropImage(img1, width, height);
const croppedImg2 = this._cropImage(img2, width, height);
const diff = new PNG({ width, height });
const diffPixels = pixelmatch(
croppedImg1.data,
croppedImg2.data,
diff.data,
width,
height,
{ threshold }
);
const diffPath = path.join(path.dirname(imgPath1), `${label}-diff-${Date.now()}.png`);
if (diffPixels > 0) {
fs.writeFileSync(diffPath, PNG.sync.write(diff));
return { diffPixels, diffPath, isDifferent: true };
}
return { diffPixels, diffPath: null, isDifferent: false };
}
static _cropImage(png, width, height) {
const cropped = new PNG({ width, height });
PNG.bitblt(png, cropped, 0, 0, width, height, 0, 0);
return cropped;
}
}
module.exports = ScreenshotComparison;