mirror of
https://github.com/hanzoai/Detox.git
synced 2026-09-24 16:55:12 +00:00
94 lines
3.6 KiB
JavaScript
94 lines
3.6 KiB
JavaScript
const fs = require('fs-extra');
|
|
const { ssim } = require('ssim.js');
|
|
const { PNG } = require('pngjs');
|
|
const { isRNNewArch, rnVersion } = require('../../../src/utils/rn-consts/rn-consts');
|
|
|
|
const rnMinorVer = rnVersion.minor;
|
|
const jestExpect = require('expect').default;
|
|
|
|
// Threshold for SSIM comparison, if two images have SSIM score below this threshold, they are considered different.
|
|
const SSIM_SCORE_THRESHOLD = 0.997;
|
|
|
|
async function expectElementSnapshotToMatch(elementOrDevice, snapshotName, ssimThreshold = SSIM_SCORE_THRESHOLD, androidSdk) {
|
|
const bitmapPath = await elementOrDevice.takeScreenshot(snapshotName);
|
|
const isNewArchString = isRNNewArch ? '.new-arch' : '';
|
|
const androidSdkString = androidSdk ? `-sdk${androidSdk}` : '';
|
|
const expectedBitmapPath = `./e2e/assets/${snapshotName}.${device.getPlatform()}${androidSdkString}${isNewArchString}.png`;
|
|
|
|
if (await fs.pathExists(expectedBitmapPath) === false || process.env.UPDATE_SNAPSHOTS === 'true') {
|
|
await fs.copy(bitmapPath, expectedBitmapPath, { overwrite: true });
|
|
} else {
|
|
await expectSSIMToBeClose(bitmapPath, expectedBitmapPath, ssimThreshold);
|
|
}
|
|
}
|
|
|
|
async function expectDeviceSnapshotToMatch(snapshotName, ssimThreshold = SSIM_SCORE_THRESHOLD, androidSdk) {
|
|
// Set status bar to consistent state for snapshot. Currently, doesn't work on iOS 17.
|
|
await device.setStatusBar({ time: '2024-03-08T09:41:00-07:00' });
|
|
|
|
await expectElementSnapshotToMatch(device, snapshotName, ssimThreshold, androidSdk);
|
|
}
|
|
|
|
async function expectSSIMToBeClose(bitmapPath, expectedBitmapPath, ssimThreshold) {
|
|
const image = loadImage(bitmapPath);
|
|
const expectedImage = loadImage(expectedBitmapPath);
|
|
|
|
const { mssim, performance } = ssim(image, expectedImage);
|
|
|
|
if (mssim < ssimThreshold) {
|
|
throw new Error(
|
|
`Expected bitmaps at '${bitmapPath}' and '${expectedBitmapPath}' to have an SSIM score ` +
|
|
`of at least ${SSIM_SCORE_THRESHOLD}, but got ${mssim}. This means the snapshots are different ` +
|
|
`(comparison took ${performance}ms)`
|
|
);
|
|
}
|
|
}
|
|
|
|
function loadImage(path) {
|
|
const imageBuffer = fs.readFileSync(path);
|
|
const image = PNG.sync.read(imageBuffer);
|
|
return convertToSSIMFormat(image);
|
|
}
|
|
|
|
function convertToSSIMFormat(image) {
|
|
return {
|
|
data: new Uint8Array(image.data),
|
|
width: image.width,
|
|
height: image.height
|
|
};
|
|
}
|
|
|
|
// Allow numeric values to be inconsistent, as they are not consistent between environments.
|
|
async function expectViewHierarchySnapshotToMatch(viewHierarchy, snapshotName) {
|
|
// Find all occurrences of number attributes and replace with `="<number>"`
|
|
const viewHierarchyWithNumberReplaced = viewHierarchy.replace(/[=]"\d+"/g, '="<number>"');
|
|
await expectSnapshotToMatch(viewHierarchyWithNumberReplaced, snapshotName);
|
|
}
|
|
|
|
async function expectSnapshotToMatch(value, snapshotName, ignoreWhiteSpace = true) {
|
|
const isNewArchString = isRNNewArch ? '.new-arch' : '';
|
|
const snapshotPath = `./e2e/assets/${snapshotName}.${rnMinorVer}.${device.getPlatform()}${isNewArchString}.txt`;
|
|
|
|
function removeWhiteSpaces(str) {
|
|
return str.replace(/\s/g, '');
|
|
}
|
|
|
|
if (await fs.pathExists(snapshotPath) === false || process.env.UPDATE_SNAPSHOTS === 'true') {
|
|
await fs.writeFile(snapshotPath, value, 'utf8');
|
|
} else {
|
|
const expectedValue = await fs.readFile(snapshotPath, 'utf8');
|
|
if (ignoreWhiteSpace) {
|
|
jestExpect(removeWhiteSpaces(value)).toEqual(removeWhiteSpaces(expectedValue));
|
|
} else {
|
|
jestExpect(value).toEqual(expectedValue);
|
|
}
|
|
}
|
|
}
|
|
|
|
module.exports = {
|
|
expectViewHierarchySnapshotToMatch,
|
|
expectSnapshotToMatch,
|
|
expectElementSnapshotToMatch,
|
|
expectDeviceSnapshotToMatch
|
|
};
|