UNPKG

@lewiswright/vitest-plugin-vis

Version:
81 lines (75 loc) 4.21 kB
import dedent from 'dedent'; import { resolve } from 'pathe'; import { isBase64String } from "../shared/base64.js"; import { compareImage } from "../shared/compare_image.js"; import { alignImagesToSameSize } from "./align_images.js"; import { toDataURL, toImageData } from "./image_data.js"; import { prettifyOptions } from "./image_snapshot_matcher.logic.js"; import { convertElementToCssSelector } from "./selector.js"; import { toTaskId } from "./task_id.js"; import { server } from "./vitest_browser_context_proxy.js"; export function imageSnapshotMatcher(commands) { return async function matchImageSnapshot(test, subject, options) { const isAutoSnapshot = !!test.meta.vis?.isAutoSnapshot; const taskId = toTaskId(test); const info = await commands.prepareImageSnapshotComparison(taskId, parseImageSnapshotSubject(subject), isAutoSnapshot, options?.customizeSnapshotId ? await parseImageSnapshotOptions(commands, taskId, isAutoSnapshot, options) : options); if (!info) return; options = { ...info, ...options }; const baselineImage = await toImageData(info.baseline); const resultImage = await toImageData(info.result); const [baselineAlignedImage, resultAlignedImage] = alignImagesToSameSize(baselineImage, resultImage); const { width, height } = baselineAlignedImage; const diffImage = new ImageData(width, height); const { pass, diffAmount } = compareImage(baselineAlignedImage.data, resultAlignedImage.data, diffImage.data, width, height, options); if (pass) { if (options?.expectToFail) { throw new Error(dedent `Snapshot \`${taskId}\` matched but expected to fail. Options: ${prettifyOptions(options)} Diff: ${options.failureThresholdType === 'percent' ? `${diffAmount}%` : `${diffAmount} pixels`} Expected: ${resolve(info.projectRoot, info.baselinePath)} Actual: ${resolve(info.projectRoot, info.resultPath)}`); } return; } if (server.config.snapshotOptions.updateSnapshot === 'all' && !options?.expectToFail) { await writeSnapshot(commands, resolve(info.projectRoot, info.baselinePath), resultImage); return; } await writeSnapshot(commands, resolve(info.projectRoot, info.diffPath), diffImage); throw new Error(dedent `Snapshot \`${taskId}\` mismatched ${options?.failureThreshold ? options?.failureThresholdType === 'percent' ? `Expected image to match within ${options.failureThreshold}% but was differ by ${diffAmount}%.` : `Expected image to match within ${options.failureThreshold} pixels but was differ by ${diffAmount} pixels.` : `Expected image to match but was differ by ${options?.failureThresholdType === 'percent' ? `${diffAmount}%` : `${diffAmount} pixels`}.`} Options: ${prettifyOptions(options)} Expected: ${resolve(info.projectRoot, info.baselinePath)} Actual: ${resolve(info.projectRoot, info.resultPath)} Difference: ${resolve(info.projectRoot, info.diffPath)}`); }; } /** * @deprecated internalized. Use `matchImageSnapshot` directly instead. */ export function parseImageSnapshotSubject(subject) { if (subject instanceof Element) return convertElementToCssSelector(subject); if (subject?.['selector']) return subject['selector']; if (isBase64String(subject)) return subject; throw new Error(`'toMatchImageSnapshot()' expects the subject to be an element, locator, or image encoded in base64 string, but got: ${subject}`); } async function writeSnapshot(commands, path, image) { const content = (await toDataURL(image)).split(',')[1]; return commands.writeFile(path, content, { encoding: 'base64' }); } async function parseImageSnapshotOptions(commands, taskId, isAutoSnapshot, options) { const index = await commands.imageSnapshotNextIndex(taskId); const { customizeSnapshotId, ...rest } = options; const snapshotFileId = customizeSnapshotId({ id: taskId, index, isAutoSnapshot }); return { ...rest, snapshotFileId }; }