From 9a4e7338278d3788f37ba1f2824399d8f8fab144 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 3 Nov 2022 16:29:59 +0000 Subject: [PATCH] chore(release): 1.1.0 [skip ci] # [1.1.0](https://github.com/braze-inc/cypress-plugin-visual-regression-diff/compare/v1.0.2...v1.1.0) (2022-11-03) ### Bug Fixes * **deps:** update all non-major dependencies ([#165](https://github.com/braze-inc/cypress-plugin-visual-regression-diff/issues/165)) ([602640f](https://github.com/braze-inc/cypress-plugin-visual-regression-diff/commit/602640fcca6e8173930efa116244258549aa5264)) * ts declaration generation ([1a1e0cc](https://github.com/braze-inc/cypress-plugin-visual-regression-diff/commit/1a1e0ccd4c442d3e4d45f4d899139a08963e0c85)) * typings for older typescript ([#170](https://github.com/braze-inc/cypress-plugin-visual-regression-diff/issues/170)) ([96499ec](https://github.com/braze-inc/cypress-plugin-visual-regression-diff/commit/96499ecc2959bab8c39b599ba7eb87fbd79ceec3)), closes [#167](https://github.com/braze-inc/cypress-plugin-visual-regression-diff/issues/167) ### Features * support Cypress retries functionality ([#171](https://github.com/braze-inc/cypress-plugin-visual-regression-diff/issues/171)) ([7d7d010](https://github.com/braze-inc/cypress-plugin-visual-regression-diff/commit/7d7d010938ee124e694e8cf0270aa99c89db59df)), closes [#168](https://github.com/braze-inc/cypress-plugin-visual-regression-diff/issues/168) --- dist/plugins.js | 10 ++++++++-- dist/plugins.js.map | 2 +- dist/plugins.mjs | 10 ++++++++-- dist/plugins.mjs.map | 2 +- dist/support.js | 25 +++++++++++++++++++++---- dist/support.js.map | 2 +- dist/support.mjs | 25 +++++++++++++++++++++---- dist/support.mjs.map | 2 +- 8 files changed, 62 insertions(+), 16 deletions(-) diff --git a/dist/plugins.js b/dist/plugins.js index 8d0653e2..dabd995c 100644 --- a/dist/plugins.js +++ b/dist/plugins.js @@ -43,7 +43,7 @@ const PATH_VARIABLES = { const WINDOWS_LIKE_DRIVE_REGEX = /^[A-Z]:$/; const METADATA_KEY = "FRSOURCE_CPVRD_V"; -var version = "3.0.1"; +var version = "3.1.0"; function isHighSurrogate(codePoint) { return codePoint >= 0xd800 && codePoint <= 0xdbff; @@ -152,7 +152,8 @@ const nameCacheCounter = {}; const generateScreenshotPath = ({ titleFromOptions, imagesPath, - specPath + specPath, + currentRetryNumber }) => { const parsePathPartVariables = (pathPart, i) => { if (pathPart === PATH_VARIABLES.specPath) { @@ -172,6 +173,11 @@ const generateScreenshotPath = ({ if (typeof nameCacheCounter[screenshotPath] === "undefined") { nameCacheCounter[screenshotPath] = -1; + } // it's a retry of the same image, so let's decrease the counter + + + if (currentRetryNumber > 0) { + --nameCacheCounter[screenshotPath]; } return path__default["default"].join(IMAGE_SNAPSHOT_PREFIX, `${screenshotPath} #${++nameCacheCounter[screenshotPath]}${FILE_SUFFIX.actual}.png`); diff --git a/dist/plugins.js.map b/dist/plugins.js.map index 041126c2..6c8bf919 100644 --- a/dist/plugins.js.map +++ b/dist/plugins.js.map @@ -1 +1 @@ -{"version":3,"file":"plugins.js","sources":["../src/constants.ts","../node_modules/truncate-utf8-bytes/lib/truncate.js","../node_modules/truncate-utf8-bytes/index.js","../node_modules/sanitize-filename/index.js","../src/screenshotPath.utils.ts","../src/image.utils.ts","../src/afterScreenshot.hook.ts","../src/task.hook.ts","../src/plugins.ts"],"sourcesContent":["const PLUGIN_NAME = \"cp-visual-regression-diff\";\nexport const LINK_PREFIX = `#${PLUGIN_NAME}-`;\nexport const OVERLAY_CLASS = `${PLUGIN_NAME}-overlay`;\nexport const IMAGE_SNAPSHOT_PREFIX = `__${PLUGIN_NAME}_snapshots__`;\n\nexport enum FILE_SUFFIX {\n diff = \".diff\",\n actual = \".actual\",\n}\n\nexport const TASK = {\n getScreenshotPathInfo: `${PLUGIN_NAME}-getScreenshotPathInfo`,\n compareImages: `${PLUGIN_NAME}-compareImages`,\n approveImage: `${PLUGIN_NAME}-approveImage`,\n cleanupImages: `${PLUGIN_NAME}-cleanupImages`,\n doesFileExist: `${PLUGIN_NAME}-doesFileExist`,\n runAfterScreenshotHook: `${PLUGIN_NAME}-runAfterScreenshotHook`,\n /* c8 ignore next */\n};\n\nexport const PATH_VARIABLES = {\n specPath: \"{spec_path}\",\n unixSystemRootPath: \"{unix_system_root_path}\",\n winSystemRootPath: \"{win_system_root_path}\",\n} as const;\n\nexport const WINDOWS_LIKE_DRIVE_REGEX = /^[A-Z]:$/;\n\nexport const METADATA_KEY = \"FRSOURCE_CPVRD_V\";\n","'use strict';\n\nfunction isHighSurrogate(codePoint) {\n return codePoint >= 0xd800 && codePoint <= 0xdbff;\n}\n\nfunction isLowSurrogate(codePoint) {\n return codePoint >= 0xdc00 && codePoint <= 0xdfff;\n}\n\n// Truncate string by size in bytes\nmodule.exports = function truncate(getLength, string, byteLength) {\n if (typeof string !== \"string\") {\n throw new Error(\"Input must be string\");\n }\n\n var charLength = string.length;\n var curByteLength = 0;\n var codePoint;\n var segment;\n\n for (var i = 0; i < charLength; i += 1) {\n codePoint = string.charCodeAt(i);\n segment = string[i];\n\n if (isHighSurrogate(codePoint) && isLowSurrogate(string.charCodeAt(i + 1))) {\n i += 1;\n segment += string[i];\n }\n\n curByteLength += getLength(segment);\n\n if (curByteLength === byteLength) {\n return string.slice(0, i + 1);\n }\n else if (curByteLength > byteLength) {\n return string.slice(0, i - segment.length + 1);\n }\n }\n\n return string;\n};\n\n","'use strict';\n\nvar truncate = require(\"./lib/truncate\");\nvar getLength = Buffer.byteLength.bind(Buffer);\nmodule.exports = truncate.bind(null, getLength);\n","/*jshint node:true*/\n'use strict';\n\n/**\n * Replaces characters in strings that are illegal/unsafe for filenames.\n * Unsafe characters are either removed or replaced by a substitute set\n * in the optional `options` object.\n *\n * Illegal Characters on Various Operating Systems\n * / ? < > \\ : * | \"\n * https://kb.acronis.com/content/39790\n *\n * Unicode Control codes\n * C0 0x00-0x1f & C1 (0x80-0x9f)\n * http://en.wikipedia.org/wiki/C0_and_C1_control_codes\n *\n * Reserved filenames on Unix-based systems (\".\", \"..\")\n * Reserved filenames in Windows (\"CON\", \"PRN\", \"AUX\", \"NUL\", \"COM1\",\n * \"COM2\", \"COM3\", \"COM4\", \"COM5\", \"COM6\", \"COM7\", \"COM8\", \"COM9\",\n * \"LPT1\", \"LPT2\", \"LPT3\", \"LPT4\", \"LPT5\", \"LPT6\", \"LPT7\", \"LPT8\", and\n * \"LPT9\") case-insesitively and with or without filename extensions.\n *\n * Capped at 255 characters in length.\n * http://unix.stackexchange.com/questions/32795/what-is-the-maximum-allowed-filename-and-folder-size-with-ecryptfs\n *\n * @param {String} input Original filename\n * @param {Object} options {replacement: String | Function }\n * @return {String} Sanitized filename\n */\n\nvar truncate = require(\"truncate-utf8-bytes\");\n\nvar illegalRe = /[\\/\\?<>\\\\:\\*\\|\"]/g;\nvar controlRe = /[\\x00-\\x1f\\x80-\\x9f]/g;\nvar reservedRe = /^\\.+$/;\nvar windowsReservedRe = /^(con|prn|aux|nul|com[0-9]|lpt[0-9])(\\..*)?$/i;\nvar windowsTrailingRe = /[\\. ]+$/;\n\nfunction sanitize(input, replacement) {\n if (typeof input !== 'string') {\n throw new Error('Input must be string');\n }\n var sanitized = input\n .replace(illegalRe, replacement)\n .replace(controlRe, replacement)\n .replace(reservedRe, replacement)\n .replace(windowsReservedRe, replacement)\n .replace(windowsTrailingRe, replacement);\n return truncate(sanitized, 255);\n}\n\nmodule.exports = function (input, options) {\n var replacement = (options && options.replacement) || '';\n var output = sanitize(input, replacement);\n if (replacement === '') {\n return output;\n }\n return sanitize(output, '');\n};\n","import path from \"path\";\nimport {\n FILE_SUFFIX,\n IMAGE_SNAPSHOT_PREFIX,\n PATH_VARIABLES,\n WINDOWS_LIKE_DRIVE_REGEX,\n} from \"./constants\";\nimport sanitize from \"sanitize-filename\";\n\nconst nameCacheCounter: Record = {};\n\nexport const generateScreenshotPath = ({\n titleFromOptions,\n imagesPath,\n specPath,\n}: {\n titleFromOptions: string;\n imagesPath: string;\n specPath: string;\n}) => {\n const parsePathPartVariables = (pathPart: string, i: number) => {\n if (pathPart === PATH_VARIABLES.specPath) {\n return path.dirname(specPath);\n } else if (i === 0 && !pathPart) {\n // when unix-like absolute path\n return PATH_VARIABLES.unixSystemRootPath;\n } else if (i === 0 && WINDOWS_LIKE_DRIVE_REGEX.test(pathPart)) {\n // when win-like absolute path\n return path.join(PATH_VARIABLES.winSystemRootPath, pathPart[0]);\n }\n\n return pathPart;\n };\n\n const screenshotPath = path.join(\n ...imagesPath.split(\"/\").map(parsePathPartVariables),\n sanitize(titleFromOptions)\n );\n\n if (typeof nameCacheCounter[screenshotPath] === \"undefined\") {\n nameCacheCounter[screenshotPath] = -1;\n }\n return path.join(\n IMAGE_SNAPSHOT_PREFIX,\n `${screenshotPath} #${++nameCacheCounter[screenshotPath]}${\n FILE_SUFFIX.actual\n }.png`\n );\n};\n\nconst screenshotPathRegex = new RegExp(\n `^([\\\\s\\\\S]+?) #([0-9]+)(?:(?:\\\\${FILE_SUFFIX.diff})|(?:\\\\${FILE_SUFFIX.actual}))?\\\\.(?:png|PNG)$`\n);\nexport const wasScreenshotUsed = (imagePath: string) => {\n const matched = imagePath.match(screenshotPathRegex);\n /* c8 ignore next */ if (!matched) return false;\n const [, screenshotPath, numString] = matched;\n const num = parseInt(numString);\n /* c8 ignore next */ if (!screenshotPath || isNaN(num)) return false;\n return (\n screenshotPath in nameCacheCounter &&\n num <= nameCacheCounter[screenshotPath]\n );\n};\n\nexport const resetScreenshotNameCache = () => {\n Object.keys(nameCacheCounter).forEach((k) => delete nameCacheCounter[k]);\n};\n","import path from \"path\";\nimport fs from \"fs\";\nimport { PNG, PNGWithMetadata } from \"pngjs\";\nimport sharp from \"sharp\";\nimport { addMetadata, getMetadata } from \"meta-png\";\nimport glob from \"glob\";\nimport { version } from \"../package.json\";\nimport { wasScreenshotUsed } from \"./screenshotPath.utils\";\nimport { METADATA_KEY } from \"./constants\";\n\nexport const addPNGMetadata = (png: Buffer) =>\n addMetadata(png, METADATA_KEY, version /* c8 ignore next */);\nexport const getPNGMetadata = (png: Buffer) =>\n getMetadata(png, METADATA_KEY /* c8 ignore next */);\nexport const isImageCurrentVersion = (png: Buffer) =>\n getPNGMetadata(png) === version;\nexport const isImageGeneratedByPlugin = (png: Buffer) =>\n !!getPNGMetadata(png /* c8 ignore next */);\n\nexport const writePNG = (name: string, png: PNG | Buffer) =>\n fs.writeFileSync(\n name,\n addPNGMetadata(png instanceof PNG ? PNG.sync.write(png) : png)\n );\n\nconst inArea = (x: number, y: number, height: number, width: number) =>\n y > height || x > width;\n\nexport const fillSizeDifference = (\n image: PNG,\n width: number,\n height: number\n) => {\n for (let y = 0; y < image.height; y++) {\n for (let x = 0; x < image.width; x++) {\n if (inArea(x, y, height, width)) {\n const idx = (image.width * y + x) << 2;\n image.data[idx] = 0;\n image.data[idx + 1] = 0;\n image.data[idx + 2] = 0;\n image.data[idx + 3] = 64;\n }\n }\n }\n return image;\n /* c8 ignore next */\n};\n\nexport const createImageResizer =\n (width: number, height: number) => (source: PNG) => {\n const resized = new PNG({ width, height, fill: true });\n PNG.bitblt(source, resized, 0, 0, source.width, source.height, 0, 0);\n return resized;\n /* c8 ignore next */\n };\n\nexport const scaleImageAndWrite = async ({\n scaleFactor,\n path,\n}: {\n scaleFactor: number;\n path: string;\n}) => {\n const imgBuffer = fs.readFileSync(path);\n if (scaleFactor === 1) return imgBuffer;\n\n const rawImgNew = PNG.sync.read(imgBuffer);\n const newImageWidth = Math.ceil(rawImgNew.width * scaleFactor);\n const newImageHeight = Math.ceil(rawImgNew.height * scaleFactor);\n await sharp(imgBuffer).resize(newImageWidth, newImageHeight).toFile(path);\n\n return fs.readFileSync(path);\n};\n\nexport const alignImagesToSameSize = (\n firstImage: PNGWithMetadata,\n secondImage: PNGWithMetadata\n) => {\n const firstImageWidth = firstImage.width;\n const firstImageHeight = firstImage.height;\n const secondImageWidth = secondImage.width;\n const secondImageHeight = secondImage.height;\n\n const resizeToSameSize = createImageResizer(\n Math.max(firstImageWidth, secondImageWidth),\n Math.max(firstImageHeight, secondImageHeight)\n );\n\n const resizedFirst = resizeToSameSize(firstImage);\n const resizedSecond = resizeToSameSize(secondImage);\n\n return [\n fillSizeDifference(resizedFirst, firstImageWidth, firstImageHeight),\n fillSizeDifference(resizedSecond, secondImageWidth, secondImageHeight),\n ];\n};\n\nexport const cleanupUnused = (rootPath: string) => {\n glob\n .sync(\"**/*.png\", {\n cwd: rootPath,\n ignore: \"node_modules/**/*\",\n })\n .forEach((pngPath) => {\n const absolutePath = path.join(rootPath, pngPath);\n if (\n !wasScreenshotUsed(pngPath) &&\n isImageGeneratedByPlugin(fs.readFileSync(absolutePath))\n ) {\n fs.unlinkSync(absolutePath);\n }\n });\n};\n","import path from \"path\";\nimport { promises as fs } from \"fs\";\nimport moveFile from \"move-file\";\nimport { IMAGE_SNAPSHOT_PREFIX, PATH_VARIABLES } from \"./constants\";\n\ntype NotFalsy = T extends false | null | undefined ? never : T;\n\nconst MIMIC_ROOT_WIN_REGEX = new RegExp(\n `^${PATH_VARIABLES.winSystemRootPath}\\\\${path.sep}([A-Z])\\\\${path.sep}`\n);\nconst MIMIC_ROOT_UNIX_REGEX = new RegExp(\n `^${PATH_VARIABLES.unixSystemRootPath}\\\\${path.sep}`\n);\n\nconst getConfigVariableOrThrow = (\n config: Cypress.PluginConfigOptions,\n name: K\n) => {\n if (config[name]) {\n return config[name] as NotFalsy;\n }\n\n /* c8 ignore start */\n throw `[@frsource/cypress-plugin-visual-regression-diff] CypressConfig.${name} cannot be missing or \\`false\\`!`;\n};\n/* c8 ignore stop */\n\nexport const parseAbsolutePath = ({\n screenshotPath,\n projectRoot,\n}: {\n screenshotPath: string;\n projectRoot: string;\n}) => {\n let newAbsolutePath: string;\n const matchedMimicingWinRoot = screenshotPath.match(MIMIC_ROOT_WIN_REGEX);\n const matchedMimicingUnixRoot = screenshotPath.match(MIMIC_ROOT_UNIX_REGEX);\n if (matchedMimicingWinRoot && matchedMimicingWinRoot[1]) {\n const driveLetter = matchedMimicingWinRoot[1];\n newAbsolutePath = path.join(\n `${driveLetter}:\\\\`,\n screenshotPath.substring(matchedMimicingWinRoot[0].length)\n );\n } else if (matchedMimicingUnixRoot) {\n newAbsolutePath =\n path.sep + screenshotPath.substring(matchedMimicingUnixRoot[0].length);\n } else {\n newAbsolutePath = path.join(projectRoot, screenshotPath);\n }\n return path.normalize(newAbsolutePath);\n};\n\nexport const initAfterScreenshotHook =\n (config: Cypress.PluginConfigOptions) =>\n (\n details: Cypress.ScreenshotDetails\n ):\n | void\n | Cypress.AfterScreenshotReturnObject\n | Promise => {\n // it's not a screenshot generated by FRSOURCE Cypress Plugin Visual Regression Diff\n /* c8 ignore start */\n if (details.name?.indexOf(IMAGE_SNAPSHOT_PREFIX) !== 0) return;\n /* c8 ignore stop */\n const screenshotsFolder = getConfigVariableOrThrow(\n config,\n \"screenshotsFolder\"\n );\n const screenshotPath = details.name.substring(\n IMAGE_SNAPSHOT_PREFIX.length + path.sep.length\n );\n const newAbsolutePath = parseAbsolutePath({\n screenshotPath,\n projectRoot: config.projectRoot,\n });\n\n return (async () => {\n await moveFile(details.path, newAbsolutePath);\n await fs.rm(path.join(screenshotsFolder, IMAGE_SNAPSHOT_PREFIX), {\n recursive: true,\n force: true,\n });\n\n return { path: newAbsolutePath };\n })();\n };\n","import fs from \"fs\";\nimport { PNG } from \"pngjs\";\nimport pixelmatch, { PixelmatchOptions } from \"pixelmatch\";\nimport moveFile from \"move-file\";\nimport path from \"path\";\nimport { FILE_SUFFIX, TASK } from \"./constants\";\nimport {\n cleanupUnused,\n alignImagesToSameSize,\n scaleImageAndWrite,\n isImageCurrentVersion,\n writePNG,\n} from \"./image.utils\";\nimport {\n generateScreenshotPath,\n resetScreenshotNameCache,\n} from \"./screenshotPath.utils\";\nimport type { CompareImagesTaskReturn } from \"./types\";\nimport { initAfterScreenshotHook } from \"./afterScreenshot.hook\";\n\nexport type CompareImagesCfg = {\n scaleFactor: number;\n title: string;\n imgNew: string;\n imgOld: string;\n updateImages: boolean;\n maxDiffThreshold: number;\n diffConfig: PixelmatchOptions;\n};\n\nconst round = (n: number) => Math.ceil(n * 1000) / 1000;\n\nconst unlinkSyncSafe = (path: string) =>\n fs.existsSync(path) && fs.unlinkSync(path);\nconst moveSyncSafe = (pathFrom: string, pathTo: string) =>\n fs.existsSync(pathFrom) && moveFile.sync(pathFrom, pathTo);\n\nexport const getScreenshotPathInfoTask = (cfg: {\n titleFromOptions: string;\n imagesPath: string;\n specPath: string;\n}) => {\n const screenshotPath = generateScreenshotPath(cfg);\n\n return { screenshotPath, title: path.basename(screenshotPath, \".png\") };\n};\n\nexport const cleanupImagesTask = (config: Cypress.PluginConfigOptions) => {\n if (config.env[\"pluginVisualRegressionCleanupUnusedImages\"]) {\n cleanupUnused(config.projectRoot);\n }\n\n resetScreenshotNameCache();\n\n return null;\n};\n\nexport const approveImageTask = ({ img }: { img: string }) => {\n const oldImg = img.replace(FILE_SUFFIX.actual, \"\");\n unlinkSyncSafe(oldImg);\n\n const diffImg = img.replace(FILE_SUFFIX.actual, FILE_SUFFIX.diff);\n unlinkSyncSafe(diffImg);\n\n moveSyncSafe(img, oldImg);\n\n return null;\n};\n\nexport const compareImagesTask = async (\n cfg: CompareImagesCfg\n): Promise => {\n const messages = [] as string[];\n const rawImgNewBuffer = await scaleImageAndWrite({\n scaleFactor: cfg.scaleFactor,\n path: cfg.imgNew,\n });\n let imgDiff: number | undefined;\n let imgNewBase64: string, imgOldBase64: string, imgDiffBase64: string;\n let error = false;\n\n if (fs.existsSync(cfg.imgOld) && !cfg.updateImages) {\n const rawImgNew = PNG.sync.read(rawImgNewBuffer);\n const rawImgOldBuffer = fs.readFileSync(cfg.imgOld);\n const rawImgOld = PNG.sync.read(rawImgOldBuffer);\n const isImgSizeDifferent =\n rawImgNew.height !== rawImgOld.height ||\n rawImgNew.width !== rawImgOld.width;\n\n const [imgNew, imgOld] = isImgSizeDifferent\n ? alignImagesToSameSize(rawImgNew, rawImgOld)\n : [rawImgNew, rawImgOld];\n\n const { width, height } = imgNew;\n const diff = new PNG({ width, height });\n const diffConfig = Object.assign({ includeAA: true }, cfg.diffConfig);\n\n const diffPixels = pixelmatch(\n imgNew.data,\n imgOld.data,\n diff.data,\n width,\n height,\n diffConfig\n );\n imgDiff = diffPixels / (width * height);\n\n if (isImgSizeDifferent) {\n messages.push(\n `Warning: Images size mismatch - new screenshot is ${rawImgNew.width}px by ${rawImgNew.height}px while old one is ${rawImgOld.width}px by ${rawImgOld.height} (width x height).`\n );\n }\n\n if (imgDiff > cfg.maxDiffThreshold) {\n messages.unshift(\n `Image diff factor (${round(\n imgDiff\n )}%) is bigger than maximum threshold option ${cfg.maxDiffThreshold}.`\n );\n error = true;\n }\n\n const diffBuffer = PNG.sync.write(diff);\n imgNewBase64 = PNG.sync.write(imgNew).toString(\"base64\");\n imgDiffBase64 = diffBuffer.toString(\"base64\");\n imgOldBase64 = PNG.sync.write(imgOld).toString(\"base64\");\n\n if (error) {\n writePNG(\n cfg.imgNew.replace(FILE_SUFFIX.actual, FILE_SUFFIX.diff),\n diffBuffer\n );\n return {\n error,\n message: messages.join(\"\\n\"),\n imgDiff,\n imgNewBase64,\n imgDiffBase64,\n imgOldBase64,\n maxDiffThreshold: cfg.maxDiffThreshold,\n };\n } else {\n if (rawImgOld && !isImageCurrentVersion(rawImgOldBuffer)) {\n writePNG(cfg.imgNew, rawImgNewBuffer);\n moveFile.sync(cfg.imgNew, cfg.imgOld);\n } else {\n // don't overwrite file if it's the same (imgDiff < cfg.maxDiffThreshold && !isImgSizeDifferent)\n fs.unlinkSync(cfg.imgNew);\n }\n }\n } else {\n // there is no \"old screenshot\" or screenshots should be immediately updated\n imgDiff = 0;\n imgNewBase64 = \"\";\n imgDiffBase64 = \"\";\n imgOldBase64 = \"\";\n writePNG(cfg.imgNew, rawImgNewBuffer);\n moveFile.sync(cfg.imgNew, cfg.imgOld);\n }\n\n if (typeof imgDiff !== \"undefined\") {\n messages.unshift(\n `Image diff factor (${round(\n imgDiff\n )}%) is within boundaries of maximum threshold option ${\n cfg.maxDiffThreshold\n }.`\n );\n return {\n message: messages.join(\"\\n\"),\n imgDiff,\n imgNewBase64,\n imgDiffBase64,\n imgOldBase64,\n maxDiffThreshold: cfg.maxDiffThreshold,\n };\n }\n\n /* c8 ignore next */\n return null;\n};\n\nexport const doesFileExistTask = ({ path }: { path: string }) =>\n fs.existsSync(path);\n\n/* c8 ignore start */\nexport const initTaskHook = (config: Cypress.PluginConfigOptions) => ({\n [TASK.getScreenshotPathInfo]: getScreenshotPathInfoTask,\n [TASK.cleanupImages]: cleanupImagesTask.bind(undefined, config),\n [TASK.doesFileExist]: doesFileExistTask,\n [TASK.approveImage]: approveImageTask,\n [TASK.compareImages]: compareImagesTask,\n [TASK.runAfterScreenshotHook]: initAfterScreenshotHook(config),\n});\n/* c8 ignore stop */\n","import { initTaskHook } from \"./task.hook\";\nimport { initAfterScreenshotHook } from \"./afterScreenshot.hook\";\n\n/* c8 ignore start */\nconst initForceDeviceScaleFactor = (on: Cypress.PluginEvents) => {\n // based on https://github.com/cypress-io/cypress/issues/2102#issuecomment-521299946\n on(\"before:browser:launch\", (browser, launchOptions) => {\n if (browser.name === \"chrome\" || browser.name === \"chromium\") {\n launchOptions.args.push(\"--force-device-scale-factor=1\");\n launchOptions.args.push(\"--high-dpi-support=1\");\n } else if (browser.name === \"electron\" && browser.isHeaded) {\n // eslint-disable-next-line no-console\n console.log(\n \"There isn't currently a way of setting the device scale factor in Cypress when running headed electron so we disable the image regression commands.\"\n );\n }\n });\n};\n/* c8 ignore stop */\n\nexport const initPlugin = (\n on: Cypress.PluginEvents,\n config: Cypress.PluginConfigOptions\n) => {\n /* c8 ignore start */\n if (config.env[\"pluginVisualRegressionForceDeviceScaleFactor\"] !== false) {\n initForceDeviceScaleFactor(on);\n }\n /* c8 ignore stop */\n on(\"task\", initTaskHook(config));\n on(\"after:screenshot\", initAfterScreenshotHook(config));\n};\n"],"names":["PLUGIN_NAME","IMAGE_SNAPSHOT_PREFIX","FILE_SUFFIX","TASK","getScreenshotPathInfo","compareImages","approveImage","cleanupImages","doesFileExist","runAfterScreenshotHook","PATH_VARIABLES","specPath","unixSystemRootPath","winSystemRootPath","WINDOWS_LIKE_DRIVE_REGEX","METADATA_KEY","truncate","nameCacheCounter","generateScreenshotPath","titleFromOptions","imagesPath","parsePathPartVariables","pathPart","i","path","dirname","test","join","screenshotPath","split","map","sanitize","actual","screenshotPathRegex","RegExp","diff","wasScreenshotUsed","imagePath","matched","match","numString","num","parseInt","isNaN","resetScreenshotNameCache","Object","keys","forEach","k","addPNGMetadata","png","addMetadata","version","getPNGMetadata","getMetadata","isImageCurrentVersion","isImageGeneratedByPlugin","writePNG","name","fs","writeFileSync","PNG","sync","write","inArea","x","y","height","width","fillSizeDifference","image","idx","data","createImageResizer","source","resized","fill","bitblt","scaleImageAndWrite","scaleFactor","imgBuffer","readFileSync","rawImgNew","read","newImageWidth","Math","ceil","newImageHeight","sharp","resize","toFile","alignImagesToSameSize","firstImage","secondImage","firstImageWidth","firstImageHeight","secondImageWidth","secondImageHeight","resizeToSameSize","max","resizedFirst","resizedSecond","cleanupUnused","rootPath","glob","cwd","ignore","pngPath","absolutePath","unlinkSync","MIMIC_ROOT_WIN_REGEX","sep","MIMIC_ROOT_UNIX_REGEX","getConfigVariableOrThrow","config","parseAbsolutePath","projectRoot","newAbsolutePath","matchedMimicingWinRoot","matchedMimicingUnixRoot","driveLetter","substring","length","normalize","initAfterScreenshotHook","details","indexOf","screenshotsFolder","moveFile","rm","recursive","force","round","n","unlinkSyncSafe","existsSync","moveSyncSafe","pathFrom","pathTo","getScreenshotPathInfoTask","cfg","title","basename","cleanupImagesTask","env","approveImageTask","img","oldImg","replace","diffImg","compareImagesTask","messages","rawImgNewBuffer","imgNew","imgDiff","imgNewBase64","imgOldBase64","imgDiffBase64","error","imgOld","updateImages","rawImgOldBuffer","rawImgOld","isImgSizeDifferent","diffConfig","assign","includeAA","diffPixels","pixelmatch","push","maxDiffThreshold","unshift","diffBuffer","toString","message","doesFileExistTask","initTaskHook","bind","undefined","initForceDeviceScaleFactor","on","browser","launchOptions","args","isHeaded","console","log","initPlugin"],"mappings":";;;;;;;;;;;;;;;;;;AAAA,MAAMA,WAAW,GAAG,2BAApB;AAGO,MAAMC,qBAAqB,QAAQD,yBAAnC;AAEP,IAAYE,WAAZ;;AAAA,WAAYA;AACVA,EAAAA,mBAAA,UAAA;AACAA,EAAAA,qBAAA,YAAA;AACD,CAHD,EAAYA,WAAW,KAAXA,WAAW,KAAA,CAAvB;;AAKO,MAAMC,IAAI,GAAG;AAClBC,EAAAA,qBAAqB,KAAKJ,mCADR;AAElBK,EAAAA,aAAa,KAAKL,2BAFA;AAGlBM,EAAAA,YAAY,KAAKN,0BAHC;AAIlBO,EAAAA,aAAa,KAAKP,2BAJA;AAKlBQ,EAAAA,aAAa,KAAKR,2BALA;AAMlBS,EAAAA,sBAAsB,KAAKT;AAC3B;;AAPkB,CAAb;AAUA,MAAMU,cAAc,GAAG;AAC5BC,EAAAA,QAAQ,EAAE,aADkB;AAE5BC,EAAAA,kBAAkB,EAAE,yBAFQ;AAG5BC,EAAAA,iBAAiB,EAAE;AAHS,CAAvB;AAMA,MAAMC,wBAAwB,GAAG,UAAjC;AAEA,MAAMC,YAAY,GAAG,kBAArB;;;;AC1BP,SAAS,eAAe,CAAC,SAAS,EAAE;AACpC,EAAE,OAAO,SAAS,IAAI,MAAM,IAAI,SAAS,IAAI,MAAM,CAAC;AACpD,CAAC;AACD;AACA,SAAS,cAAc,CAAC,SAAS,EAAE;AACnC,EAAE,OAAO,SAAS,IAAI,MAAM,IAAI,SAAS,IAAI,MAAM,CAAC;AACpD,CAAC;AACD;AACA;AACA,YAAc,GAAG,SAAS,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE;AAClE,EAAE,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE;AAClC,IAAI,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;AAC5C,GAAG;AACH;AACA,EAAE,IAAI,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC;AACjC,EAAE,IAAI,aAAa,GAAG,CAAC,CAAC;AACxB,EAAE,IAAI,SAAS,CAAC;AAChB,EAAE,IAAI,OAAO,CAAC;AACd;AACA,EAAE,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,UAAU,EAAE,CAAC,IAAI,CAAC,EAAE;AAC1C,IAAI,SAAS,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;AACrC,IAAI,OAAO,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;AACxB;AACA,IAAI,IAAI,eAAe,CAAC,SAAS,CAAC,IAAI,cAAc,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;AAChF,MAAM,CAAC,IAAI,CAAC,CAAC;AACb,MAAM,OAAO,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC;AAC3B,KAAK;AACL;AACA,IAAI,aAAa,IAAI,SAAS,CAAC,OAAO,CAAC,CAAC;AACxC;AACA,IAAI,IAAI,aAAa,KAAK,UAAU,EAAE;AACtC,MAAM,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;AACpC,KAAK;AACL,SAAS,IAAI,aAAa,GAAG,UAAU,EAAE;AACzC,MAAM,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AACrD,KAAK;AACL,GAAG;AACH;AACA,EAAE,OAAO,MAAM,CAAC;AAChB,CAAC;;ACtCD,IAAI,SAAS,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAC/C,qBAAc,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC;;;ACF/C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAC8C;AAC9C;AACA,IAAI,SAAS,GAAG,mBAAmB,CAAC;AACpC,IAAI,SAAS,GAAG,uBAAuB,CAAC;AACxC,IAAI,UAAU,GAAG,OAAO,CAAC;AACzB,IAAI,iBAAiB,GAAG,+CAA+C,CAAC;AACxE,IAAI,iBAAiB,GAAG,SAAS,CAAC;AAClC;AACA,SAAS,QAAQ,CAAC,KAAK,EAAE,WAAW,EAAE;AACtC,EAAE,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE;AACjC,IAAI,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;AAC5C,GAAG;AACH,EAAE,IAAI,SAAS,GAAG,KAAK;AACvB,KAAK,OAAO,CAAC,SAAS,EAAE,WAAW,CAAC;AACpC,KAAK,OAAO,CAAC,SAAS,EAAE,WAAW,CAAC;AACpC,KAAK,OAAO,CAAC,UAAU,EAAE,WAAW,CAAC;AACrC,KAAK,OAAO,CAAC,iBAAiB,EAAE,WAAW,CAAC;AAC5C,KAAK,OAAO,CAAC,iBAAiB,EAAE,WAAW,CAAC,CAAC;AAC7C,EAAE,OAAOC,iBAAQ,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;AAClC,CAAC;AACD;AACA,oBAAc,GAAG,UAAU,KAAK,EAAE,OAAO,EAAE;AAC3C,EAAE,IAAI,WAAW,GAAG,CAAC,OAAO,IAAI,OAAO,CAAC,WAAW,KAAK,EAAE,CAAC;AAC3D,EAAE,IAAI,MAAM,GAAG,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;AAC5C,EAAE,IAAI,WAAW,KAAK,EAAE,EAAE;AAC1B,IAAI,OAAO,MAAM,CAAC;AAClB,GAAG;AACH,EAAE,OAAO,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AAC9B,CAAC;;ACjDD,MAAMC,gBAAgB,GAA2B,EAAjD;AAEO,MAAMC,sBAAsB,GAAG,CAAC;AACrCC,EAAAA,gBADqC;AAErCC,EAAAA,UAFqC;AAGrCT,EAAAA;AAHqC,CAAD;AASpC,QAAMU,sBAAsB,GAAG,CAACC,QAAD,EAAmBC,CAAnB;AAC7B,QAAID,QAAQ,KAAKZ,cAAc,CAACC,QAAhC,EAA0C;AACxC,aAAOa,wBAAI,CAACC,OAAL,CAAad,QAAb,CAAP;AACD,KAFD,MAEO,IAAIY,CAAC,KAAK,CAAN,IAAW,CAACD,QAAhB,EAA0B;AAC/B;AACA,aAAOZ,cAAc,CAACE,kBAAtB;AACD,KAHM,MAGA,IAAIW,CAAC,KAAK,CAAN,IAAWT,wBAAwB,CAACY,IAAzB,CAA8BJ,QAA9B,CAAf,EAAwD;AAC7D;AACA,aAAOE,wBAAI,CAACG,IAAL,CAAUjB,cAAc,CAACG,iBAAzB,EAA4CS,QAAQ,CAAC,CAAD,CAApD,CAAP;AACD;;AAED,WAAOA,QAAP;AACD,GAZD;;AAcA,QAAMM,cAAc,GAAGJ,wBAAI,CAACG,IAAL,CACrB,GAAGP,UAAU,CAACS,KAAX,CAAiB,GAAjB,EAAsBC,GAAtB,CAA0BT,sBAA1B,CADkB,EAErBU,gBAAQ,CAACZ,gBAAD,CAFa,CAAvB;;AAKA,MAAI,OAAOF,gBAAgB,CAACW,cAAD,CAAvB,KAA4C,WAAhD,EAA6D;AAC3DX,IAAAA,gBAAgB,CAACW,cAAD,CAAhB,GAAmC,CAAC,CAApC;AACD;;AACD,SAAOJ,wBAAI,CAACG,IAAL,CACL1B,qBADK,KAEF2B,mBAAmB,EAAEX,gBAAgB,CAACW,cAAD,IACtC1B,WAAW,CAAC8B,YAHT,CAAP;AAMD,CArCM;AAuCP,MAAMC,mBAAmB,GAAG,IAAIC,MAAJ,mCACQhC,WAAW,CAACiC,cAAcjC,WAAW,CAAC8B,0BAD9C,CAA5B;AAGO,MAAMI,iBAAiB,GAAIC,SAAD;AAC/B,QAAMC,OAAO,GAAGD,SAAS,CAACE,KAAV,CAAgBN,mBAAhB,CAAhB;AACA;;AAAqB,MAAI,CAACK,OAAL,EAAc,OAAO,KAAP;AACnC,QAAM,GAAGV,cAAH,EAAmBY,SAAnB,IAAgCF,OAAtC;AACA,QAAMG,GAAG,GAAGC,QAAQ,CAACF,SAAD,CAApB;AACA;;AAAqB,MAAI,CAACZ,cAAD,IAAmBe,KAAK,CAACF,GAAD,CAA5B,EAAmC,OAAO,KAAP;AACxD,SACEb,cAAc,IAAIX,gBAAlB,IACAwB,GAAG,IAAIxB,gBAAgB,CAACW,cAAD,CAFzB;AAID,CAVM;AAYA,MAAMgB,wBAAwB,GAAG;AACtCC,EAAAA,MAAM,CAACC,IAAP,CAAY7B,gBAAZ,EAA8B8B,OAA9B,CAAuCC,CAAD,IAAO,OAAO/B,gBAAgB,CAAC+B,CAAD,CAApE;AACD,CAFM;;ACvDA,MAAMC,cAAc,GAAIC,GAAD,IAC5BC,mBAAW,CAACD,GAAD,EAAMnC,YAAN,EAAoBqC;AAAQ;AAA5B,CADN;AAEA,MAAMC,cAAc,GAAIH,GAAD,IAC5BI,mBAAW,CAACJ,GAAD,EAAMnC;AAAa;AAAnB,CADN;AAEA,MAAMwC,qBAAqB,GAAIL,GAAD,IACnCG,cAAc,CAACH,GAAD,CAAd,KAAwBE,OADnB;AAEA,MAAMI,wBAAwB,GAAIN,GAAD,IACtC,CAAC,CAACG,cAAc,CAACH;AAAI;AAAL,CADX;AAGA,MAAMO,QAAQ,GAAG,CAACC,IAAD,EAAeR,GAAf,KACtBS,sBAAE,CAACC,aAAH,CACEF,IADF,EAEET,cAAc,CAACC,GAAG,YAAYW,SAAf,GAAqBA,SAAG,CAACC,IAAJ,CAASC,KAAT,CAAeb,GAAf,CAArB,GAA2CA,GAA5C,CAFhB,CADK;;AAMP,MAAMc,MAAM,GAAG,CAACC,CAAD,EAAYC,CAAZ,EAAuBC,MAAvB,EAAuCC,KAAvC,KACbF,CAAC,GAAGC,MAAJ,IAAcF,CAAC,GAAGG,KADpB;;AAGO,MAAMC,kBAAkB,GAAG,CAChCC,KADgC,EAEhCF,KAFgC,EAGhCD,MAHgC;AAKhC,OAAK,IAAID,CAAC,GAAG,CAAb,EAAgBA,CAAC,GAAGI,KAAK,CAACH,MAA1B,EAAkCD,CAAC,EAAnC,EAAuC;AACrC,SAAK,IAAID,CAAC,GAAG,CAAb,EAAgBA,CAAC,GAAGK,KAAK,CAACF,KAA1B,EAAiCH,CAAC,EAAlC,EAAsC;AACpC,UAAID,MAAM,CAACC,CAAD,EAAIC,CAAJ,EAAOC,MAAP,EAAeC,KAAf,CAAV,EAAiC;AAC/B,cAAMG,GAAG,GAAID,KAAK,CAACF,KAAN,GAAcF,CAAd,GAAkBD,CAAnB,IAAyB,CAArC;AACAK,QAAAA,KAAK,CAACE,IAAN,CAAWD,GAAX,IAAkB,CAAlB;AACAD,QAAAA,KAAK,CAACE,IAAN,CAAWD,GAAG,GAAG,CAAjB,IAAsB,CAAtB;AACAD,QAAAA,KAAK,CAACE,IAAN,CAAWD,GAAG,GAAG,CAAjB,IAAsB,CAAtB;AACAD,QAAAA,KAAK,CAACE,IAAN,CAAWD,GAAG,GAAG,CAAjB,IAAsB,EAAtB;AACD;AACF;AACF;;AACD,SAAOD,KAAP;AACA;AACD,CAlBM;AAoBA,MAAMG,kBAAkB,GAC7B,CAACL,KAAD,EAAgBD,MAAhB,KAAoCO,MAAD;AACjC,QAAMC,OAAO,GAAG,IAAId,SAAJ,CAAQ;AAAEO,IAAAA,KAAF;AAASD,IAAAA,MAAT;AAAiBS,IAAAA,IAAI,EAAE;AAAvB,GAAR,CAAhB;AACAf,EAAAA,SAAG,CAACgB,MAAJ,CAAWH,MAAX,EAAmBC,OAAnB,EAA4B,CAA5B,EAA+B,CAA/B,EAAkCD,MAAM,CAACN,KAAzC,EAAgDM,MAAM,CAACP,MAAvD,EAA+D,CAA/D,EAAkE,CAAlE;AACA,SAAOQ,OAAP;AACA;AACD,CANI;AAQA,MAAMG,kBAAkB,GAAG,OAAO;AACvCC,EAAAA,WADuC;AAEvCvD,EAAAA;AAFuC,CAAP;AAOhC,QAAMwD,SAAS,GAAGrB,sBAAE,CAACsB,YAAH,CAAgBzD,IAAhB,CAAlB;AACA,MAAIuD,WAAW,KAAK,CAApB,EAAuB,OAAOC,SAAP;AAEvB,QAAME,SAAS,GAAGrB,SAAG,CAACC,IAAJ,CAASqB,IAAT,CAAcH,SAAd,CAAlB;AACA,QAAMI,aAAa,GAAGC,IAAI,CAACC,IAAL,CAAUJ,SAAS,CAACd,KAAV,GAAkBW,WAA5B,CAAtB;AACA,QAAMQ,cAAc,GAAGF,IAAI,CAACC,IAAL,CAAUJ,SAAS,CAACf,MAAV,GAAmBY,WAA7B,CAAvB;AACA,QAAMS,yBAAK,CAACR,SAAD,CAAL,CAAiBS,MAAjB,CAAwBL,aAAxB,EAAuCG,cAAvC,EAAuDG,MAAvD,CAA8DlE,IAA9D,CAAN;AAEA,SAAOmC,sBAAE,CAACsB,YAAH,CAAgBzD,IAAhB,CAAP;AACD,CAhBM;AAkBA,MAAMmE,qBAAqB,GAAG,CACnCC,UADmC,EAEnCC,WAFmC;AAInC,QAAMC,eAAe,GAAGF,UAAU,CAACxB,KAAnC;AACA,QAAM2B,gBAAgB,GAAGH,UAAU,CAACzB,MAApC;AACA,QAAM6B,gBAAgB,GAAGH,WAAW,CAACzB,KAArC;AACA,QAAM6B,iBAAiB,GAAGJ,WAAW,CAAC1B,MAAtC;AAEA,QAAM+B,gBAAgB,GAAGzB,kBAAkB,CACzCY,IAAI,CAACc,GAAL,CAASL,eAAT,EAA0BE,gBAA1B,CADyC,EAEzCX,IAAI,CAACc,GAAL,CAASJ,gBAAT,EAA2BE,iBAA3B,CAFyC,CAA3C;AAKA,QAAMG,YAAY,GAAGF,gBAAgB,CAACN,UAAD,CAArC;AACA,QAAMS,aAAa,GAAGH,gBAAgB,CAACL,WAAD,CAAtC;AAEA,SAAO,CACLxB,kBAAkB,CAAC+B,YAAD,EAAeN,eAAf,EAAgCC,gBAAhC,CADb,EAEL1B,kBAAkB,CAACgC,aAAD,EAAgBL,gBAAhB,EAAkCC,iBAAlC,CAFb,CAAP;AAID,CArBM;AAuBA,MAAMK,aAAa,GAAIC,QAAD;AAC3BC,EAAAA,wBAAI,CACD1C,IADH,CACQ,UADR,EACoB;AAChB2C,IAAAA,GAAG,EAAEF,QADW;AAEhBG,IAAAA,MAAM,EAAE;AAFQ,GADpB,EAKG3D,OALH,CAKY4D,OAAD;AACP,UAAMC,YAAY,GAAGpF,wBAAI,CAACG,IAAL,CAAU4E,QAAV,EAAoBI,OAApB,CAArB;;AACA,QACE,CAACvE,iBAAiB,CAACuE,OAAD,CAAlB,IACAnD,wBAAwB,CAACG,sBAAE,CAACsB,YAAH,CAAgB2B,YAAhB,CAAD,CAF1B,EAGE;AACAjD,MAAAA,sBAAE,CAACkD,UAAH,CAAcD,YAAd;AACD;AACF,GAbH;AAcD,CAfM;;AC1FP,MAAME,oBAAoB,GAAG,IAAI5E,MAAJ,KACvBxB,cAAc,CAACG,sBAAsBW,wBAAI,CAACuF,eAAevF,wBAAI,CAACuF,KADvC,CAA7B;AAGA,MAAMC,qBAAqB,GAAG,IAAI9E,MAAJ,KACxBxB,cAAc,CAACE,uBAAuBY,wBAAI,CAACuF,KADnB,CAA9B;;AAIA,MAAME,wBAAwB,GAAG,CAC/BC,MAD+B,EAE/BxD,IAF+B;AAI/B,MAAIwD,MAAM,CAACxD,IAAD,CAAV,EAAkB;AAChB,WAAOwD,MAAM,CAACxD,IAAD,CAAb;AACD;AAED;;;AACA,2EAAyEA,sCAAzE;AACD,CAVD;AAWA;;;AAEO,MAAMyD,iBAAiB,GAAG,CAAC;AAChCvF,EAAAA,cADgC;AAEhCwF,EAAAA;AAFgC,CAAD;AAO/B,MAAIC,eAAJ;AACA,QAAMC,sBAAsB,GAAG1F,cAAc,CAACW,KAAf,CAAqBuE,oBAArB,CAA/B;AACA,QAAMS,uBAAuB,GAAG3F,cAAc,CAACW,KAAf,CAAqByE,qBAArB,CAAhC;;AACA,MAAIM,sBAAsB,IAAIA,sBAAsB,CAAC,CAAD,CAApD,EAAyD;AACvD,UAAME,WAAW,GAAGF,sBAAsB,CAAC,CAAD,CAA1C;AACAD,IAAAA,eAAe,GAAG7F,wBAAI,CAACG,IAAL,IACb6F,gBADa,EAEhB5F,cAAc,CAAC6F,SAAf,CAAyBH,sBAAsB,CAAC,CAAD,CAAtB,CAA0BI,MAAnD,CAFgB,CAAlB;AAID,GAND,MAMO,IAAIH,uBAAJ,EAA6B;AAClCF,IAAAA,eAAe,GACb7F,wBAAI,CAACuF,GAAL,GAAWnF,cAAc,CAAC6F,SAAf,CAAyBF,uBAAuB,CAAC,CAAD,CAAvB,CAA2BG,MAApD,CADb;AAED,GAHM,MAGA;AACLL,IAAAA,eAAe,GAAG7F,wBAAI,CAACG,IAAL,CAAUyF,WAAV,EAAuBxF,cAAvB,CAAlB;AACD;;AACD,SAAOJ,wBAAI,CAACmG,SAAL,CAAeN,eAAf,CAAP;AACD,CAvBM;AAyBA,MAAMO,uBAAuB,GACjCV,MAAD,IAEEW,OADF;;;AAME;;AACA;AACA,MAAI,kBAAAA,OAAO,CAACnE,IAAR,mCAAcoE,OAAd,CAAsB7H,qBAAtB,OAAiD,CAArD,EAAwD;AACxD;;AACA,QAAM8H,iBAAiB,GAAGd,wBAAwB,CAChDC,MADgD,EAEhD,mBAFgD,CAAlD;AAIA,QAAMtF,cAAc,GAAGiG,OAAO,CAACnE,IAAR,CAAa+D,SAAb,CACrBxH,qBAAqB,CAACyH,MAAtB,GAA+BlG,wBAAI,CAACuF,GAAL,CAASW,MADnB,CAAvB;AAGA,QAAML,eAAe,GAAGF,iBAAiB,CAAC;AACxCvF,IAAAA,cADwC;AAExCwF,IAAAA,WAAW,EAAEF,MAAM,CAACE;AAFoB,GAAD,CAAzC;AAKA,SAAO,CAAC;AACN,UAAMY,4BAAQ,CAACH,OAAO,CAACrG,IAAT,EAAe6F,eAAf,CAAd;AACA,UAAM1D,WAAE,CAACsE,EAAH,CAAMzG,wBAAI,CAACG,IAAL,CAAUoG,iBAAV,EAA6B9H,qBAA7B,CAAN,EAA2D;AAC/DiI,MAAAA,SAAS,EAAE,IADoD;AAE/DC,MAAAA,KAAK,EAAE;AAFwD,KAA3D,CAAN;AAKA,WAAO;AAAE3G,MAAAA,IAAI,EAAE6F;AAAR,KAAP;AACD,GARM,GAAP;AASD,CAjCI;;ACtBP,MAAMe,KAAK,GAAIC,CAAD,IAAehD,IAAI,CAACC,IAAL,CAAU+C,CAAC,GAAG,IAAd,IAAsB,IAAnD;;AAEA,MAAMC,cAAc,GAAI9G,IAAD,IACrBmC,sBAAE,CAAC4E,UAAH,CAAc/G,IAAd,KAAuBmC,sBAAE,CAACkD,UAAH,CAAcrF,IAAd,CADzB;;AAEA,MAAMgH,YAAY,GAAG,CAACC,QAAD,EAAmBC,MAAnB,KACnB/E,sBAAE,CAAC4E,UAAH,CAAcE,QAAd,KAA2BT,4BAAQ,CAAClE,IAAT,CAAc2E,QAAd,EAAwBC,MAAxB,CAD7B;;AAGO,MAAMC,yBAAyB,GAAIC,GAAD;AAKvC,QAAMhH,cAAc,GAAGV,sBAAsB,CAAC0H,GAAD,CAA7C;AAEA,SAAO;AAAEhH,IAAAA,cAAF;AAAkBiH,IAAAA,KAAK,EAAErH,wBAAI,CAACsH,QAAL,CAAclH,cAAd,EAA8B,MAA9B;AAAzB,GAAP;AACD,CARM;AAUA,MAAMmH,iBAAiB,GAAI7B,MAAD;AAC/B,MAAIA,MAAM,CAAC8B,GAAP,CAAW,2CAAX,CAAJ,EAA6D;AAC3D1C,IAAAA,aAAa,CAACY,MAAM,CAACE,WAAR,CAAb;AACD;;AAEDxE,EAAAA,wBAAwB;AAExB,SAAO,IAAP;AACD,CARM;AAUA,MAAMqG,gBAAgB,GAAG,CAAC;AAAEC,EAAAA;AAAF,CAAD;AAC9B,QAAMC,MAAM,GAAGD,GAAG,CAACE,OAAJ,CAAYlJ,WAAW,CAAC8B,MAAxB,EAAgC,EAAhC,CAAf;AACAsG,EAAAA,cAAc,CAACa,MAAD,CAAd;AAEA,QAAME,OAAO,GAAGH,GAAG,CAACE,OAAJ,CAAYlJ,WAAW,CAAC8B,MAAxB,EAAgC9B,WAAW,CAACiC,IAA5C,CAAhB;AACAmG,EAAAA,cAAc,CAACe,OAAD,CAAd;AAEAb,EAAAA,YAAY,CAACU,GAAD,EAAMC,MAAN,CAAZ;AAEA,SAAO,IAAP;AACD,CAVM;AAYA,MAAMG,iBAAiB,GAAG,MAC/BV,GAD+B;AAG/B,QAAMW,QAAQ,GAAG,EAAjB;AACA,QAAMC,eAAe,GAAG,MAAM1E,kBAAkB,CAAC;AAC/CC,IAAAA,WAAW,EAAE6D,GAAG,CAAC7D,WAD8B;AAE/CvD,IAAAA,IAAI,EAAEoH,GAAG,CAACa;AAFqC,GAAD,CAAhD;AAIA,MAAIC,OAAJ;AACA,MAAIC,YAAJ,EAA0BC,YAA1B,EAAgDC,aAAhD;AACA,MAAIC,KAAK,GAAG,KAAZ;;AAEA,MAAInG,sBAAE,CAAC4E,UAAH,CAAcK,GAAG,CAACmB,MAAlB,KAA6B,CAACnB,GAAG,CAACoB,YAAtC,EAAoD;AAClD,UAAM9E,SAAS,GAAGrB,SAAG,CAACC,IAAJ,CAASqB,IAAT,CAAcqE,eAAd,CAAlB;AACA,UAAMS,eAAe,GAAGtG,sBAAE,CAACsB,YAAH,CAAgB2D,GAAG,CAACmB,MAApB,CAAxB;AACA,UAAMG,SAAS,GAAGrG,SAAG,CAACC,IAAJ,CAASqB,IAAT,CAAc8E,eAAd,CAAlB;AACA,UAAME,kBAAkB,GACtBjF,SAAS,CAACf,MAAV,KAAqB+F,SAAS,CAAC/F,MAA/B,IACAe,SAAS,CAACd,KAAV,KAAoB8F,SAAS,CAAC9F,KAFhC;AAIA,UAAM,CAACqF,MAAD,EAASM,MAAT,IAAmBI,kBAAkB,GACvCxE,qBAAqB,CAACT,SAAD,EAAYgF,SAAZ,CADkB,GAEvC,CAAChF,SAAD,EAAYgF,SAAZ,CAFJ;AAIA,UAAM;AAAE9F,MAAAA,KAAF;AAASD,MAAAA;AAAT,QAAoBsF,MAA1B;AACA,UAAMtH,IAAI,GAAG,IAAI0B,SAAJ,CAAQ;AAAEO,MAAAA,KAAF;AAASD,MAAAA;AAAT,KAAR,CAAb;AACA,UAAMiG,UAAU,GAAGvH,MAAM,CAACwH,MAAP,CAAc;AAAEC,MAAAA,SAAS,EAAE;AAAb,KAAd,EAAmC1B,GAAG,CAACwB,UAAvC,CAAnB;AAEA,UAAMG,UAAU,GAAGC,8BAAU,CAC3Bf,MAAM,CAACjF,IADoB,EAE3BuF,MAAM,CAACvF,IAFoB,EAG3BrC,IAAI,CAACqC,IAHsB,EAI3BJ,KAJ2B,EAK3BD,MAL2B,EAM3BiG,UAN2B,CAA7B;AAQAV,IAAAA,OAAO,GAAGa,UAAU,IAAInG,KAAK,GAAGD,MAAZ,CAApB;;AAEA,QAAIgG,kBAAJ,EAAwB;AACtBZ,MAAAA,QAAQ,CAACkB,IAAT,sDACuDvF,SAAS,CAACd,cAAcc,SAAS,CAACf,6BAA6B+F,SAAS,CAAC9F,cAAc8F,SAAS,CAAC/F,0BADxJ;AAGD;;AAED,QAAIuF,OAAO,GAAGd,GAAG,CAAC8B,gBAAlB,EAAoC;AAClCnB,MAAAA,QAAQ,CAACoB,OAAT,uBACwBvC,KAAK,CACzBsB,OADyB,+CAEoBd,GAAG,CAAC8B,mBAHrD;AAKAZ,MAAAA,KAAK,GAAG,IAAR;AACD;;AAED,UAAMc,UAAU,GAAG/G,SAAG,CAACC,IAAJ,CAASC,KAAT,CAAe5B,IAAf,CAAnB;AACAwH,IAAAA,YAAY,GAAG9F,SAAG,CAACC,IAAJ,CAASC,KAAT,CAAe0F,MAAf,EAAuBoB,QAAvB,CAAgC,QAAhC,CAAf;AACAhB,IAAAA,aAAa,GAAGe,UAAU,CAACC,QAAX,CAAoB,QAApB,CAAhB;AACAjB,IAAAA,YAAY,GAAG/F,SAAG,CAACC,IAAJ,CAASC,KAAT,CAAegG,MAAf,EAAuBc,QAAvB,CAAgC,QAAhC,CAAf;;AAEA,QAAIf,KAAJ,EAAW;AACTrG,MAAAA,QAAQ,CACNmF,GAAG,CAACa,MAAJ,CAAWL,OAAX,CAAmBlJ,WAAW,CAAC8B,MAA/B,EAAuC9B,WAAW,CAACiC,IAAnD,CADM,EAENyI,UAFM,CAAR;AAIA,aAAO;AACLd,QAAAA,KADK;AAELgB,QAAAA,OAAO,EAAEvB,QAAQ,CAAC5H,IAAT,CAAc,IAAd,CAFJ;AAGL+H,QAAAA,OAHK;AAILC,QAAAA,YAJK;AAKLE,QAAAA,aALK;AAMLD,QAAAA,YANK;AAOLc,QAAAA,gBAAgB,EAAE9B,GAAG,CAAC8B;AAPjB,OAAP;AASD,KAdD,MAcO;AACL,UAAIR,SAAS,IAAI,CAAC3G,qBAAqB,CAAC0G,eAAD,CAAvC,EAA0D;AACxDxG,QAAAA,QAAQ,CAACmF,GAAG,CAACa,MAAL,EAAaD,eAAb,CAAR;AACAxB,QAAAA,4BAAQ,CAAClE,IAAT,CAAc8E,GAAG,CAACa,MAAlB,EAA0Bb,GAAG,CAACmB,MAA9B;AACD,OAHD,MAGO;AACL;AACApG,QAAAA,sBAAE,CAACkD,UAAH,CAAc+B,GAAG,CAACa,MAAlB;AACD;AACF;AACF,GArED,MAqEO;AACL;AACAC,IAAAA,OAAO,GAAG,CAAV;AACAC,IAAAA,YAAY,GAAG,EAAf;AACAE,IAAAA,aAAa,GAAG,EAAhB;AACAD,IAAAA,YAAY,GAAG,EAAf;AACAnG,IAAAA,QAAQ,CAACmF,GAAG,CAACa,MAAL,EAAaD,eAAb,CAAR;AACAxB,IAAAA,4BAAQ,CAAClE,IAAT,CAAc8E,GAAG,CAACa,MAAlB,EAA0Bb,GAAG,CAACmB,MAA9B;AACD;;AAED,MAAI,OAAOL,OAAP,KAAmB,WAAvB,EAAoC;AAClCH,IAAAA,QAAQ,CAACoB,OAAT,uBACwBvC,KAAK,CACzBsB,OADyB,wDAGzBd,GAAG,CAAC8B,mBAJR;AAOA,WAAO;AACLI,MAAAA,OAAO,EAAEvB,QAAQ,CAAC5H,IAAT,CAAc,IAAd,CADJ;AAEL+H,MAAAA,OAFK;AAGLC,MAAAA,YAHK;AAILE,MAAAA,aAJK;AAKLD,MAAAA,YALK;AAMLc,MAAAA,gBAAgB,EAAE9B,GAAG,CAAC8B;AANjB,KAAP;AAQD;AAED;;;AACA,SAAO,IAAP;AACD,CA/GM;AAiHA,MAAMK,iBAAiB,GAAG,CAAC;AAAEvJ,EAAAA;AAAF,CAAD,KAC/BmC,sBAAE,CAAC4E,UAAH,CAAc/G,IAAd,CADK;AAGP;;AACO,MAAMwJ,YAAY,GAAI9D,MAAD,KAA0C;AACpE,GAAC/G,IAAI,CAACC,qBAAN,GAA8BuI,yBADsC;AAEpE,GAACxI,IAAI,CAACI,aAAN,GAAsBwI,iBAAiB,CAACkC,IAAlB,CAAuBC,SAAvB,EAAkChE,MAAlC,CAF8C;AAGpE,GAAC/G,IAAI,CAACK,aAAN,GAAsBuK,iBAH8C;AAIpE,GAAC5K,IAAI,CAACG,YAAN,GAAqB2I,gBAJ+C;AAKpE,GAAC9I,IAAI,CAACE,aAAN,GAAsBiJ,iBAL8C;AAMpE,GAACnJ,IAAI,CAACM,sBAAN,GAA+BmH,uBAAuB,CAACV,MAAD;AANc,CAA1C,CAArB;AAQP;;AC/LA;;AACA,MAAMiE,0BAA0B,GAAIC,EAAD;AACjC;AACAA,EAAAA,EAAE,CAAC,uBAAD,EAA0B,CAACC,OAAD,EAAUC,aAAV;AAC1B,QAAID,OAAO,CAAC3H,IAAR,KAAiB,QAAjB,IAA6B2H,OAAO,CAAC3H,IAAR,KAAiB,UAAlD,EAA8D;AAC5D4H,MAAAA,aAAa,CAACC,IAAd,CAAmBd,IAAnB,CAAwB,+BAAxB;AACAa,MAAAA,aAAa,CAACC,IAAd,CAAmBd,IAAnB,CAAwB,sBAAxB;AACD,KAHD,MAGO,IAAIY,OAAO,CAAC3H,IAAR,KAAiB,UAAjB,IAA+B2H,OAAO,CAACG,QAA3C,EAAqD;AAC1D;AACAC,MAAAA,OAAO,CAACC,GAAR,CACE,qJADF;AAGD;AACF,GAVC,CAAF;AAWD,CAbD;AAcA;;;MAEaC,UAAU,GAAG,CACxBP,EADwB,EAExBlE,MAFwB;AAIxB;AACA,MAAIA,MAAM,CAAC8B,GAAP,CAAW,8CAAX,MAA+D,KAAnE,EAA0E;AACxEmC,IAAAA,0BAA0B,CAACC,EAAD,CAA1B;AACD;AACD;;;AACAA,EAAAA,EAAE,CAAC,MAAD,EAASJ,YAAY,CAAC9D,MAAD,CAArB,CAAF;AACAkE,EAAAA,EAAE,CAAC,kBAAD,EAAqBxD,uBAAuB,CAACV,MAAD,CAA5C,CAAF;AACD;;;;"} \ No newline at end of file +{"version":3,"file":"plugins.js","sources":["../src/constants.ts","../node_modules/truncate-utf8-bytes/lib/truncate.js","../node_modules/truncate-utf8-bytes/index.js","../node_modules/sanitize-filename/index.js","../src/screenshotPath.utils.ts","../src/image.utils.ts","../src/afterScreenshot.hook.ts","../src/task.hook.ts","../src/plugins.ts"],"sourcesContent":["const PLUGIN_NAME = \"cp-visual-regression-diff\";\nexport const LINK_PREFIX = `#${PLUGIN_NAME}-`;\nexport const OVERLAY_CLASS = `${PLUGIN_NAME}-overlay`;\nexport const IMAGE_SNAPSHOT_PREFIX = `__${PLUGIN_NAME}_snapshots__`;\n\nexport enum FILE_SUFFIX {\n diff = \".diff\",\n actual = \".actual\",\n}\n\nexport const TASK = {\n getScreenshotPathInfo: `${PLUGIN_NAME}-getScreenshotPathInfo`,\n compareImages: `${PLUGIN_NAME}-compareImages`,\n approveImage: `${PLUGIN_NAME}-approveImage`,\n cleanupImages: `${PLUGIN_NAME}-cleanupImages`,\n doesFileExist: `${PLUGIN_NAME}-doesFileExist`,\n runAfterScreenshotHook: `${PLUGIN_NAME}-runAfterScreenshotHook`,\n /* c8 ignore next */\n};\n\nexport const PATH_VARIABLES = {\n specPath: \"{spec_path}\",\n unixSystemRootPath: \"{unix_system_root_path}\",\n winSystemRootPath: \"{win_system_root_path}\",\n} as const;\n\nexport const WINDOWS_LIKE_DRIVE_REGEX = /^[A-Z]:$/;\n\nexport const METADATA_KEY = \"FRSOURCE_CPVRD_V\";\n","'use strict';\n\nfunction isHighSurrogate(codePoint) {\n return codePoint >= 0xd800 && codePoint <= 0xdbff;\n}\n\nfunction isLowSurrogate(codePoint) {\n return codePoint >= 0xdc00 && codePoint <= 0xdfff;\n}\n\n// Truncate string by size in bytes\nmodule.exports = function truncate(getLength, string, byteLength) {\n if (typeof string !== \"string\") {\n throw new Error(\"Input must be string\");\n }\n\n var charLength = string.length;\n var curByteLength = 0;\n var codePoint;\n var segment;\n\n for (var i = 0; i < charLength; i += 1) {\n codePoint = string.charCodeAt(i);\n segment = string[i];\n\n if (isHighSurrogate(codePoint) && isLowSurrogate(string.charCodeAt(i + 1))) {\n i += 1;\n segment += string[i];\n }\n\n curByteLength += getLength(segment);\n\n if (curByteLength === byteLength) {\n return string.slice(0, i + 1);\n }\n else if (curByteLength > byteLength) {\n return string.slice(0, i - segment.length + 1);\n }\n }\n\n return string;\n};\n\n","'use strict';\n\nvar truncate = require(\"./lib/truncate\");\nvar getLength = Buffer.byteLength.bind(Buffer);\nmodule.exports = truncate.bind(null, getLength);\n","/*jshint node:true*/\n'use strict';\n\n/**\n * Replaces characters in strings that are illegal/unsafe for filenames.\n * Unsafe characters are either removed or replaced by a substitute set\n * in the optional `options` object.\n *\n * Illegal Characters on Various Operating Systems\n * / ? < > \\ : * | \"\n * https://kb.acronis.com/content/39790\n *\n * Unicode Control codes\n * C0 0x00-0x1f & C1 (0x80-0x9f)\n * http://en.wikipedia.org/wiki/C0_and_C1_control_codes\n *\n * Reserved filenames on Unix-based systems (\".\", \"..\")\n * Reserved filenames in Windows (\"CON\", \"PRN\", \"AUX\", \"NUL\", \"COM1\",\n * \"COM2\", \"COM3\", \"COM4\", \"COM5\", \"COM6\", \"COM7\", \"COM8\", \"COM9\",\n * \"LPT1\", \"LPT2\", \"LPT3\", \"LPT4\", \"LPT5\", \"LPT6\", \"LPT7\", \"LPT8\", and\n * \"LPT9\") case-insesitively and with or without filename extensions.\n *\n * Capped at 255 characters in length.\n * http://unix.stackexchange.com/questions/32795/what-is-the-maximum-allowed-filename-and-folder-size-with-ecryptfs\n *\n * @param {String} input Original filename\n * @param {Object} options {replacement: String | Function }\n * @return {String} Sanitized filename\n */\n\nvar truncate = require(\"truncate-utf8-bytes\");\n\nvar illegalRe = /[\\/\\?<>\\\\:\\*\\|\"]/g;\nvar controlRe = /[\\x00-\\x1f\\x80-\\x9f]/g;\nvar reservedRe = /^\\.+$/;\nvar windowsReservedRe = /^(con|prn|aux|nul|com[0-9]|lpt[0-9])(\\..*)?$/i;\nvar windowsTrailingRe = /[\\. ]+$/;\n\nfunction sanitize(input, replacement) {\n if (typeof input !== 'string') {\n throw new Error('Input must be string');\n }\n var sanitized = input\n .replace(illegalRe, replacement)\n .replace(controlRe, replacement)\n .replace(reservedRe, replacement)\n .replace(windowsReservedRe, replacement)\n .replace(windowsTrailingRe, replacement);\n return truncate(sanitized, 255);\n}\n\nmodule.exports = function (input, options) {\n var replacement = (options && options.replacement) || '';\n var output = sanitize(input, replacement);\n if (replacement === '') {\n return output;\n }\n return sanitize(output, '');\n};\n","import path from \"path\";\nimport {\n FILE_SUFFIX,\n IMAGE_SNAPSHOT_PREFIX,\n PATH_VARIABLES,\n WINDOWS_LIKE_DRIVE_REGEX,\n} from \"./constants\";\nimport sanitize from \"sanitize-filename\";\n\nconst nameCacheCounter: Record = {};\n\nexport const generateScreenshotPath = ({\n titleFromOptions,\n imagesPath,\n specPath,\n currentRetryNumber,\n}: {\n titleFromOptions: string;\n imagesPath: string;\n specPath: string;\n currentRetryNumber: number;\n}) => {\n const parsePathPartVariables = (pathPart: string, i: number) => {\n if (pathPart === PATH_VARIABLES.specPath) {\n return path.dirname(specPath);\n } else if (i === 0 && !pathPart) {\n // when unix-like absolute path\n return PATH_VARIABLES.unixSystemRootPath;\n } else if (i === 0 && WINDOWS_LIKE_DRIVE_REGEX.test(pathPart)) {\n // when win-like absolute path\n return path.join(PATH_VARIABLES.winSystemRootPath, pathPart[0]);\n }\n\n return pathPart;\n };\n\n const screenshotPath = path.join(\n ...imagesPath.split(\"/\").map(parsePathPartVariables),\n sanitize(titleFromOptions)\n );\n\n if (typeof nameCacheCounter[screenshotPath] === \"undefined\") {\n nameCacheCounter[screenshotPath] = -1;\n }\n\n // it's a retry of the same image, so let's decrease the counter\n if (currentRetryNumber > 0) {\n --nameCacheCounter[screenshotPath];\n }\n return path.join(\n IMAGE_SNAPSHOT_PREFIX,\n `${screenshotPath} #${++nameCacheCounter[screenshotPath]}${\n FILE_SUFFIX.actual\n }.png`\n );\n};\n\nconst screenshotPathRegex = new RegExp(\n `^([\\\\s\\\\S]+?) #([0-9]+)(?:(?:\\\\${FILE_SUFFIX.diff})|(?:\\\\${FILE_SUFFIX.actual}))?\\\\.(?:png|PNG)$`\n);\nexport const wasScreenshotUsed = (imagePath: string) => {\n const matched = imagePath.match(screenshotPathRegex);\n /* c8 ignore next */ if (!matched) return false;\n const [, screenshotPath, numString] = matched;\n const num = parseInt(numString);\n /* c8 ignore next */ if (!screenshotPath || isNaN(num)) return false;\n return (\n screenshotPath in nameCacheCounter &&\n num <= nameCacheCounter[screenshotPath]\n );\n};\n\nexport const resetScreenshotNameCache = () => {\n Object.keys(nameCacheCounter).forEach((k) => delete nameCacheCounter[k]);\n};\n","import path from \"path\";\nimport fs from \"fs\";\nimport { PNG, PNGWithMetadata } from \"pngjs\";\nimport sharp from \"sharp\";\nimport { addMetadata, getMetadata } from \"meta-png\";\nimport glob from \"glob\";\nimport { version } from \"../package.json\";\nimport { wasScreenshotUsed } from \"./screenshotPath.utils\";\nimport { METADATA_KEY } from \"./constants\";\n\nexport const addPNGMetadata = (png: Buffer) =>\n addMetadata(png, METADATA_KEY, version /* c8 ignore next */);\nexport const getPNGMetadata = (png: Buffer) =>\n getMetadata(png, METADATA_KEY /* c8 ignore next */);\nexport const isImageCurrentVersion = (png: Buffer) =>\n getPNGMetadata(png) === version;\nexport const isImageGeneratedByPlugin = (png: Buffer) =>\n !!getPNGMetadata(png /* c8 ignore next */);\n\nexport const writePNG = (name: string, png: PNG | Buffer) =>\n fs.writeFileSync(\n name,\n addPNGMetadata(png instanceof PNG ? PNG.sync.write(png) : png)\n );\n\nconst inArea = (x: number, y: number, height: number, width: number) =>\n y > height || x > width;\n\nexport const fillSizeDifference = (\n image: PNG,\n width: number,\n height: number\n) => {\n for (let y = 0; y < image.height; y++) {\n for (let x = 0; x < image.width; x++) {\n if (inArea(x, y, height, width)) {\n const idx = (image.width * y + x) << 2;\n image.data[idx] = 0;\n image.data[idx + 1] = 0;\n image.data[idx + 2] = 0;\n image.data[idx + 3] = 64;\n }\n }\n }\n return image;\n /* c8 ignore next */\n};\n\nexport const createImageResizer =\n (width: number, height: number) => (source: PNG) => {\n const resized = new PNG({ width, height, fill: true });\n PNG.bitblt(source, resized, 0, 0, source.width, source.height, 0, 0);\n return resized;\n /* c8 ignore next */\n };\n\nexport const scaleImageAndWrite = async ({\n scaleFactor,\n path,\n}: {\n scaleFactor: number;\n path: string;\n}) => {\n const imgBuffer = fs.readFileSync(path);\n if (scaleFactor === 1) return imgBuffer;\n\n const rawImgNew = PNG.sync.read(imgBuffer);\n const newImageWidth = Math.ceil(rawImgNew.width * scaleFactor);\n const newImageHeight = Math.ceil(rawImgNew.height * scaleFactor);\n await sharp(imgBuffer).resize(newImageWidth, newImageHeight).toFile(path);\n\n return fs.readFileSync(path);\n};\n\nexport const alignImagesToSameSize = (\n firstImage: PNGWithMetadata,\n secondImage: PNGWithMetadata\n) => {\n const firstImageWidth = firstImage.width;\n const firstImageHeight = firstImage.height;\n const secondImageWidth = secondImage.width;\n const secondImageHeight = secondImage.height;\n\n const resizeToSameSize = createImageResizer(\n Math.max(firstImageWidth, secondImageWidth),\n Math.max(firstImageHeight, secondImageHeight)\n );\n\n const resizedFirst = resizeToSameSize(firstImage);\n const resizedSecond = resizeToSameSize(secondImage);\n\n return [\n fillSizeDifference(resizedFirst, firstImageWidth, firstImageHeight),\n fillSizeDifference(resizedSecond, secondImageWidth, secondImageHeight),\n ];\n};\n\nexport const cleanupUnused = (rootPath: string) => {\n glob\n .sync(\"**/*.png\", {\n cwd: rootPath,\n ignore: \"node_modules/**/*\",\n })\n .forEach((pngPath) => {\n const absolutePath = path.join(rootPath, pngPath);\n if (\n !wasScreenshotUsed(pngPath) &&\n isImageGeneratedByPlugin(fs.readFileSync(absolutePath))\n ) {\n fs.unlinkSync(absolutePath);\n }\n });\n};\n","import path from \"path\";\nimport { promises as fs } from \"fs\";\nimport moveFile from \"move-file\";\nimport { IMAGE_SNAPSHOT_PREFIX, PATH_VARIABLES } from \"./constants\";\n\ntype NotFalsy = T extends false | null | undefined ? never : T;\n\nconst MIMIC_ROOT_WIN_REGEX = new RegExp(\n `^${PATH_VARIABLES.winSystemRootPath}\\\\${path.sep}([A-Z])\\\\${path.sep}`\n);\nconst MIMIC_ROOT_UNIX_REGEX = new RegExp(\n `^${PATH_VARIABLES.unixSystemRootPath}\\\\${path.sep}`\n);\n\nconst getConfigVariableOrThrow = (\n config: Cypress.PluginConfigOptions,\n name: K\n) => {\n if (config[name]) {\n return config[name] as NotFalsy;\n }\n\n /* c8 ignore start */\n throw `[@frsource/cypress-plugin-visual-regression-diff] CypressConfig.${name} cannot be missing or \\`false\\`!`;\n};\n/* c8 ignore stop */\n\nexport const parseAbsolutePath = ({\n screenshotPath,\n projectRoot,\n}: {\n screenshotPath: string;\n projectRoot: string;\n}) => {\n let newAbsolutePath: string;\n const matchedMimicingWinRoot = screenshotPath.match(MIMIC_ROOT_WIN_REGEX);\n const matchedMimicingUnixRoot = screenshotPath.match(MIMIC_ROOT_UNIX_REGEX);\n if (matchedMimicingWinRoot && matchedMimicingWinRoot[1]) {\n const driveLetter = matchedMimicingWinRoot[1];\n newAbsolutePath = path.join(\n `${driveLetter}:\\\\`,\n screenshotPath.substring(matchedMimicingWinRoot[0].length)\n );\n } else if (matchedMimicingUnixRoot) {\n newAbsolutePath =\n path.sep + screenshotPath.substring(matchedMimicingUnixRoot[0].length);\n } else {\n newAbsolutePath = path.join(projectRoot, screenshotPath);\n }\n return path.normalize(newAbsolutePath);\n};\n\nexport const initAfterScreenshotHook =\n (config: Cypress.PluginConfigOptions) =>\n (\n details: Cypress.ScreenshotDetails\n ):\n | void\n | Cypress.AfterScreenshotReturnObject\n | Promise => {\n // it's not a screenshot generated by FRSOURCE Cypress Plugin Visual Regression Diff\n /* c8 ignore start */\n if (details.name?.indexOf(IMAGE_SNAPSHOT_PREFIX) !== 0) return;\n /* c8 ignore stop */\n const screenshotsFolder = getConfigVariableOrThrow(\n config,\n \"screenshotsFolder\"\n );\n const screenshotPath = details.name.substring(\n IMAGE_SNAPSHOT_PREFIX.length + path.sep.length\n );\n const newAbsolutePath = parseAbsolutePath({\n screenshotPath,\n projectRoot: config.projectRoot,\n });\n\n return (async () => {\n await moveFile(details.path, newAbsolutePath);\n await fs.rm(path.join(screenshotsFolder, IMAGE_SNAPSHOT_PREFIX), {\n recursive: true,\n force: true,\n });\n\n return { path: newAbsolutePath };\n })();\n };\n","import fs from \"fs\";\nimport { PNG } from \"pngjs\";\nimport pixelmatch, { PixelmatchOptions } from \"pixelmatch\";\nimport moveFile from \"move-file\";\nimport path from \"path\";\nimport { FILE_SUFFIX, TASK } from \"./constants\";\nimport {\n cleanupUnused,\n alignImagesToSameSize,\n scaleImageAndWrite,\n isImageCurrentVersion,\n writePNG,\n} from \"./image.utils\";\nimport {\n generateScreenshotPath,\n resetScreenshotNameCache,\n} from \"./screenshotPath.utils\";\nimport type { CompareImagesTaskReturn } from \"./types\";\nimport { initAfterScreenshotHook } from \"./afterScreenshot.hook\";\n\nexport type CompareImagesCfg = {\n scaleFactor: number;\n title: string;\n imgNew: string;\n imgOld: string;\n updateImages: boolean;\n maxDiffThreshold: number;\n diffConfig: PixelmatchOptions;\n};\n\nconst round = (n: number) => Math.ceil(n * 1000) / 1000;\n\nconst unlinkSyncSafe = (path: string) =>\n fs.existsSync(path) && fs.unlinkSync(path);\nconst moveSyncSafe = (pathFrom: string, pathTo: string) =>\n fs.existsSync(pathFrom) && moveFile.sync(pathFrom, pathTo);\n\nexport const getScreenshotPathInfoTask = (cfg: {\n titleFromOptions: string;\n imagesPath: string;\n specPath: string;\n currentRetryNumber: number;\n}) => {\n const screenshotPath = generateScreenshotPath(cfg);\n\n return { screenshotPath, title: path.basename(screenshotPath, \".png\") };\n};\n\nexport const cleanupImagesTask = (config: Cypress.PluginConfigOptions) => {\n if (config.env[\"pluginVisualRegressionCleanupUnusedImages\"]) {\n cleanupUnused(config.projectRoot);\n }\n\n resetScreenshotNameCache();\n\n return null;\n};\n\nexport const approveImageTask = ({ img }: { img: string }) => {\n const oldImg = img.replace(FILE_SUFFIX.actual, \"\");\n unlinkSyncSafe(oldImg);\n\n const diffImg = img.replace(FILE_SUFFIX.actual, FILE_SUFFIX.diff);\n unlinkSyncSafe(diffImg);\n\n moveSyncSafe(img, oldImg);\n\n return null;\n};\n\nexport const compareImagesTask = async (\n cfg: CompareImagesCfg\n): Promise => {\n const messages = [] as string[];\n const rawImgNewBuffer = await scaleImageAndWrite({\n scaleFactor: cfg.scaleFactor,\n path: cfg.imgNew,\n });\n let imgDiff: number | undefined;\n let imgNewBase64: string, imgOldBase64: string, imgDiffBase64: string;\n let error = false;\n\n if (fs.existsSync(cfg.imgOld) && !cfg.updateImages) {\n const rawImgNew = PNG.sync.read(rawImgNewBuffer);\n const rawImgOldBuffer = fs.readFileSync(cfg.imgOld);\n const rawImgOld = PNG.sync.read(rawImgOldBuffer);\n const isImgSizeDifferent =\n rawImgNew.height !== rawImgOld.height ||\n rawImgNew.width !== rawImgOld.width;\n\n const [imgNew, imgOld] = isImgSizeDifferent\n ? alignImagesToSameSize(rawImgNew, rawImgOld)\n : [rawImgNew, rawImgOld];\n\n const { width, height } = imgNew;\n const diff = new PNG({ width, height });\n const diffConfig = Object.assign({ includeAA: true }, cfg.diffConfig);\n\n const diffPixels = pixelmatch(\n imgNew.data,\n imgOld.data,\n diff.data,\n width,\n height,\n diffConfig\n );\n imgDiff = diffPixels / (width * height);\n\n if (isImgSizeDifferent) {\n messages.push(\n `Warning: Images size mismatch - new screenshot is ${rawImgNew.width}px by ${rawImgNew.height}px while old one is ${rawImgOld.width}px by ${rawImgOld.height} (width x height).`\n );\n }\n\n if (imgDiff > cfg.maxDiffThreshold) {\n messages.unshift(\n `Image diff factor (${round(\n imgDiff\n )}%) is bigger than maximum threshold option ${cfg.maxDiffThreshold}.`\n );\n error = true;\n }\n\n const diffBuffer = PNG.sync.write(diff);\n imgNewBase64 = PNG.sync.write(imgNew).toString(\"base64\");\n imgDiffBase64 = diffBuffer.toString(\"base64\");\n imgOldBase64 = PNG.sync.write(imgOld).toString(\"base64\");\n\n if (error) {\n writePNG(\n cfg.imgNew.replace(FILE_SUFFIX.actual, FILE_SUFFIX.diff),\n diffBuffer\n );\n return {\n error,\n message: messages.join(\"\\n\"),\n imgDiff,\n imgNewBase64,\n imgDiffBase64,\n imgOldBase64,\n maxDiffThreshold: cfg.maxDiffThreshold,\n };\n } else {\n if (rawImgOld && !isImageCurrentVersion(rawImgOldBuffer)) {\n writePNG(cfg.imgNew, rawImgNewBuffer);\n moveFile.sync(cfg.imgNew, cfg.imgOld);\n } else {\n // don't overwrite file if it's the same (imgDiff < cfg.maxDiffThreshold && !isImgSizeDifferent)\n fs.unlinkSync(cfg.imgNew);\n }\n }\n } else {\n // there is no \"old screenshot\" or screenshots should be immediately updated\n imgDiff = 0;\n imgNewBase64 = \"\";\n imgDiffBase64 = \"\";\n imgOldBase64 = \"\";\n writePNG(cfg.imgNew, rawImgNewBuffer);\n moveFile.sync(cfg.imgNew, cfg.imgOld);\n }\n\n if (typeof imgDiff !== \"undefined\") {\n messages.unshift(\n `Image diff factor (${round(\n imgDiff\n )}%) is within boundaries of maximum threshold option ${\n cfg.maxDiffThreshold\n }.`\n );\n return {\n message: messages.join(\"\\n\"),\n imgDiff,\n imgNewBase64,\n imgDiffBase64,\n imgOldBase64,\n maxDiffThreshold: cfg.maxDiffThreshold,\n };\n }\n\n /* c8 ignore next */\n return null;\n};\n\nexport const doesFileExistTask = ({ path }: { path: string }) =>\n fs.existsSync(path);\n\n/* c8 ignore start */\nexport const initTaskHook = (config: Cypress.PluginConfigOptions) => ({\n [TASK.getScreenshotPathInfo]: getScreenshotPathInfoTask,\n [TASK.cleanupImages]: cleanupImagesTask.bind(undefined, config),\n [TASK.doesFileExist]: doesFileExistTask,\n [TASK.approveImage]: approveImageTask,\n [TASK.compareImages]: compareImagesTask,\n [TASK.runAfterScreenshotHook]: initAfterScreenshotHook(config),\n});\n/* c8 ignore stop */\n","import { initTaskHook } from \"./task.hook\";\nimport { initAfterScreenshotHook } from \"./afterScreenshot.hook\";\n\n/* c8 ignore start */\nconst initForceDeviceScaleFactor = (on: Cypress.PluginEvents) => {\n // based on https://github.com/cypress-io/cypress/issues/2102#issuecomment-521299946\n on(\"before:browser:launch\", (browser, launchOptions) => {\n if (browser.name === \"chrome\" || browser.name === \"chromium\") {\n launchOptions.args.push(\"--force-device-scale-factor=1\");\n launchOptions.args.push(\"--high-dpi-support=1\");\n } else if (browser.name === \"electron\" && browser.isHeaded) {\n // eslint-disable-next-line no-console\n console.log(\n \"There isn't currently a way of setting the device scale factor in Cypress when running headed electron so we disable the image regression commands.\"\n );\n }\n });\n};\n/* c8 ignore stop */\n\nexport const initPlugin = (\n on: Cypress.PluginEvents,\n config: Cypress.PluginConfigOptions\n) => {\n /* c8 ignore start */\n if (config.env[\"pluginVisualRegressionForceDeviceScaleFactor\"] !== false) {\n initForceDeviceScaleFactor(on);\n }\n /* c8 ignore stop */\n on(\"task\", initTaskHook(config));\n on(\"after:screenshot\", initAfterScreenshotHook(config));\n};\n"],"names":["PLUGIN_NAME","IMAGE_SNAPSHOT_PREFIX","FILE_SUFFIX","TASK","getScreenshotPathInfo","compareImages","approveImage","cleanupImages","doesFileExist","runAfterScreenshotHook","PATH_VARIABLES","specPath","unixSystemRootPath","winSystemRootPath","WINDOWS_LIKE_DRIVE_REGEX","METADATA_KEY","truncate","nameCacheCounter","generateScreenshotPath","titleFromOptions","imagesPath","currentRetryNumber","parsePathPartVariables","pathPart","i","path","dirname","test","join","screenshotPath","split","map","sanitize","actual","screenshotPathRegex","RegExp","diff","wasScreenshotUsed","imagePath","matched","match","numString","num","parseInt","isNaN","resetScreenshotNameCache","Object","keys","forEach","k","addPNGMetadata","png","addMetadata","version","getPNGMetadata","getMetadata","isImageCurrentVersion","isImageGeneratedByPlugin","writePNG","name","fs","writeFileSync","PNG","sync","write","inArea","x","y","height","width","fillSizeDifference","image","idx","data","createImageResizer","source","resized","fill","bitblt","scaleImageAndWrite","scaleFactor","imgBuffer","readFileSync","rawImgNew","read","newImageWidth","Math","ceil","newImageHeight","sharp","resize","toFile","alignImagesToSameSize","firstImage","secondImage","firstImageWidth","firstImageHeight","secondImageWidth","secondImageHeight","resizeToSameSize","max","resizedFirst","resizedSecond","cleanupUnused","rootPath","glob","cwd","ignore","pngPath","absolutePath","unlinkSync","MIMIC_ROOT_WIN_REGEX","sep","MIMIC_ROOT_UNIX_REGEX","getConfigVariableOrThrow","config","parseAbsolutePath","projectRoot","newAbsolutePath","matchedMimicingWinRoot","matchedMimicingUnixRoot","driveLetter","substring","length","normalize","initAfterScreenshotHook","details","indexOf","screenshotsFolder","moveFile","rm","recursive","force","round","n","unlinkSyncSafe","existsSync","moveSyncSafe","pathFrom","pathTo","getScreenshotPathInfoTask","cfg","title","basename","cleanupImagesTask","env","approveImageTask","img","oldImg","replace","diffImg","compareImagesTask","messages","rawImgNewBuffer","imgNew","imgDiff","imgNewBase64","imgOldBase64","imgDiffBase64","error","imgOld","updateImages","rawImgOldBuffer","rawImgOld","isImgSizeDifferent","diffConfig","assign","includeAA","diffPixels","pixelmatch","push","maxDiffThreshold","unshift","diffBuffer","toString","message","doesFileExistTask","initTaskHook","bind","undefined","initForceDeviceScaleFactor","on","browser","launchOptions","args","isHeaded","console","log","initPlugin"],"mappings":"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"} \ No newline at end of file diff --git a/dist/plugins.mjs b/dist/plugins.mjs index d593a33c..6b7f6569 100644 --- a/dist/plugins.mjs +++ b/dist/plugins.mjs @@ -34,7 +34,7 @@ const PATH_VARIABLES = { const WINDOWS_LIKE_DRIVE_REGEX = /^[A-Z]:$/; const METADATA_KEY = "FRSOURCE_CPVRD_V"; -var version = "3.0.1"; +var version = "3.1.0"; function isHighSurrogate(codePoint) { return codePoint >= 0xd800 && codePoint <= 0xdbff; @@ -143,7 +143,8 @@ const nameCacheCounter = {}; const generateScreenshotPath = ({ titleFromOptions, imagesPath, - specPath + specPath, + currentRetryNumber }) => { const parsePathPartVariables = (pathPart, i) => { if (pathPart === PATH_VARIABLES.specPath) { @@ -163,6 +164,11 @@ const generateScreenshotPath = ({ if (typeof nameCacheCounter[screenshotPath] === "undefined") { nameCacheCounter[screenshotPath] = -1; + } // it's a retry of the same image, so let's decrease the counter + + + if (currentRetryNumber > 0) { + --nameCacheCounter[screenshotPath]; } return path.join(IMAGE_SNAPSHOT_PREFIX, `${screenshotPath} #${++nameCacheCounter[screenshotPath]}${FILE_SUFFIX.actual}.png`); diff --git a/dist/plugins.mjs.map b/dist/plugins.mjs.map index e7a8b77a..7fe1d44d 100644 --- a/dist/plugins.mjs.map +++ b/dist/plugins.mjs.map @@ -1 +1 @@ -{"version":3,"file":"plugins.mjs","sources":["../src/constants.ts","../node_modules/truncate-utf8-bytes/lib/truncate.js","../node_modules/truncate-utf8-bytes/index.js","../node_modules/sanitize-filename/index.js","../src/screenshotPath.utils.ts","../src/image.utils.ts","../src/afterScreenshot.hook.ts","../src/task.hook.ts","../src/plugins.ts"],"sourcesContent":["const PLUGIN_NAME = \"cp-visual-regression-diff\";\nexport const LINK_PREFIX = `#${PLUGIN_NAME}-`;\nexport const OVERLAY_CLASS = `${PLUGIN_NAME}-overlay`;\nexport const IMAGE_SNAPSHOT_PREFIX = `__${PLUGIN_NAME}_snapshots__`;\n\nexport enum FILE_SUFFIX {\n diff = \".diff\",\n actual = \".actual\",\n}\n\nexport const TASK = {\n getScreenshotPathInfo: `${PLUGIN_NAME}-getScreenshotPathInfo`,\n compareImages: `${PLUGIN_NAME}-compareImages`,\n approveImage: `${PLUGIN_NAME}-approveImage`,\n cleanupImages: `${PLUGIN_NAME}-cleanupImages`,\n doesFileExist: `${PLUGIN_NAME}-doesFileExist`,\n runAfterScreenshotHook: `${PLUGIN_NAME}-runAfterScreenshotHook`,\n /* c8 ignore next */\n};\n\nexport const PATH_VARIABLES = {\n specPath: \"{spec_path}\",\n unixSystemRootPath: \"{unix_system_root_path}\",\n winSystemRootPath: \"{win_system_root_path}\",\n} as const;\n\nexport const WINDOWS_LIKE_DRIVE_REGEX = /^[A-Z]:$/;\n\nexport const METADATA_KEY = \"FRSOURCE_CPVRD_V\";\n","'use strict';\n\nfunction isHighSurrogate(codePoint) {\n return codePoint >= 0xd800 && codePoint <= 0xdbff;\n}\n\nfunction isLowSurrogate(codePoint) {\n return codePoint >= 0xdc00 && codePoint <= 0xdfff;\n}\n\n// Truncate string by size in bytes\nmodule.exports = function truncate(getLength, string, byteLength) {\n if (typeof string !== \"string\") {\n throw new Error(\"Input must be string\");\n }\n\n var charLength = string.length;\n var curByteLength = 0;\n var codePoint;\n var segment;\n\n for (var i = 0; i < charLength; i += 1) {\n codePoint = string.charCodeAt(i);\n segment = string[i];\n\n if (isHighSurrogate(codePoint) && isLowSurrogate(string.charCodeAt(i + 1))) {\n i += 1;\n segment += string[i];\n }\n\n curByteLength += getLength(segment);\n\n if (curByteLength === byteLength) {\n return string.slice(0, i + 1);\n }\n else if (curByteLength > byteLength) {\n return string.slice(0, i - segment.length + 1);\n }\n }\n\n return string;\n};\n\n","'use strict';\n\nvar truncate = require(\"./lib/truncate\");\nvar getLength = Buffer.byteLength.bind(Buffer);\nmodule.exports = truncate.bind(null, getLength);\n","/*jshint node:true*/\n'use strict';\n\n/**\n * Replaces characters in strings that are illegal/unsafe for filenames.\n * Unsafe characters are either removed or replaced by a substitute set\n * in the optional `options` object.\n *\n * Illegal Characters on Various Operating Systems\n * / ? < > \\ : * | \"\n * https://kb.acronis.com/content/39790\n *\n * Unicode Control codes\n * C0 0x00-0x1f & C1 (0x80-0x9f)\n * http://en.wikipedia.org/wiki/C0_and_C1_control_codes\n *\n * Reserved filenames on Unix-based systems (\".\", \"..\")\n * Reserved filenames in Windows (\"CON\", \"PRN\", \"AUX\", \"NUL\", \"COM1\",\n * \"COM2\", \"COM3\", \"COM4\", \"COM5\", \"COM6\", \"COM7\", \"COM8\", \"COM9\",\n * \"LPT1\", \"LPT2\", \"LPT3\", \"LPT4\", \"LPT5\", \"LPT6\", \"LPT7\", \"LPT8\", and\n * \"LPT9\") case-insesitively and with or without filename extensions.\n *\n * Capped at 255 characters in length.\n * http://unix.stackexchange.com/questions/32795/what-is-the-maximum-allowed-filename-and-folder-size-with-ecryptfs\n *\n * @param {String} input Original filename\n * @param {Object} options {replacement: String | Function }\n * @return {String} Sanitized filename\n */\n\nvar truncate = require(\"truncate-utf8-bytes\");\n\nvar illegalRe = /[\\/\\?<>\\\\:\\*\\|\"]/g;\nvar controlRe = /[\\x00-\\x1f\\x80-\\x9f]/g;\nvar reservedRe = /^\\.+$/;\nvar windowsReservedRe = /^(con|prn|aux|nul|com[0-9]|lpt[0-9])(\\..*)?$/i;\nvar windowsTrailingRe = /[\\. ]+$/;\n\nfunction sanitize(input, replacement) {\n if (typeof input !== 'string') {\n throw new Error('Input must be string');\n }\n var sanitized = input\n .replace(illegalRe, replacement)\n .replace(controlRe, replacement)\n .replace(reservedRe, replacement)\n .replace(windowsReservedRe, replacement)\n .replace(windowsTrailingRe, replacement);\n return truncate(sanitized, 255);\n}\n\nmodule.exports = function (input, options) {\n var replacement = (options && options.replacement) || '';\n var output = sanitize(input, replacement);\n if (replacement === '') {\n return output;\n }\n return sanitize(output, '');\n};\n","import path from \"path\";\nimport {\n FILE_SUFFIX,\n IMAGE_SNAPSHOT_PREFIX,\n PATH_VARIABLES,\n WINDOWS_LIKE_DRIVE_REGEX,\n} from \"./constants\";\nimport sanitize from \"sanitize-filename\";\n\nconst nameCacheCounter: Record = {};\n\nexport const generateScreenshotPath = ({\n titleFromOptions,\n imagesPath,\n specPath,\n}: {\n titleFromOptions: string;\n imagesPath: string;\n specPath: string;\n}) => {\n const parsePathPartVariables = (pathPart: string, i: number) => {\n if (pathPart === PATH_VARIABLES.specPath) {\n return path.dirname(specPath);\n } else if (i === 0 && !pathPart) {\n // when unix-like absolute path\n return PATH_VARIABLES.unixSystemRootPath;\n } else if (i === 0 && WINDOWS_LIKE_DRIVE_REGEX.test(pathPart)) {\n // when win-like absolute path\n return path.join(PATH_VARIABLES.winSystemRootPath, pathPart[0]);\n }\n\n return pathPart;\n };\n\n const screenshotPath = path.join(\n ...imagesPath.split(\"/\").map(parsePathPartVariables),\n sanitize(titleFromOptions)\n );\n\n if (typeof nameCacheCounter[screenshotPath] === \"undefined\") {\n nameCacheCounter[screenshotPath] = -1;\n }\n return path.join(\n IMAGE_SNAPSHOT_PREFIX,\n `${screenshotPath} #${++nameCacheCounter[screenshotPath]}${\n FILE_SUFFIX.actual\n }.png`\n );\n};\n\nconst screenshotPathRegex = new RegExp(\n `^([\\\\s\\\\S]+?) #([0-9]+)(?:(?:\\\\${FILE_SUFFIX.diff})|(?:\\\\${FILE_SUFFIX.actual}))?\\\\.(?:png|PNG)$`\n);\nexport const wasScreenshotUsed = (imagePath: string) => {\n const matched = imagePath.match(screenshotPathRegex);\n /* c8 ignore next */ if (!matched) return false;\n const [, screenshotPath, numString] = matched;\n const num = parseInt(numString);\n /* c8 ignore next */ if (!screenshotPath || isNaN(num)) return false;\n return (\n screenshotPath in nameCacheCounter &&\n num <= nameCacheCounter[screenshotPath]\n );\n};\n\nexport const resetScreenshotNameCache = () => {\n Object.keys(nameCacheCounter).forEach((k) => delete nameCacheCounter[k]);\n};\n","import path from \"path\";\nimport fs from \"fs\";\nimport { PNG, PNGWithMetadata } from \"pngjs\";\nimport sharp from \"sharp\";\nimport { addMetadata, getMetadata } from \"meta-png\";\nimport glob from \"glob\";\nimport { version } from \"../package.json\";\nimport { wasScreenshotUsed } from \"./screenshotPath.utils\";\nimport { METADATA_KEY } from \"./constants\";\n\nexport const addPNGMetadata = (png: Buffer) =>\n addMetadata(png, METADATA_KEY, version /* c8 ignore next */);\nexport const getPNGMetadata = (png: Buffer) =>\n getMetadata(png, METADATA_KEY /* c8 ignore next */);\nexport const isImageCurrentVersion = (png: Buffer) =>\n getPNGMetadata(png) === version;\nexport const isImageGeneratedByPlugin = (png: Buffer) =>\n !!getPNGMetadata(png /* c8 ignore next */);\n\nexport const writePNG = (name: string, png: PNG | Buffer) =>\n fs.writeFileSync(\n name,\n addPNGMetadata(png instanceof PNG ? PNG.sync.write(png) : png)\n );\n\nconst inArea = (x: number, y: number, height: number, width: number) =>\n y > height || x > width;\n\nexport const fillSizeDifference = (\n image: PNG,\n width: number,\n height: number\n) => {\n for (let y = 0; y < image.height; y++) {\n for (let x = 0; x < image.width; x++) {\n if (inArea(x, y, height, width)) {\n const idx = (image.width * y + x) << 2;\n image.data[idx] = 0;\n image.data[idx + 1] = 0;\n image.data[idx + 2] = 0;\n image.data[idx + 3] = 64;\n }\n }\n }\n return image;\n /* c8 ignore next */\n};\n\nexport const createImageResizer =\n (width: number, height: number) => (source: PNG) => {\n const resized = new PNG({ width, height, fill: true });\n PNG.bitblt(source, resized, 0, 0, source.width, source.height, 0, 0);\n return resized;\n /* c8 ignore next */\n };\n\nexport const scaleImageAndWrite = async ({\n scaleFactor,\n path,\n}: {\n scaleFactor: number;\n path: string;\n}) => {\n const imgBuffer = fs.readFileSync(path);\n if (scaleFactor === 1) return imgBuffer;\n\n const rawImgNew = PNG.sync.read(imgBuffer);\n const newImageWidth = Math.ceil(rawImgNew.width * scaleFactor);\n const newImageHeight = Math.ceil(rawImgNew.height * scaleFactor);\n await sharp(imgBuffer).resize(newImageWidth, newImageHeight).toFile(path);\n\n return fs.readFileSync(path);\n};\n\nexport const alignImagesToSameSize = (\n firstImage: PNGWithMetadata,\n secondImage: PNGWithMetadata\n) => {\n const firstImageWidth = firstImage.width;\n const firstImageHeight = firstImage.height;\n const secondImageWidth = secondImage.width;\n const secondImageHeight = secondImage.height;\n\n const resizeToSameSize = createImageResizer(\n Math.max(firstImageWidth, secondImageWidth),\n Math.max(firstImageHeight, secondImageHeight)\n );\n\n const resizedFirst = resizeToSameSize(firstImage);\n const resizedSecond = resizeToSameSize(secondImage);\n\n return [\n fillSizeDifference(resizedFirst, firstImageWidth, firstImageHeight),\n fillSizeDifference(resizedSecond, secondImageWidth, secondImageHeight),\n ];\n};\n\nexport const cleanupUnused = (rootPath: string) => {\n glob\n .sync(\"**/*.png\", {\n cwd: rootPath,\n ignore: \"node_modules/**/*\",\n })\n .forEach((pngPath) => {\n const absolutePath = path.join(rootPath, pngPath);\n if (\n !wasScreenshotUsed(pngPath) &&\n isImageGeneratedByPlugin(fs.readFileSync(absolutePath))\n ) {\n fs.unlinkSync(absolutePath);\n }\n });\n};\n","import path from \"path\";\nimport { promises as fs } from \"fs\";\nimport moveFile from \"move-file\";\nimport { IMAGE_SNAPSHOT_PREFIX, PATH_VARIABLES } from \"./constants\";\n\ntype NotFalsy = T extends false | null | undefined ? never : T;\n\nconst MIMIC_ROOT_WIN_REGEX = new RegExp(\n `^${PATH_VARIABLES.winSystemRootPath}\\\\${path.sep}([A-Z])\\\\${path.sep}`\n);\nconst MIMIC_ROOT_UNIX_REGEX = new RegExp(\n `^${PATH_VARIABLES.unixSystemRootPath}\\\\${path.sep}`\n);\n\nconst getConfigVariableOrThrow = (\n config: Cypress.PluginConfigOptions,\n name: K\n) => {\n if (config[name]) {\n return config[name] as NotFalsy;\n }\n\n /* c8 ignore start */\n throw `[@frsource/cypress-plugin-visual-regression-diff] CypressConfig.${name} cannot be missing or \\`false\\`!`;\n};\n/* c8 ignore stop */\n\nexport const parseAbsolutePath = ({\n screenshotPath,\n projectRoot,\n}: {\n screenshotPath: string;\n projectRoot: string;\n}) => {\n let newAbsolutePath: string;\n const matchedMimicingWinRoot = screenshotPath.match(MIMIC_ROOT_WIN_REGEX);\n const matchedMimicingUnixRoot = screenshotPath.match(MIMIC_ROOT_UNIX_REGEX);\n if (matchedMimicingWinRoot && matchedMimicingWinRoot[1]) {\n const driveLetter = matchedMimicingWinRoot[1];\n newAbsolutePath = path.join(\n `${driveLetter}:\\\\`,\n screenshotPath.substring(matchedMimicingWinRoot[0].length)\n );\n } else if (matchedMimicingUnixRoot) {\n newAbsolutePath =\n path.sep + screenshotPath.substring(matchedMimicingUnixRoot[0].length);\n } else {\n newAbsolutePath = path.join(projectRoot, screenshotPath);\n }\n return path.normalize(newAbsolutePath);\n};\n\nexport const initAfterScreenshotHook =\n (config: Cypress.PluginConfigOptions) =>\n (\n details: Cypress.ScreenshotDetails\n ):\n | void\n | Cypress.AfterScreenshotReturnObject\n | Promise => {\n // it's not a screenshot generated by FRSOURCE Cypress Plugin Visual Regression Diff\n /* c8 ignore start */\n if (details.name?.indexOf(IMAGE_SNAPSHOT_PREFIX) !== 0) return;\n /* c8 ignore stop */\n const screenshotsFolder = getConfigVariableOrThrow(\n config,\n \"screenshotsFolder\"\n );\n const screenshotPath = details.name.substring(\n IMAGE_SNAPSHOT_PREFIX.length + path.sep.length\n );\n const newAbsolutePath = parseAbsolutePath({\n screenshotPath,\n projectRoot: config.projectRoot,\n });\n\n return (async () => {\n await moveFile(details.path, newAbsolutePath);\n await fs.rm(path.join(screenshotsFolder, IMAGE_SNAPSHOT_PREFIX), {\n recursive: true,\n force: true,\n });\n\n return { path: newAbsolutePath };\n })();\n };\n","import fs from \"fs\";\nimport { PNG } from \"pngjs\";\nimport pixelmatch, { PixelmatchOptions } from \"pixelmatch\";\nimport moveFile from \"move-file\";\nimport path from \"path\";\nimport { FILE_SUFFIX, TASK } from \"./constants\";\nimport {\n cleanupUnused,\n alignImagesToSameSize,\n scaleImageAndWrite,\n isImageCurrentVersion,\n writePNG,\n} from \"./image.utils\";\nimport {\n generateScreenshotPath,\n resetScreenshotNameCache,\n} from \"./screenshotPath.utils\";\nimport type { CompareImagesTaskReturn } from \"./types\";\nimport { initAfterScreenshotHook } from \"./afterScreenshot.hook\";\n\nexport type CompareImagesCfg = {\n scaleFactor: number;\n title: string;\n imgNew: string;\n imgOld: string;\n updateImages: boolean;\n maxDiffThreshold: number;\n diffConfig: PixelmatchOptions;\n};\n\nconst round = (n: number) => Math.ceil(n * 1000) / 1000;\n\nconst unlinkSyncSafe = (path: string) =>\n fs.existsSync(path) && fs.unlinkSync(path);\nconst moveSyncSafe = (pathFrom: string, pathTo: string) =>\n fs.existsSync(pathFrom) && moveFile.sync(pathFrom, pathTo);\n\nexport const getScreenshotPathInfoTask = (cfg: {\n titleFromOptions: string;\n imagesPath: string;\n specPath: string;\n}) => {\n const screenshotPath = generateScreenshotPath(cfg);\n\n return { screenshotPath, title: path.basename(screenshotPath, \".png\") };\n};\n\nexport const cleanupImagesTask = (config: Cypress.PluginConfigOptions) => {\n if (config.env[\"pluginVisualRegressionCleanupUnusedImages\"]) {\n cleanupUnused(config.projectRoot);\n }\n\n resetScreenshotNameCache();\n\n return null;\n};\n\nexport const approveImageTask = ({ img }: { img: string }) => {\n const oldImg = img.replace(FILE_SUFFIX.actual, \"\");\n unlinkSyncSafe(oldImg);\n\n const diffImg = img.replace(FILE_SUFFIX.actual, FILE_SUFFIX.diff);\n unlinkSyncSafe(diffImg);\n\n moveSyncSafe(img, oldImg);\n\n return null;\n};\n\nexport const compareImagesTask = async (\n cfg: CompareImagesCfg\n): Promise => {\n const messages = [] as string[];\n const rawImgNewBuffer = await scaleImageAndWrite({\n scaleFactor: cfg.scaleFactor,\n path: cfg.imgNew,\n });\n let imgDiff: number | undefined;\n let imgNewBase64: string, imgOldBase64: string, imgDiffBase64: string;\n let error = false;\n\n if (fs.existsSync(cfg.imgOld) && !cfg.updateImages) {\n const rawImgNew = PNG.sync.read(rawImgNewBuffer);\n const rawImgOldBuffer = fs.readFileSync(cfg.imgOld);\n const rawImgOld = PNG.sync.read(rawImgOldBuffer);\n const isImgSizeDifferent =\n rawImgNew.height !== rawImgOld.height ||\n rawImgNew.width !== rawImgOld.width;\n\n const [imgNew, imgOld] = isImgSizeDifferent\n ? alignImagesToSameSize(rawImgNew, rawImgOld)\n : [rawImgNew, rawImgOld];\n\n const { width, height } = imgNew;\n const diff = new PNG({ width, height });\n const diffConfig = Object.assign({ includeAA: true }, cfg.diffConfig);\n\n const diffPixels = pixelmatch(\n imgNew.data,\n imgOld.data,\n diff.data,\n width,\n height,\n diffConfig\n );\n imgDiff = diffPixels / (width * height);\n\n if (isImgSizeDifferent) {\n messages.push(\n `Warning: Images size mismatch - new screenshot is ${rawImgNew.width}px by ${rawImgNew.height}px while old one is ${rawImgOld.width}px by ${rawImgOld.height} (width x height).`\n );\n }\n\n if (imgDiff > cfg.maxDiffThreshold) {\n messages.unshift(\n `Image diff factor (${round(\n imgDiff\n )}%) is bigger than maximum threshold option ${cfg.maxDiffThreshold}.`\n );\n error = true;\n }\n\n const diffBuffer = PNG.sync.write(diff);\n imgNewBase64 = PNG.sync.write(imgNew).toString(\"base64\");\n imgDiffBase64 = diffBuffer.toString(\"base64\");\n imgOldBase64 = PNG.sync.write(imgOld).toString(\"base64\");\n\n if (error) {\n writePNG(\n cfg.imgNew.replace(FILE_SUFFIX.actual, FILE_SUFFIX.diff),\n diffBuffer\n );\n return {\n error,\n message: messages.join(\"\\n\"),\n imgDiff,\n imgNewBase64,\n imgDiffBase64,\n imgOldBase64,\n maxDiffThreshold: cfg.maxDiffThreshold,\n };\n } else {\n if (rawImgOld && !isImageCurrentVersion(rawImgOldBuffer)) {\n writePNG(cfg.imgNew, rawImgNewBuffer);\n moveFile.sync(cfg.imgNew, cfg.imgOld);\n } else {\n // don't overwrite file if it's the same (imgDiff < cfg.maxDiffThreshold && !isImgSizeDifferent)\n fs.unlinkSync(cfg.imgNew);\n }\n }\n } else {\n // there is no \"old screenshot\" or screenshots should be immediately updated\n imgDiff = 0;\n imgNewBase64 = \"\";\n imgDiffBase64 = \"\";\n imgOldBase64 = \"\";\n writePNG(cfg.imgNew, rawImgNewBuffer);\n moveFile.sync(cfg.imgNew, cfg.imgOld);\n }\n\n if (typeof imgDiff !== \"undefined\") {\n messages.unshift(\n `Image diff factor (${round(\n imgDiff\n )}%) is within boundaries of maximum threshold option ${\n cfg.maxDiffThreshold\n }.`\n );\n return {\n message: messages.join(\"\\n\"),\n imgDiff,\n imgNewBase64,\n imgDiffBase64,\n imgOldBase64,\n maxDiffThreshold: cfg.maxDiffThreshold,\n };\n }\n\n /* c8 ignore next */\n return null;\n};\n\nexport const doesFileExistTask = ({ path }: { path: string }) =>\n fs.existsSync(path);\n\n/* c8 ignore start */\nexport const initTaskHook = (config: Cypress.PluginConfigOptions) => ({\n [TASK.getScreenshotPathInfo]: getScreenshotPathInfoTask,\n [TASK.cleanupImages]: cleanupImagesTask.bind(undefined, config),\n [TASK.doesFileExist]: doesFileExistTask,\n [TASK.approveImage]: approveImageTask,\n [TASK.compareImages]: compareImagesTask,\n [TASK.runAfterScreenshotHook]: initAfterScreenshotHook(config),\n});\n/* c8 ignore stop */\n","import { initTaskHook } from \"./task.hook\";\nimport { initAfterScreenshotHook } from \"./afterScreenshot.hook\";\n\n/* c8 ignore start */\nconst initForceDeviceScaleFactor = (on: Cypress.PluginEvents) => {\n // based on https://github.com/cypress-io/cypress/issues/2102#issuecomment-521299946\n on(\"before:browser:launch\", (browser, launchOptions) => {\n if (browser.name === \"chrome\" || browser.name === \"chromium\") {\n launchOptions.args.push(\"--force-device-scale-factor=1\");\n launchOptions.args.push(\"--high-dpi-support=1\");\n } else if (browser.name === \"electron\" && browser.isHeaded) {\n // eslint-disable-next-line no-console\n console.log(\n \"There isn't currently a way of setting the device scale factor in Cypress when running headed electron so we disable the image regression commands.\"\n );\n }\n });\n};\n/* c8 ignore stop */\n\nexport const initPlugin = (\n on: Cypress.PluginEvents,\n config: Cypress.PluginConfigOptions\n) => {\n /* c8 ignore start */\n if (config.env[\"pluginVisualRegressionForceDeviceScaleFactor\"] !== false) {\n initForceDeviceScaleFactor(on);\n }\n /* c8 ignore stop */\n on(\"task\", initTaskHook(config));\n on(\"after:screenshot\", initAfterScreenshotHook(config));\n};\n"],"names":["PLUGIN_NAME","IMAGE_SNAPSHOT_PREFIX","FILE_SUFFIX","TASK","getScreenshotPathInfo","compareImages","approveImage","cleanupImages","doesFileExist","runAfterScreenshotHook","PATH_VARIABLES","specPath","unixSystemRootPath","winSystemRootPath","WINDOWS_LIKE_DRIVE_REGEX","METADATA_KEY","truncate","nameCacheCounter","generateScreenshotPath","titleFromOptions","imagesPath","parsePathPartVariables","pathPart","i","path","dirname","test","join","screenshotPath","split","map","sanitize","actual","screenshotPathRegex","RegExp","diff","wasScreenshotUsed","imagePath","matched","match","numString","num","parseInt","isNaN","resetScreenshotNameCache","Object","keys","forEach","k","addPNGMetadata","png","addMetadata","version","getPNGMetadata","getMetadata","isImageCurrentVersion","isImageGeneratedByPlugin","writePNG","name","fs","writeFileSync","PNG","sync","write","inArea","x","y","height","width","fillSizeDifference","image","idx","data","createImageResizer","source","resized","fill","bitblt","scaleImageAndWrite","scaleFactor","imgBuffer","readFileSync","rawImgNew","read","newImageWidth","Math","ceil","newImageHeight","sharp","resize","toFile","alignImagesToSameSize","firstImage","secondImage","firstImageWidth","firstImageHeight","secondImageWidth","secondImageHeight","resizeToSameSize","max","resizedFirst","resizedSecond","cleanupUnused","rootPath","glob","cwd","ignore","pngPath","absolutePath","unlinkSync","MIMIC_ROOT_WIN_REGEX","sep","MIMIC_ROOT_UNIX_REGEX","getConfigVariableOrThrow","config","parseAbsolutePath","projectRoot","newAbsolutePath","matchedMimicingWinRoot","matchedMimicingUnixRoot","driveLetter","substring","length","normalize","initAfterScreenshotHook","details","indexOf","screenshotsFolder","moveFile","rm","recursive","force","round","n","unlinkSyncSafe","existsSync","moveSyncSafe","pathFrom","pathTo","getScreenshotPathInfoTask","cfg","title","basename","cleanupImagesTask","env","approveImageTask","img","oldImg","replace","diffImg","compareImagesTask","messages","rawImgNewBuffer","imgNew","imgDiff","imgNewBase64","imgOldBase64","imgDiffBase64","error","imgOld","updateImages","rawImgOldBuffer","rawImgOld","isImgSizeDifferent","diffConfig","assign","includeAA","diffPixels","pixelmatch","push","maxDiffThreshold","unshift","diffBuffer","toString","message","doesFileExistTask","initTaskHook","bind","undefined","initForceDeviceScaleFactor","on","browser","launchOptions","args","isHeaded","console","log","initPlugin"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"plugins.mjs","sources":["../src/constants.ts","../node_modules/truncate-utf8-bytes/lib/truncate.js","../node_modules/truncate-utf8-bytes/index.js","../node_modules/sanitize-filename/index.js","../src/screenshotPath.utils.ts","../src/image.utils.ts","../src/afterScreenshot.hook.ts","../src/task.hook.ts","../src/plugins.ts"],"sourcesContent":["const PLUGIN_NAME = \"cp-visual-regression-diff\";\nexport const LINK_PREFIX = `#${PLUGIN_NAME}-`;\nexport const OVERLAY_CLASS = `${PLUGIN_NAME}-overlay`;\nexport const IMAGE_SNAPSHOT_PREFIX = `__${PLUGIN_NAME}_snapshots__`;\n\nexport enum FILE_SUFFIX {\n diff = \".diff\",\n actual = \".actual\",\n}\n\nexport const TASK = {\n getScreenshotPathInfo: `${PLUGIN_NAME}-getScreenshotPathInfo`,\n compareImages: `${PLUGIN_NAME}-compareImages`,\n approveImage: `${PLUGIN_NAME}-approveImage`,\n cleanupImages: `${PLUGIN_NAME}-cleanupImages`,\n doesFileExist: `${PLUGIN_NAME}-doesFileExist`,\n runAfterScreenshotHook: `${PLUGIN_NAME}-runAfterScreenshotHook`,\n /* c8 ignore next */\n};\n\nexport const PATH_VARIABLES = {\n specPath: \"{spec_path}\",\n unixSystemRootPath: \"{unix_system_root_path}\",\n winSystemRootPath: \"{win_system_root_path}\",\n} as const;\n\nexport const WINDOWS_LIKE_DRIVE_REGEX = /^[A-Z]:$/;\n\nexport const METADATA_KEY = \"FRSOURCE_CPVRD_V\";\n","'use strict';\n\nfunction isHighSurrogate(codePoint) {\n return codePoint >= 0xd800 && codePoint <= 0xdbff;\n}\n\nfunction isLowSurrogate(codePoint) {\n return codePoint >= 0xdc00 && codePoint <= 0xdfff;\n}\n\n// Truncate string by size in bytes\nmodule.exports = function truncate(getLength, string, byteLength) {\n if (typeof string !== \"string\") {\n throw new Error(\"Input must be string\");\n }\n\n var charLength = string.length;\n var curByteLength = 0;\n var codePoint;\n var segment;\n\n for (var i = 0; i < charLength; i += 1) {\n codePoint = string.charCodeAt(i);\n segment = string[i];\n\n if (isHighSurrogate(codePoint) && isLowSurrogate(string.charCodeAt(i + 1))) {\n i += 1;\n segment += string[i];\n }\n\n curByteLength += getLength(segment);\n\n if (curByteLength === byteLength) {\n return string.slice(0, i + 1);\n }\n else if (curByteLength > byteLength) {\n return string.slice(0, i - segment.length + 1);\n }\n }\n\n return string;\n};\n\n","'use strict';\n\nvar truncate = require(\"./lib/truncate\");\nvar getLength = Buffer.byteLength.bind(Buffer);\nmodule.exports = truncate.bind(null, getLength);\n","/*jshint node:true*/\n'use strict';\n\n/**\n * Replaces characters in strings that are illegal/unsafe for filenames.\n * Unsafe characters are either removed or replaced by a substitute set\n * in the optional `options` object.\n *\n * Illegal Characters on Various Operating Systems\n * / ? < > \\ : * | \"\n * https://kb.acronis.com/content/39790\n *\n * Unicode Control codes\n * C0 0x00-0x1f & C1 (0x80-0x9f)\n * http://en.wikipedia.org/wiki/C0_and_C1_control_codes\n *\n * Reserved filenames on Unix-based systems (\".\", \"..\")\n * Reserved filenames in Windows (\"CON\", \"PRN\", \"AUX\", \"NUL\", \"COM1\",\n * \"COM2\", \"COM3\", \"COM4\", \"COM5\", \"COM6\", \"COM7\", \"COM8\", \"COM9\",\n * \"LPT1\", \"LPT2\", \"LPT3\", \"LPT4\", \"LPT5\", \"LPT6\", \"LPT7\", \"LPT8\", and\n * \"LPT9\") case-insesitively and with or without filename extensions.\n *\n * Capped at 255 characters in length.\n * http://unix.stackexchange.com/questions/32795/what-is-the-maximum-allowed-filename-and-folder-size-with-ecryptfs\n *\n * @param {String} input Original filename\n * @param {Object} options {replacement: String | Function }\n * @return {String} Sanitized filename\n */\n\nvar truncate = require(\"truncate-utf8-bytes\");\n\nvar illegalRe = /[\\/\\?<>\\\\:\\*\\|\"]/g;\nvar controlRe = /[\\x00-\\x1f\\x80-\\x9f]/g;\nvar reservedRe = /^\\.+$/;\nvar windowsReservedRe = /^(con|prn|aux|nul|com[0-9]|lpt[0-9])(\\..*)?$/i;\nvar windowsTrailingRe = /[\\. ]+$/;\n\nfunction sanitize(input, replacement) {\n if (typeof input !== 'string') {\n throw new Error('Input must be string');\n }\n var sanitized = input\n .replace(illegalRe, replacement)\n .replace(controlRe, replacement)\n .replace(reservedRe, replacement)\n .replace(windowsReservedRe, replacement)\n .replace(windowsTrailingRe, replacement);\n return truncate(sanitized, 255);\n}\n\nmodule.exports = function (input, options) {\n var replacement = (options && options.replacement) || '';\n var output = sanitize(input, replacement);\n if (replacement === '') {\n return output;\n }\n return sanitize(output, '');\n};\n","import path from \"path\";\nimport {\n FILE_SUFFIX,\n IMAGE_SNAPSHOT_PREFIX,\n PATH_VARIABLES,\n WINDOWS_LIKE_DRIVE_REGEX,\n} from \"./constants\";\nimport sanitize from \"sanitize-filename\";\n\nconst nameCacheCounter: Record = {};\n\nexport const generateScreenshotPath = ({\n titleFromOptions,\n imagesPath,\n specPath,\n currentRetryNumber,\n}: {\n titleFromOptions: string;\n imagesPath: string;\n specPath: string;\n currentRetryNumber: number;\n}) => {\n const parsePathPartVariables = (pathPart: string, i: number) => {\n if (pathPart === PATH_VARIABLES.specPath) {\n return path.dirname(specPath);\n } else if (i === 0 && !pathPart) {\n // when unix-like absolute path\n return PATH_VARIABLES.unixSystemRootPath;\n } else if (i === 0 && WINDOWS_LIKE_DRIVE_REGEX.test(pathPart)) {\n // when win-like absolute path\n return path.join(PATH_VARIABLES.winSystemRootPath, pathPart[0]);\n }\n\n return pathPart;\n };\n\n const screenshotPath = path.join(\n ...imagesPath.split(\"/\").map(parsePathPartVariables),\n sanitize(titleFromOptions)\n );\n\n if (typeof nameCacheCounter[screenshotPath] === \"undefined\") {\n nameCacheCounter[screenshotPath] = -1;\n }\n\n // it's a retry of the same image, so let's decrease the counter\n if (currentRetryNumber > 0) {\n --nameCacheCounter[screenshotPath];\n }\n return path.join(\n IMAGE_SNAPSHOT_PREFIX,\n `${screenshotPath} #${++nameCacheCounter[screenshotPath]}${\n FILE_SUFFIX.actual\n }.png`\n );\n};\n\nconst screenshotPathRegex = new RegExp(\n `^([\\\\s\\\\S]+?) #([0-9]+)(?:(?:\\\\${FILE_SUFFIX.diff})|(?:\\\\${FILE_SUFFIX.actual}))?\\\\.(?:png|PNG)$`\n);\nexport const wasScreenshotUsed = (imagePath: string) => {\n const matched = imagePath.match(screenshotPathRegex);\n /* c8 ignore next */ if (!matched) return false;\n const [, screenshotPath, numString] = matched;\n const num = parseInt(numString);\n /* c8 ignore next */ if (!screenshotPath || isNaN(num)) return false;\n return (\n screenshotPath in nameCacheCounter &&\n num <= nameCacheCounter[screenshotPath]\n );\n};\n\nexport const resetScreenshotNameCache = () => {\n Object.keys(nameCacheCounter).forEach((k) => delete nameCacheCounter[k]);\n};\n","import path from \"path\";\nimport fs from \"fs\";\nimport { PNG, PNGWithMetadata } from \"pngjs\";\nimport sharp from \"sharp\";\nimport { addMetadata, getMetadata } from \"meta-png\";\nimport glob from \"glob\";\nimport { version } from \"../package.json\";\nimport { wasScreenshotUsed } from \"./screenshotPath.utils\";\nimport { METADATA_KEY } from \"./constants\";\n\nexport const addPNGMetadata = (png: Buffer) =>\n addMetadata(png, METADATA_KEY, version /* c8 ignore next */);\nexport const getPNGMetadata = (png: Buffer) =>\n getMetadata(png, METADATA_KEY /* c8 ignore next */);\nexport const isImageCurrentVersion = (png: Buffer) =>\n getPNGMetadata(png) === version;\nexport const isImageGeneratedByPlugin = (png: Buffer) =>\n !!getPNGMetadata(png /* c8 ignore next */);\n\nexport const writePNG = (name: string, png: PNG | Buffer) =>\n fs.writeFileSync(\n name,\n addPNGMetadata(png instanceof PNG ? PNG.sync.write(png) : png)\n );\n\nconst inArea = (x: number, y: number, height: number, width: number) =>\n y > height || x > width;\n\nexport const fillSizeDifference = (\n image: PNG,\n width: number,\n height: number\n) => {\n for (let y = 0; y < image.height; y++) {\n for (let x = 0; x < image.width; x++) {\n if (inArea(x, y, height, width)) {\n const idx = (image.width * y + x) << 2;\n image.data[idx] = 0;\n image.data[idx + 1] = 0;\n image.data[idx + 2] = 0;\n image.data[idx + 3] = 64;\n }\n }\n }\n return image;\n /* c8 ignore next */\n};\n\nexport const createImageResizer =\n (width: number, height: number) => (source: PNG) => {\n const resized = new PNG({ width, height, fill: true });\n PNG.bitblt(source, resized, 0, 0, source.width, source.height, 0, 0);\n return resized;\n /* c8 ignore next */\n };\n\nexport const scaleImageAndWrite = async ({\n scaleFactor,\n path,\n}: {\n scaleFactor: number;\n path: string;\n}) => {\n const imgBuffer = fs.readFileSync(path);\n if (scaleFactor === 1) return imgBuffer;\n\n const rawImgNew = PNG.sync.read(imgBuffer);\n const newImageWidth = Math.ceil(rawImgNew.width * scaleFactor);\n const newImageHeight = Math.ceil(rawImgNew.height * scaleFactor);\n await sharp(imgBuffer).resize(newImageWidth, newImageHeight).toFile(path);\n\n return fs.readFileSync(path);\n};\n\nexport const alignImagesToSameSize = (\n firstImage: PNGWithMetadata,\n secondImage: PNGWithMetadata\n) => {\n const firstImageWidth = firstImage.width;\n const firstImageHeight = firstImage.height;\n const secondImageWidth = secondImage.width;\n const secondImageHeight = secondImage.height;\n\n const resizeToSameSize = createImageResizer(\n Math.max(firstImageWidth, secondImageWidth),\n Math.max(firstImageHeight, secondImageHeight)\n );\n\n const resizedFirst = resizeToSameSize(firstImage);\n const resizedSecond = resizeToSameSize(secondImage);\n\n return [\n fillSizeDifference(resizedFirst, firstImageWidth, firstImageHeight),\n fillSizeDifference(resizedSecond, secondImageWidth, secondImageHeight),\n ];\n};\n\nexport const cleanupUnused = (rootPath: string) => {\n glob\n .sync(\"**/*.png\", {\n cwd: rootPath,\n ignore: \"node_modules/**/*\",\n })\n .forEach((pngPath) => {\n const absolutePath = path.join(rootPath, pngPath);\n if (\n !wasScreenshotUsed(pngPath) &&\n isImageGeneratedByPlugin(fs.readFileSync(absolutePath))\n ) {\n fs.unlinkSync(absolutePath);\n }\n });\n};\n","import path from \"path\";\nimport { promises as fs } from \"fs\";\nimport moveFile from \"move-file\";\nimport { IMAGE_SNAPSHOT_PREFIX, PATH_VARIABLES } from \"./constants\";\n\ntype NotFalsy = T extends false | null | undefined ? never : T;\n\nconst MIMIC_ROOT_WIN_REGEX = new RegExp(\n `^${PATH_VARIABLES.winSystemRootPath}\\\\${path.sep}([A-Z])\\\\${path.sep}`\n);\nconst MIMIC_ROOT_UNIX_REGEX = new RegExp(\n `^${PATH_VARIABLES.unixSystemRootPath}\\\\${path.sep}`\n);\n\nconst getConfigVariableOrThrow = (\n config: Cypress.PluginConfigOptions,\n name: K\n) => {\n if (config[name]) {\n return config[name] as NotFalsy;\n }\n\n /* c8 ignore start */\n throw `[@frsource/cypress-plugin-visual-regression-diff] CypressConfig.${name} cannot be missing or \\`false\\`!`;\n};\n/* c8 ignore stop */\n\nexport const parseAbsolutePath = ({\n screenshotPath,\n projectRoot,\n}: {\n screenshotPath: string;\n projectRoot: string;\n}) => {\n let newAbsolutePath: string;\n const matchedMimicingWinRoot = screenshotPath.match(MIMIC_ROOT_WIN_REGEX);\n const matchedMimicingUnixRoot = screenshotPath.match(MIMIC_ROOT_UNIX_REGEX);\n if (matchedMimicingWinRoot && matchedMimicingWinRoot[1]) {\n const driveLetter = matchedMimicingWinRoot[1];\n newAbsolutePath = path.join(\n `${driveLetter}:\\\\`,\n screenshotPath.substring(matchedMimicingWinRoot[0].length)\n );\n } else if (matchedMimicingUnixRoot) {\n newAbsolutePath =\n path.sep + screenshotPath.substring(matchedMimicingUnixRoot[0].length);\n } else {\n newAbsolutePath = path.join(projectRoot, screenshotPath);\n }\n return path.normalize(newAbsolutePath);\n};\n\nexport const initAfterScreenshotHook =\n (config: Cypress.PluginConfigOptions) =>\n (\n details: Cypress.ScreenshotDetails\n ):\n | void\n | Cypress.AfterScreenshotReturnObject\n | Promise => {\n // it's not a screenshot generated by FRSOURCE Cypress Plugin Visual Regression Diff\n /* c8 ignore start */\n if (details.name?.indexOf(IMAGE_SNAPSHOT_PREFIX) !== 0) return;\n /* c8 ignore stop */\n const screenshotsFolder = getConfigVariableOrThrow(\n config,\n \"screenshotsFolder\"\n );\n const screenshotPath = details.name.substring(\n IMAGE_SNAPSHOT_PREFIX.length + path.sep.length\n );\n const newAbsolutePath = parseAbsolutePath({\n screenshotPath,\n projectRoot: config.projectRoot,\n });\n\n return (async () => {\n await moveFile(details.path, newAbsolutePath);\n await fs.rm(path.join(screenshotsFolder, IMAGE_SNAPSHOT_PREFIX), {\n recursive: true,\n force: true,\n });\n\n return { path: newAbsolutePath };\n })();\n };\n","import fs from \"fs\";\nimport { PNG } from \"pngjs\";\nimport pixelmatch, { PixelmatchOptions } from \"pixelmatch\";\nimport moveFile from \"move-file\";\nimport path from \"path\";\nimport { FILE_SUFFIX, TASK } from \"./constants\";\nimport {\n cleanupUnused,\n alignImagesToSameSize,\n scaleImageAndWrite,\n isImageCurrentVersion,\n writePNG,\n} from \"./image.utils\";\nimport {\n generateScreenshotPath,\n resetScreenshotNameCache,\n} from \"./screenshotPath.utils\";\nimport type { CompareImagesTaskReturn } from \"./types\";\nimport { initAfterScreenshotHook } from \"./afterScreenshot.hook\";\n\nexport type CompareImagesCfg = {\n scaleFactor: number;\n title: string;\n imgNew: string;\n imgOld: string;\n updateImages: boolean;\n maxDiffThreshold: number;\n diffConfig: PixelmatchOptions;\n};\n\nconst round = (n: number) => Math.ceil(n * 1000) / 1000;\n\nconst unlinkSyncSafe = (path: string) =>\n fs.existsSync(path) && fs.unlinkSync(path);\nconst moveSyncSafe = (pathFrom: string, pathTo: string) =>\n fs.existsSync(pathFrom) && moveFile.sync(pathFrom, pathTo);\n\nexport const getScreenshotPathInfoTask = (cfg: {\n titleFromOptions: string;\n imagesPath: string;\n specPath: string;\n currentRetryNumber: number;\n}) => {\n const screenshotPath = generateScreenshotPath(cfg);\n\n return { screenshotPath, title: path.basename(screenshotPath, \".png\") };\n};\n\nexport const cleanupImagesTask = (config: Cypress.PluginConfigOptions) => {\n if (config.env[\"pluginVisualRegressionCleanupUnusedImages\"]) {\n cleanupUnused(config.projectRoot);\n }\n\n resetScreenshotNameCache();\n\n return null;\n};\n\nexport const approveImageTask = ({ img }: { img: string }) => {\n const oldImg = img.replace(FILE_SUFFIX.actual, \"\");\n unlinkSyncSafe(oldImg);\n\n const diffImg = img.replace(FILE_SUFFIX.actual, FILE_SUFFIX.diff);\n unlinkSyncSafe(diffImg);\n\n moveSyncSafe(img, oldImg);\n\n return null;\n};\n\nexport const compareImagesTask = async (\n cfg: CompareImagesCfg\n): Promise => {\n const messages = [] as string[];\n const rawImgNewBuffer = await scaleImageAndWrite({\n scaleFactor: cfg.scaleFactor,\n path: cfg.imgNew,\n });\n let imgDiff: number | undefined;\n let imgNewBase64: string, imgOldBase64: string, imgDiffBase64: string;\n let error = false;\n\n if (fs.existsSync(cfg.imgOld) && !cfg.updateImages) {\n const rawImgNew = PNG.sync.read(rawImgNewBuffer);\n const rawImgOldBuffer = fs.readFileSync(cfg.imgOld);\n const rawImgOld = PNG.sync.read(rawImgOldBuffer);\n const isImgSizeDifferent =\n rawImgNew.height !== rawImgOld.height ||\n rawImgNew.width !== rawImgOld.width;\n\n const [imgNew, imgOld] = isImgSizeDifferent\n ? alignImagesToSameSize(rawImgNew, rawImgOld)\n : [rawImgNew, rawImgOld];\n\n const { width, height } = imgNew;\n const diff = new PNG({ width, height });\n const diffConfig = Object.assign({ includeAA: true }, cfg.diffConfig);\n\n const diffPixels = pixelmatch(\n imgNew.data,\n imgOld.data,\n diff.data,\n width,\n height,\n diffConfig\n );\n imgDiff = diffPixels / (width * height);\n\n if (isImgSizeDifferent) {\n messages.push(\n `Warning: Images size mismatch - new screenshot is ${rawImgNew.width}px by ${rawImgNew.height}px while old one is ${rawImgOld.width}px by ${rawImgOld.height} (width x height).`\n );\n }\n\n if (imgDiff > cfg.maxDiffThreshold) {\n messages.unshift(\n `Image diff factor (${round(\n imgDiff\n )}%) is bigger than maximum threshold option ${cfg.maxDiffThreshold}.`\n );\n error = true;\n }\n\n const diffBuffer = PNG.sync.write(diff);\n imgNewBase64 = PNG.sync.write(imgNew).toString(\"base64\");\n imgDiffBase64 = diffBuffer.toString(\"base64\");\n imgOldBase64 = PNG.sync.write(imgOld).toString(\"base64\");\n\n if (error) {\n writePNG(\n cfg.imgNew.replace(FILE_SUFFIX.actual, FILE_SUFFIX.diff),\n diffBuffer\n );\n return {\n error,\n message: messages.join(\"\\n\"),\n imgDiff,\n imgNewBase64,\n imgDiffBase64,\n imgOldBase64,\n maxDiffThreshold: cfg.maxDiffThreshold,\n };\n } else {\n if (rawImgOld && !isImageCurrentVersion(rawImgOldBuffer)) {\n writePNG(cfg.imgNew, rawImgNewBuffer);\n moveFile.sync(cfg.imgNew, cfg.imgOld);\n } else {\n // don't overwrite file if it's the same (imgDiff < cfg.maxDiffThreshold && !isImgSizeDifferent)\n fs.unlinkSync(cfg.imgNew);\n }\n }\n } else {\n // there is no \"old screenshot\" or screenshots should be immediately updated\n imgDiff = 0;\n imgNewBase64 = \"\";\n imgDiffBase64 = \"\";\n imgOldBase64 = \"\";\n writePNG(cfg.imgNew, rawImgNewBuffer);\n moveFile.sync(cfg.imgNew, cfg.imgOld);\n }\n\n if (typeof imgDiff !== \"undefined\") {\n messages.unshift(\n `Image diff factor (${round(\n imgDiff\n )}%) is within boundaries of maximum threshold option ${\n cfg.maxDiffThreshold\n }.`\n );\n return {\n message: messages.join(\"\\n\"),\n imgDiff,\n imgNewBase64,\n imgDiffBase64,\n imgOldBase64,\n maxDiffThreshold: cfg.maxDiffThreshold,\n };\n }\n\n /* c8 ignore next */\n return null;\n};\n\nexport const doesFileExistTask = ({ path }: { path: string }) =>\n fs.existsSync(path);\n\n/* c8 ignore start */\nexport const initTaskHook = (config: Cypress.PluginConfigOptions) => ({\n [TASK.getScreenshotPathInfo]: getScreenshotPathInfoTask,\n [TASK.cleanupImages]: cleanupImagesTask.bind(undefined, config),\n [TASK.doesFileExist]: doesFileExistTask,\n [TASK.approveImage]: approveImageTask,\n [TASK.compareImages]: compareImagesTask,\n [TASK.runAfterScreenshotHook]: initAfterScreenshotHook(config),\n});\n/* c8 ignore stop */\n","import { initTaskHook } from \"./task.hook\";\nimport { initAfterScreenshotHook } from \"./afterScreenshot.hook\";\n\n/* c8 ignore start */\nconst initForceDeviceScaleFactor = (on: Cypress.PluginEvents) => {\n // based on https://github.com/cypress-io/cypress/issues/2102#issuecomment-521299946\n on(\"before:browser:launch\", (browser, launchOptions) => {\n if (browser.name === \"chrome\" || browser.name === \"chromium\") {\n launchOptions.args.push(\"--force-device-scale-factor=1\");\n launchOptions.args.push(\"--high-dpi-support=1\");\n } else if (browser.name === \"electron\" && browser.isHeaded) {\n // eslint-disable-next-line no-console\n console.log(\n \"There isn't currently a way of setting the device scale factor in Cypress when running headed electron so we disable the image regression commands.\"\n );\n }\n });\n};\n/* c8 ignore stop */\n\nexport const initPlugin = (\n on: Cypress.PluginEvents,\n config: Cypress.PluginConfigOptions\n) => {\n /* c8 ignore start */\n if (config.env[\"pluginVisualRegressionForceDeviceScaleFactor\"] !== false) {\n initForceDeviceScaleFactor(on);\n }\n /* c8 ignore stop */\n on(\"task\", initTaskHook(config));\n on(\"after:screenshot\", initAfterScreenshotHook(config));\n};\n"],"names":["PLUGIN_NAME","IMAGE_SNAPSHOT_PREFIX","FILE_SUFFIX","TASK","getScreenshotPathInfo","compareImages","approveImage","cleanupImages","doesFileExist","runAfterScreenshotHook","PATH_VARIABLES","specPath","unixSystemRootPath","winSystemRootPath","WINDOWS_LIKE_DRIVE_REGEX","METADATA_KEY","truncate","nameCacheCounter","generateScreenshotPath","titleFromOptions","imagesPath","currentRetryNumber","parsePathPartVariables","pathPart","i","path","dirname","test","join","screenshotPath","split","map","sanitize","actual","screenshotPathRegex","RegExp","diff","wasScreenshotUsed","imagePath","matched","match","numString","num","parseInt","isNaN","resetScreenshotNameCache","Object","keys","forEach","k","addPNGMetadata","png","addMetadata","version","getPNGMetadata","getMetadata","isImageCurrentVersion","isImageGeneratedByPlugin","writePNG","name","fs","writeFileSync","PNG","sync","write","inArea","x","y","height","width","fillSizeDifference","image","idx","data","createImageResizer","source","resized","fill","bitblt","scaleImageAndWrite","scaleFactor","imgBuffer","readFileSync","rawImgNew","read","newImageWidth","Math","ceil","newImageHeight","sharp","resize","toFile","alignImagesToSameSize","firstImage","secondImage","firstImageWidth","firstImageHeight","secondImageWidth","secondImageHeight","resizeToSameSize","max","resizedFirst","resizedSecond","cleanupUnused","rootPath","glob","cwd","ignore","pngPath","absolutePath","unlinkSync","MIMIC_ROOT_WIN_REGEX","sep","MIMIC_ROOT_UNIX_REGEX","getConfigVariableOrThrow","config","parseAbsolutePath","projectRoot","newAbsolutePath","matchedMimicingWinRoot","matchedMimicingUnixRoot","driveLetter","substring","length","normalize","initAfterScreenshotHook","details","indexOf","screenshotsFolder","moveFile","rm","recursive","force","round","n","unlinkSyncSafe","existsSync","moveSyncSafe","pathFrom","pathTo","getScreenshotPathInfoTask","cfg","title","basename","cleanupImagesTask","env","approveImageTask","img","oldImg","replace","diffImg","compareImagesTask","messages","rawImgNewBuffer","imgNew","imgDiff","imgNewBase64","imgOldBase64","imgDiffBase64","error","imgOld","updateImages","rawImgOldBuffer","rawImgOld","isImgSizeDifferent","diffConfig","assign","includeAA","diffPixels","pixelmatch","push","maxDiffThreshold","unshift","diffBuffer","toString","message","doesFileExistTask","initTaskHook","bind","undefined","initForceDeviceScaleFactor","on","browser","launchOptions","args","isHeaded","console","log","initPlugin"],"mappings":"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"} \ No newline at end of file diff --git a/dist/support.js b/dist/support.js index 81c57ab9..ed79b3c8 100644 --- a/dist/support.js +++ b/dist/support.js @@ -68,7 +68,8 @@ const getConfig = options => { maxDiffThreshold: options.maxDiffThreshold || Cypress.env("pluginVisualRegressionMaxDiffThreshold") || 0.01, diffConfig: options.diffConfig || Cypress.env("pluginVisualRegressionDiffConfig") || {}, screenshotConfig: options.screenshotConfig || Cypress.env("pluginVisualRegressionScreenshotConfig") || {}, - remoteScreenshotServiceUrl: options.remoteScreenshotServiceUrl || Cypress.env("pluginVisualRegressionRemoteScreenshotServiceUrl") + remoteScreenshotServiceUrl: options.remoteScreenshotServiceUrl || Cypress.env("pluginVisualRegressionRemoteScreenshotServiceUrl"), + matchAgainstPath: options.matchAgainstPath || undefined }; }; Cypress.Commands.add("matchImage", { @@ -83,12 +84,15 @@ Cypress.Commands.add("matchImage", { maxDiffThreshold, diffConfig, screenshotConfig, - remoteScreenshotServiceUrl + remoteScreenshotServiceUrl, + matchAgainstPath } = getConfig(options); + const currentRetryNumber = cy.state("test").currentRetry(); return cy.then(() => cy.task(TASK.getScreenshotPathInfo, { titleFromOptions: options.title || Cypress.currentTest.titlePath.join(" "), imagesPath, - specPath: Cypress.spec.relative + specPath: Cypress.spec.relative, + currentRetryNumber }, { log: false })).then(({ @@ -132,7 +136,7 @@ Cypress.Commands.add("matchImage", { }).then(imgPath => cy.task(TASK.compareImages, { scaleFactor, imgNew: imgPath, - imgOld: imgPath.replace(FILE_SUFFIX.actual, ""), + imgOld: matchAgainstPath || imgPath.replace(FILE_SUFFIX.actual, ""), updateImages, maxDiffThreshold, diffConfig @@ -169,6 +173,19 @@ Cypress.Commands.add("matchImage", { log.set("consoleProps", () => res); throw constructCypressError(log, new Error(res.message)); } + + return { + diffValue: res.imgDiff, + imgNewPath: imgPath, + imgPath: imgPath.replace(FILE_SUFFIX.actual, ""), + imgDiffPath: imgPath.replace(FILE_SUFFIX.actual, FILE_SUFFIX.diff), + imgNewBase64: res.imgNewBase64, + imgBase64: res.imgOldBase64, + imgDiffBase64: res.imgDiffBase64, + imgNew: typeof res.imgNewBase64 === "string" ? Cypress.Buffer.from(res.imgNewBase64, "base64") : undefined, + img: typeof res.imgOldBase64 === "string" ? Cypress.Buffer.from(res.imgOldBase64, "base64") : undefined, + imgDiff: typeof res.imgDiffBase64 === "string" ? Cypress.Buffer.from(res.imgDiffBase64, "base64") : undefined + }; }); }); diff --git a/dist/support.js.map b/dist/support.js.map index 45a2433e..cd61f485 100644 --- a/dist/support.js.map +++ b/dist/support.js.map @@ -1 +1 @@ -{"version":3,"file":"support.js","sources":["../src/constants.ts","../src/commands.ts","../src/support.ts"],"sourcesContent":["const PLUGIN_NAME = \"cp-visual-regression-diff\";\nexport const LINK_PREFIX = `#${PLUGIN_NAME}-`;\nexport const OVERLAY_CLASS = `${PLUGIN_NAME}-overlay`;\nexport const IMAGE_SNAPSHOT_PREFIX = `__${PLUGIN_NAME}_snapshots__`;\n\nexport enum FILE_SUFFIX {\n diff = \".diff\",\n actual = \".actual\",\n}\n\nexport const TASK = {\n getScreenshotPathInfo: `${PLUGIN_NAME}-getScreenshotPathInfo`,\n compareImages: `${PLUGIN_NAME}-compareImages`,\n approveImage: `${PLUGIN_NAME}-approveImage`,\n cleanupImages: `${PLUGIN_NAME}-cleanupImages`,\n doesFileExist: `${PLUGIN_NAME}-doesFileExist`,\n runAfterScreenshotHook: `${PLUGIN_NAME}-runAfterScreenshotHook`,\n /* c8 ignore next */\n};\n\nexport const PATH_VARIABLES = {\n specPath: \"{spec_path}\",\n unixSystemRootPath: \"{unix_system_root_path}\",\n winSystemRootPath: \"{win_system_root_path}\",\n} as const;\n\nexport const WINDOWS_LIKE_DRIVE_REGEX = /^[A-Z]:$/;\n\nexport const METADATA_KEY = \"FRSOURCE_CPVRD_V\";\n","import { FILE_SUFFIX, LINK_PREFIX, TASK } from \"./constants\";\nimport type pixelmatch from \"pixelmatch\";\nimport * as Base64 from \"@frsource/base64\";\nimport type { CompareImagesTaskReturn } from \"./types\";\n\ndeclare global {\n // eslint-disable-next-line @typescript-eslint/no-namespace\n namespace Cypress {\n type MatchImageOptions = {\n screenshotConfig?: Partial;\n remoteScreenshotServiceUrl?: string;\n diffConfig?: Parameters[5];\n updateImages?: boolean;\n /**\n * @deprecated since version 3.0, use imagesPath instead\n */\n imagesDir?: string;\n imagesPath?: string;\n maxDiffThreshold?: number;\n title?: string;\n };\n\n interface Chainable {\n /**\n * Command to create and compare image snapshots.\n * @memberof Cypress.Chainable\n * @example cy.get('.my-element').matchImage();\n */\n matchImage(options?: Cypress.MatchImageOptions): Chainable;\n }\n }\n}\n\nconst constructCypressError = (log: Cypress.Log, err: Error) => {\n // only way to throw & log the message properly in Cypress\n // https://github.com/cypress-io/cypress/blob/5f94cad3cb4126e0567290b957050c33e3a78e3c/packages/driver/src/cypress/error_utils.ts#L214-L216\n (err as unknown as { onFail: (e: Error) => void }).onFail = (err: Error) =>\n log.error(err);\n return err;\n};\n\nconst getImagesDir = (options: Cypress.MatchImageOptions) => {\n const imagesDir =\n options.imagesDir ||\n (Cypress.env(\"pluginVisualRegressionImagesDir\") as string | undefined);\n\n // TODO: remove in 4.0.0\n if (imagesDir) {\n console.warn(\n \"@frsource/cypress-plugin-visual-regression-diff] `imagesDir` option is deprecated, use `imagesPath` instead (https://github.com/FRSOURCE/cypress-plugin-visual-regression-diff#configuration)\"\n );\n }\n\n return imagesDir;\n};\n\nexport const getConfig = (options: Cypress.MatchImageOptions) => {\n const imagesDir = getImagesDir(options);\n\n return {\n scaleFactor:\n Cypress.env(\"pluginVisualRegressionForceDeviceScaleFactor\") === false\n ? 1\n : 1 / window.devicePixelRatio,\n updateImages:\n options.updateImages ||\n (Cypress.env(\"pluginVisualRegressionUpdateImages\") as\n | boolean\n | undefined) ||\n false,\n imagesPath:\n (imagesDir && `{spec_path}/${imagesDir}`) ||\n options.imagesPath ||\n (Cypress.env(\"pluginVisualRegressionImagesPath\") as string | undefined) ||\n \"{spec_path}/__image_snapshots__\",\n maxDiffThreshold:\n options.maxDiffThreshold ||\n (Cypress.env(\"pluginVisualRegressionMaxDiffThreshold\") as\n | number\n | undefined) ||\n 0.01,\n diffConfig:\n options.diffConfig ||\n (Cypress.env(\"pluginVisualRegressionDiffConfig\") as\n | Parameters[5]\n | undefined) ||\n {},\n screenshotConfig:\n options.screenshotConfig ||\n (Cypress.env(\"pluginVisualRegressionScreenshotConfig\") as\n | Partial\n | undefined) ||\n {},\n remoteScreenshotServiceUrl:\n options.remoteScreenshotServiceUrl ||\n (Cypress.env(\"pluginVisualRegressionRemoteScreenshotServiceUrl\") as\n | string\n | undefined),\n };\n};\n\nCypress.Commands.add(\n \"matchImage\",\n { prevSubject: \"optional\" },\n (subject, options = {}) => {\n const $el = subject as JQuery | undefined;\n let title: string;\n\n const {\n scaleFactor,\n updateImages,\n imagesPath,\n maxDiffThreshold,\n diffConfig,\n screenshotConfig,\n remoteScreenshotServiceUrl,\n } = getConfig(options);\n\n return cy\n .then(() =>\n cy.task<{ screenshotPath: string; title: string }>(\n TASK.getScreenshotPathInfo,\n {\n titleFromOptions:\n options.title || Cypress.currentTest.titlePath.join(\" \"),\n imagesPath,\n specPath: Cypress.spec.relative,\n },\n { log: false }\n )\n )\n .then(({ screenshotPath, title: titleFromTask }) => {\n title = titleFromTask;\n\n if (remoteScreenshotServiceUrl) {\n return cy.document().then((doc) => {\n return cy\n .request({\n url: remoteScreenshotServiceUrl,\n method: \"POST\",\n encoding: \"binary\",\n body: {\n html: $el?.html() || doc.body.parentElement?.innerHTML,\n },\n } as Cypress.RequestOptions)\n .then((response) => {\n return cy\n .writeFile(screenshotPath as string, response.body, \"binary\")\n .task<{ path: string }>(TASK.runAfterScreenshotHook, {\n path: screenshotPath,\n name: screenshotPath,\n });\n })\n .then(({ path }) => path);\n });\n } else {\n let imgPath: string;\n return ($el ? cy.wrap($el) : cy)\n .screenshot(screenshotPath, {\n ...screenshotConfig,\n onAfterScreenshot(el, props) {\n imgPath = props.path;\n screenshotConfig.onAfterScreenshot?.(el, props);\n },\n log: false,\n })\n .then(() => imgPath);\n }\n })\n .then((imgPath) =>\n cy\n .task(\n TASK.compareImages,\n {\n scaleFactor,\n imgNew: imgPath,\n imgOld: imgPath.replace(FILE_SUFFIX.actual, \"\"),\n updateImages,\n maxDiffThreshold,\n diffConfig,\n },\n { log: false }\n )\n .then((res) => ({\n res,\n imgPath,\n }))\n )\n .then(({ res, imgPath }) => {\n const log = Cypress.log({\n name: \"log\",\n displayName: \"Match image\",\n $el,\n });\n\n if (!res) {\n log.set(\"message\", \"Unexpected error!\");\n throw constructCypressError(log, new Error(\"Unexpected error!\"));\n }\n\n log.set(\n \"message\",\n `${res.message}${\n res.imgDiffBase64 && res.imgNewBase64 && res.imgOldBase64\n ? `\\n[See comparison](${LINK_PREFIX}${Base64.encode(\n encodeURIComponent(\n JSON.stringify({\n title,\n imgPath,\n imgDiffBase64: res.imgDiffBase64,\n imgNewBase64: res.imgNewBase64,\n imgOldBase64: res.imgOldBase64,\n error: res.error,\n })\n )\n )})`\n : \"\"\n }`\n );\n\n if (res.error) {\n log.set(\"consoleProps\", () => res);\n throw constructCypressError(log, new Error(res.message));\n }\n });\n }\n);\n","import * as Base64 from \"@frsource/base64\";\nimport \"./commands\";\nimport { LINK_PREFIX, OVERLAY_CLASS, TASK } from \"./constants\";\n\n/* c8 ignore start */\nfunction queueClear() {\n (cy as unknown as { queue: { clear: () => void } }).queue.clear();\n (cy as unknown as { state: (k: string, value: unknown) => void }).state(\n \"index\",\n 0\n );\n}\n\nfunction queueRun() {\n // needed to run a task outside of the test processing flow\n (cy as unknown as { queue: { run: () => void } }).queue.run();\n}\n/* c8 ignore stop */\nexport const generateOverlayTemplate = ({\n title,\n imgNewBase64,\n imgOldBase64,\n imgDiffBase64,\n wasImageNotUpdatedYet,\n error,\n}: {\n title: string;\n imgNewBase64: string;\n imgOldBase64: string;\n imgDiffBase64: string;\n wasImageNotUpdatedYet: boolean;\n error: boolean;\n}) => `
\n
\n \n
\n
\n
\n \n

New screenshot (hover mouse away too see the old one):

\n \n
\n

Old screenshot (hover over to see the new one):

\n \n
\n
\n
\n

Diff between new and old screenshot

\n \n
\n
\n
\n`;\n\n/* c8 ignore start */\nbefore(() => {\n if (!top) return null;\n Cypress.$(`.${OVERLAY_CLASS}`, top.document.body).remove();\n});\n\nafter(() => {\n if (!top) return null;\n\n cy.task(TASK.cleanupImages, { log: false });\n\n Cypress.$(top.document.body).on(\n \"click\",\n `a[href^=\"${LINK_PREFIX}\"]`,\n function (e) {\n e.preventDefault();\n if (!top) return false;\n\n const {\n title,\n imgPath,\n imgDiffBase64,\n imgNewBase64,\n imgOldBase64,\n error,\n } = JSON.parse(\n decodeURIComponent(\n Base64.decode(\n e.currentTarget.getAttribute(\"href\").substring(LINK_PREFIX.length)\n )\n )\n );\n queueClear();\n\n cy.task(\n TASK.doesFileExist,\n { path: imgPath },\n { log: false }\n ).then((wasImageNotUpdatedYet) => {\n if (!top) return false;\n queueClear();\n\n Cypress.$(\n generateOverlayTemplate({\n title,\n imgNewBase64,\n imgOldBase64,\n imgDiffBase64,\n error,\n wasImageNotUpdatedYet,\n })\n ).appendTo(top.document.body);\n\n const wrapper = Cypress.$(`.${OVERLAY_CLASS}`, top.document.body);\n wrapper.on(\"click\", 'button[data-type=\"close\"]', function () {\n wrapper.remove();\n });\n\n wrapper.on(\"submit\", \"form\", function (e) {\n e.preventDefault();\n\n cy.task(TASK.approveImage, { img: imgPath }).then(() =>\n wrapper.remove()\n );\n\n queueRun();\n });\n });\n\n queueRun();\n\n return false;\n }\n );\n});\n/* c8 ignore stop */\n"],"names":["PLUGIN_NAME","LINK_PREFIX","OVERLAY_CLASS","FILE_SUFFIX","TASK","getScreenshotPathInfo","compareImages","approveImage","cleanupImages","doesFileExist","runAfterScreenshotHook","constructCypressError","log","err","onFail","error","getImagesDir","options","imagesDir","Cypress","env","console","warn","getConfig","scaleFactor","window","devicePixelRatio","updateImages","imagesPath","maxDiffThreshold","diffConfig","screenshotConfig","remoteScreenshotServiceUrl","Commands","add","prevSubject","subject","$el","title","cy","then","task","titleFromOptions","currentTest","titlePath","join","specPath","spec","relative","screenshotPath","titleFromTask","document","doc","request","url","method","encoding","body","html","parentElement","innerHTML","response","writeFile","path","name","imgPath","wrap","screenshot","onAfterScreenshot","el","props","imgNew","imgOld","replace","actual","res","displayName","set","Error","message","imgDiffBase64","imgNewBase64","imgOldBase64","Base64","encode","encodeURIComponent","JSON","stringify","queueClear","queue","clear","state","queueRun","run","generateOverlayTemplate","wasImageNotUpdatedYet","before","top","$","remove","after","on","e","preventDefault","parse","decodeURIComponent","decode","currentTarget","getAttribute","substring","length","appendTo","wrapper","img"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"support.js","sources":["../src/constants.ts","../src/commands.ts","../src/support.ts"],"sourcesContent":["const PLUGIN_NAME = \"cp-visual-regression-diff\";\nexport const LINK_PREFIX = `#${PLUGIN_NAME}-`;\nexport const OVERLAY_CLASS = `${PLUGIN_NAME}-overlay`;\nexport const IMAGE_SNAPSHOT_PREFIX = `__${PLUGIN_NAME}_snapshots__`;\n\nexport enum FILE_SUFFIX {\n diff = \".diff\",\n actual = \".actual\",\n}\n\nexport const TASK = {\n getScreenshotPathInfo: `${PLUGIN_NAME}-getScreenshotPathInfo`,\n compareImages: `${PLUGIN_NAME}-compareImages`,\n approveImage: `${PLUGIN_NAME}-approveImage`,\n cleanupImages: `${PLUGIN_NAME}-cleanupImages`,\n doesFileExist: `${PLUGIN_NAME}-doesFileExist`,\n runAfterScreenshotHook: `${PLUGIN_NAME}-runAfterScreenshotHook`,\n /* c8 ignore next */\n};\n\nexport const PATH_VARIABLES = {\n specPath: \"{spec_path}\",\n unixSystemRootPath: \"{unix_system_root_path}\",\n winSystemRootPath: \"{win_system_root_path}\",\n} as const;\n\nexport const WINDOWS_LIKE_DRIVE_REGEX = /^[A-Z]:$/;\n\nexport const METADATA_KEY = \"FRSOURCE_CPVRD_V\";\n","import { FILE_SUFFIX, LINK_PREFIX, TASK } from \"./constants\";\nimport type pixelmatch from \"pixelmatch\";\nimport * as Base64 from \"@frsource/base64\";\nimport type { CompareImagesTaskReturn } from \"./types\";\n\ndeclare global {\n // eslint-disable-next-line @typescript-eslint/no-namespace\n namespace Cypress {\n type MatchImageOptions = {\n screenshotConfig?: Partial;\n remoteScreenshotServiceUrl?: string;\n diffConfig?: Parameters[5];\n updateImages?: boolean;\n /**\n * @deprecated since version 3.0, use imagesPath instead\n */\n imagesDir?: string;\n imagesPath?: string;\n maxDiffThreshold?: number;\n title?: string;\n matchAgainstPath?: string;\n // IDEA: to be implemented if support for files NOT from filesystem needed\n // matchAgainst?: string | Buffer;\n };\n\n type MatchImageReturn = {\n diffValue: number | undefined;\n imgNewPath: string;\n imgPath: string;\n imgDiffPath: string;\n imgNewBase64: string | undefined;\n imgBase64: string | undefined;\n imgDiffBase64: string | undefined;\n imgNew: InstanceType | undefined;\n img: InstanceType | undefined;\n imgDiff: InstanceType | undefined;\n };\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n interface Chainable {\n /**\n * Command to create and compare image snapshots.\n * @memberof Cypress.Chainable\n * @example cy.get('.my-element').matchImage();\n */\n matchImage(\n options?: Cypress.MatchImageOptions\n ): Chainable;\n }\n }\n}\n\nconst constructCypressError = (log: Cypress.Log, err: Error) => {\n // only way to throw & log the message properly in Cypress\n // https://github.com/cypress-io/cypress/blob/5f94cad3cb4126e0567290b957050c33e3a78e3c/packages/driver/src/cypress/error_utils.ts#L214-L216\n (err as unknown as { onFail: (e: Error) => void }).onFail = (err: Error) =>\n log.error(err);\n return err;\n};\n\nconst getImagesDir = (options: Cypress.MatchImageOptions) => {\n const imagesDir =\n options.imagesDir ||\n (Cypress.env(\"pluginVisualRegressionImagesDir\") as string | undefined);\n\n // TODO: remove in 4.0.0\n if (imagesDir) {\n console.warn(\n \"@frsource/cypress-plugin-visual-regression-diff] `imagesDir` option is deprecated, use `imagesPath` instead (https://github.com/FRSOURCE/cypress-plugin-visual-regression-diff#configuration)\"\n );\n }\n\n return imagesDir;\n};\n\nexport const getConfig = (options: Cypress.MatchImageOptions) => {\n const imagesDir = getImagesDir(options);\n\n return {\n scaleFactor:\n Cypress.env(\"pluginVisualRegressionForceDeviceScaleFactor\") === false\n ? 1\n : 1 / window.devicePixelRatio,\n updateImages:\n options.updateImages ||\n (Cypress.env(\"pluginVisualRegressionUpdateImages\") as\n | boolean\n | undefined) ||\n false,\n imagesPath:\n (imagesDir && `{spec_path}/${imagesDir}`) ||\n options.imagesPath ||\n (Cypress.env(\"pluginVisualRegressionImagesPath\") as string | undefined) ||\n \"{spec_path}/__image_snapshots__\",\n maxDiffThreshold:\n options.maxDiffThreshold ||\n (Cypress.env(\"pluginVisualRegressionMaxDiffThreshold\") as\n | number\n | undefined) ||\n 0.01,\n diffConfig:\n options.diffConfig ||\n (Cypress.env(\"pluginVisualRegressionDiffConfig\") as\n | Parameters[5]\n | undefined) ||\n {},\n screenshotConfig:\n options.screenshotConfig ||\n (Cypress.env(\"pluginVisualRegressionScreenshotConfig\") as\n | Partial\n | undefined) ||\n {},\n remoteScreenshotServiceUrl:\n options.remoteScreenshotServiceUrl ||\n (Cypress.env(\"pluginVisualRegressionRemoteScreenshotServiceUrl\") as\n | string\n | undefined),\n matchAgainstPath: options.matchAgainstPath || undefined,\n };\n};\n\nCypress.Commands.add(\n \"matchImage\",\n { prevSubject: \"optional\" },\n (subject, options = {}) => {\n const $el = subject as JQuery | undefined;\n let title: string;\n\n const {\n scaleFactor,\n updateImages,\n imagesPath,\n maxDiffThreshold,\n diffConfig,\n screenshotConfig,\n remoteScreenshotServiceUrl,\n matchAgainstPath,\n } = getConfig(options);\n\n const currentRetryNumber = (\n cy as unknown as { state: (s: string) => { currentRetry: () => number } }\n )\n .state(\"test\")\n .currentRetry();\n\n return cy\n .then(() =>\n cy.task<{ screenshotPath: string; title: string }>(\n TASK.getScreenshotPathInfo,\n {\n titleFromOptions:\n options.title || Cypress.currentTest.titlePath.join(\" \"),\n imagesPath,\n specPath: Cypress.spec.relative,\n currentRetryNumber,\n },\n { log: false }\n )\n )\n .then(({ screenshotPath, title: titleFromTask }) => {\n title = titleFromTask;\n\n if (remoteScreenshotServiceUrl) {\n return cy.document().then((doc) => {\n return cy\n .request({\n url: remoteScreenshotServiceUrl,\n method: \"POST\",\n encoding: \"binary\",\n body: {\n html: $el?.html() || doc.body.parentElement?.innerHTML,\n },\n } as Cypress.RequestOptions)\n .then((response) => {\n return cy\n .writeFile(screenshotPath as string, response.body, \"binary\")\n .task<{ path: string }>(TASK.runAfterScreenshotHook, {\n path: screenshotPath,\n name: screenshotPath,\n });\n })\n .then(({ path }) => path);\n });\n } else {\n let imgPath: string;\n return ($el ? cy.wrap($el) : cy)\n .screenshot(screenshotPath, {\n ...screenshotConfig,\n onAfterScreenshot(el, props) {\n imgPath = props.path;\n screenshotConfig.onAfterScreenshot?.(el, props);\n },\n log: false,\n })\n .then(() => imgPath);\n }\n })\n .then((imgPath) =>\n cy\n .task(\n TASK.compareImages,\n {\n scaleFactor,\n imgNew: imgPath,\n imgOld:\n matchAgainstPath || imgPath.replace(FILE_SUFFIX.actual, \"\"),\n updateImages,\n maxDiffThreshold,\n diffConfig,\n },\n { log: false }\n )\n .then((res) => ({\n res,\n imgPath,\n }))\n )\n .then(({ res, imgPath }) => {\n const log = Cypress.log({\n name: \"log\",\n displayName: \"Match image\",\n $el,\n });\n\n if (!res) {\n log.set(\"message\", \"Unexpected error!\");\n throw constructCypressError(log, new Error(\"Unexpected error!\"));\n }\n\n log.set(\n \"message\",\n `${res.message}${\n res.imgDiffBase64 && res.imgNewBase64 && res.imgOldBase64\n ? `\\n[See comparison](${LINK_PREFIX}${Base64.encode(\n encodeURIComponent(\n JSON.stringify({\n title,\n imgPath,\n imgDiffBase64: res.imgDiffBase64,\n imgNewBase64: res.imgNewBase64,\n imgOldBase64: res.imgOldBase64,\n error: res.error,\n })\n )\n )})`\n : \"\"\n }`\n );\n\n if (res.error) {\n log.set(\"consoleProps\", () => res);\n throw constructCypressError(log, new Error(res.message));\n }\n\n return {\n diffValue: res.imgDiff,\n imgNewPath: imgPath,\n imgPath: imgPath.replace(FILE_SUFFIX.actual, \"\"),\n imgDiffPath: imgPath.replace(FILE_SUFFIX.actual, FILE_SUFFIX.diff),\n imgNewBase64: res.imgNewBase64,\n imgBase64: res.imgOldBase64,\n imgDiffBase64: res.imgDiffBase64,\n imgNew:\n typeof res.imgNewBase64 === \"string\"\n ? Cypress.Buffer.from(res.imgNewBase64, \"base64\")\n : undefined,\n img:\n typeof res.imgOldBase64 === \"string\"\n ? Cypress.Buffer.from(res.imgOldBase64, \"base64\")\n : undefined,\n imgDiff:\n typeof res.imgDiffBase64 === \"string\"\n ? Cypress.Buffer.from(res.imgDiffBase64, \"base64\")\n : undefined,\n };\n });\n }\n);\n","import * as Base64 from \"@frsource/base64\";\nimport \"./commands\";\nimport { LINK_PREFIX, OVERLAY_CLASS, TASK } from \"./constants\";\n\n/* c8 ignore start */\nfunction queueClear() {\n (cy as unknown as { queue: { clear: () => void } }).queue.clear();\n (cy as unknown as { state: (k: string, value: unknown) => void }).state(\n \"index\",\n 0\n );\n}\n\nfunction queueRun() {\n // needed to run a task outside of the test processing flow\n (cy as unknown as { queue: { run: () => void } }).queue.run();\n}\n/* c8 ignore stop */\nexport const generateOverlayTemplate = ({\n title,\n imgNewBase64,\n imgOldBase64,\n imgDiffBase64,\n wasImageNotUpdatedYet,\n error,\n}: {\n title: string;\n imgNewBase64: string;\n imgOldBase64: string;\n imgDiffBase64: string;\n wasImageNotUpdatedYet: boolean;\n error: boolean;\n}) => `
\n
\n \n
\n
\n
\n \n

New screenshot (hover mouse away too see the old one):

\n \n
\n

Old screenshot (hover over to see the new one):

\n \n
\n
\n
\n

Diff between new and old screenshot

\n \n
\n
\n
\n`;\n\n/* c8 ignore start */\nbefore(() => {\n if (!top) return null;\n Cypress.$(`.${OVERLAY_CLASS}`, top.document.body).remove();\n});\n\nafter(() => {\n if (!top) return null;\n\n cy.task(TASK.cleanupImages, { log: false });\n\n Cypress.$(top.document.body).on(\n \"click\",\n `a[href^=\"${LINK_PREFIX}\"]`,\n function (e) {\n e.preventDefault();\n if (!top) return false;\n\n const {\n title,\n imgPath,\n imgDiffBase64,\n imgNewBase64,\n imgOldBase64,\n error,\n } = JSON.parse(\n decodeURIComponent(\n Base64.decode(\n e.currentTarget.getAttribute(\"href\").substring(LINK_PREFIX.length)\n )\n )\n );\n queueClear();\n\n cy.task(\n TASK.doesFileExist,\n { path: imgPath },\n { log: false }\n ).then((wasImageNotUpdatedYet) => {\n if (!top) return false;\n queueClear();\n\n Cypress.$(\n generateOverlayTemplate({\n title,\n imgNewBase64,\n imgOldBase64,\n imgDiffBase64,\n error,\n wasImageNotUpdatedYet,\n })\n ).appendTo(top.document.body);\n\n const wrapper = Cypress.$(`.${OVERLAY_CLASS}`, top.document.body);\n wrapper.on(\"click\", 'button[data-type=\"close\"]', function () {\n wrapper.remove();\n });\n\n wrapper.on(\"submit\", \"form\", function (e) {\n e.preventDefault();\n\n cy.task(TASK.approveImage, { img: imgPath }).then(() =>\n wrapper.remove()\n );\n\n queueRun();\n });\n });\n\n queueRun();\n\n return false;\n }\n );\n});\n/* c8 ignore stop */\n"],"names":["PLUGIN_NAME","LINK_PREFIX","OVERLAY_CLASS","FILE_SUFFIX","TASK","getScreenshotPathInfo","compareImages","approveImage","cleanupImages","doesFileExist","runAfterScreenshotHook","constructCypressError","log","err","onFail","error","getImagesDir","options","imagesDir","Cypress","env","console","warn","getConfig","scaleFactor","window","devicePixelRatio","updateImages","imagesPath","maxDiffThreshold","diffConfig","screenshotConfig","remoteScreenshotServiceUrl","matchAgainstPath","undefined","Commands","add","prevSubject","subject","$el","title","currentRetryNumber","cy","state","currentRetry","then","task","titleFromOptions","currentTest","titlePath","join","specPath","spec","relative","screenshotPath","titleFromTask","document","doc","request","url","method","encoding","body","html","parentElement","innerHTML","response","writeFile","path","name","imgPath","wrap","screenshot","onAfterScreenshot","el","props","imgNew","imgOld","replace","actual","res","displayName","set","Error","message","imgDiffBase64","imgNewBase64","imgOldBase64","Base64","encode","encodeURIComponent","JSON","stringify","diffValue","imgDiff","imgNewPath","imgDiffPath","diff","imgBase64","Buffer","from","img","queueClear","queue","clear","queueRun","run","generateOverlayTemplate","wasImageNotUpdatedYet","before","top","$","remove","after","on","e","preventDefault","parse","decodeURIComponent","decode","currentTarget","getAttribute","substring","length","appendTo","wrapper"],"mappings":"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"} \ No newline at end of file diff --git a/dist/support.mjs b/dist/support.mjs index bbc7f072..06c7439d 100644 --- a/dist/support.mjs +++ b/dist/support.mjs @@ -66,7 +66,8 @@ const getConfig = options => { maxDiffThreshold: options.maxDiffThreshold || Cypress.env("pluginVisualRegressionMaxDiffThreshold") || 0.01, diffConfig: options.diffConfig || Cypress.env("pluginVisualRegressionDiffConfig") || {}, screenshotConfig: options.screenshotConfig || Cypress.env("pluginVisualRegressionScreenshotConfig") || {}, - remoteScreenshotServiceUrl: options.remoteScreenshotServiceUrl || Cypress.env("pluginVisualRegressionRemoteScreenshotServiceUrl") + remoteScreenshotServiceUrl: options.remoteScreenshotServiceUrl || Cypress.env("pluginVisualRegressionRemoteScreenshotServiceUrl"), + matchAgainstPath: options.matchAgainstPath || undefined }; }; Cypress.Commands.add("matchImage", { @@ -81,12 +82,15 @@ Cypress.Commands.add("matchImage", { maxDiffThreshold, diffConfig, screenshotConfig, - remoteScreenshotServiceUrl + remoteScreenshotServiceUrl, + matchAgainstPath } = getConfig(options); + const currentRetryNumber = cy.state("test").currentRetry(); return cy.then(() => cy.task(TASK.getScreenshotPathInfo, { titleFromOptions: options.title || Cypress.currentTest.titlePath.join(" "), imagesPath, - specPath: Cypress.spec.relative + specPath: Cypress.spec.relative, + currentRetryNumber }, { log: false })).then(({ @@ -129,7 +133,7 @@ Cypress.Commands.add("matchImage", { }).then(imgPath => cy.task(TASK.compareImages, { scaleFactor, imgNew: imgPath, - imgOld: imgPath.replace(FILE_SUFFIX.actual, ""), + imgOld: matchAgainstPath || imgPath.replace(FILE_SUFFIX.actual, ""), updateImages, maxDiffThreshold, diffConfig @@ -166,6 +170,19 @@ Cypress.Commands.add("matchImage", { log.set("consoleProps", () => res); throw constructCypressError(log, new Error(res.message)); } + + return { + diffValue: res.imgDiff, + imgNewPath: imgPath, + imgPath: imgPath.replace(FILE_SUFFIX.actual, ""), + imgDiffPath: imgPath.replace(FILE_SUFFIX.actual, FILE_SUFFIX.diff), + imgNewBase64: res.imgNewBase64, + imgBase64: res.imgOldBase64, + imgDiffBase64: res.imgDiffBase64, + imgNew: typeof res.imgNewBase64 === "string" ? Cypress.Buffer.from(res.imgNewBase64, "base64") : undefined, + img: typeof res.imgOldBase64 === "string" ? Cypress.Buffer.from(res.imgOldBase64, "base64") : undefined, + imgDiff: typeof res.imgDiffBase64 === "string" ? Cypress.Buffer.from(res.imgDiffBase64, "base64") : undefined + }; }); }); diff --git a/dist/support.mjs.map b/dist/support.mjs.map index 357354cf..ac10bca2 100644 --- a/dist/support.mjs.map +++ b/dist/support.mjs.map @@ -1 +1 @@ -{"version":3,"file":"support.mjs","sources":["../src/constants.ts","../src/commands.ts","../src/support.ts"],"sourcesContent":["const PLUGIN_NAME = \"cp-visual-regression-diff\";\nexport const LINK_PREFIX = `#${PLUGIN_NAME}-`;\nexport const OVERLAY_CLASS = `${PLUGIN_NAME}-overlay`;\nexport const IMAGE_SNAPSHOT_PREFIX = `__${PLUGIN_NAME}_snapshots__`;\n\nexport enum FILE_SUFFIX {\n diff = \".diff\",\n actual = \".actual\",\n}\n\nexport const TASK = {\n getScreenshotPathInfo: `${PLUGIN_NAME}-getScreenshotPathInfo`,\n compareImages: `${PLUGIN_NAME}-compareImages`,\n approveImage: `${PLUGIN_NAME}-approveImage`,\n cleanupImages: `${PLUGIN_NAME}-cleanupImages`,\n doesFileExist: `${PLUGIN_NAME}-doesFileExist`,\n runAfterScreenshotHook: `${PLUGIN_NAME}-runAfterScreenshotHook`,\n /* c8 ignore next */\n};\n\nexport const PATH_VARIABLES = {\n specPath: \"{spec_path}\",\n unixSystemRootPath: \"{unix_system_root_path}\",\n winSystemRootPath: \"{win_system_root_path}\",\n} as const;\n\nexport const WINDOWS_LIKE_DRIVE_REGEX = /^[A-Z]:$/;\n\nexport const METADATA_KEY = \"FRSOURCE_CPVRD_V\";\n","import { FILE_SUFFIX, LINK_PREFIX, TASK } from \"./constants\";\nimport type pixelmatch from \"pixelmatch\";\nimport * as Base64 from \"@frsource/base64\";\nimport type { CompareImagesTaskReturn } from \"./types\";\n\ndeclare global {\n // eslint-disable-next-line @typescript-eslint/no-namespace\n namespace Cypress {\n type MatchImageOptions = {\n screenshotConfig?: Partial;\n remoteScreenshotServiceUrl?: string;\n diffConfig?: Parameters[5];\n updateImages?: boolean;\n /**\n * @deprecated since version 3.0, use imagesPath instead\n */\n imagesDir?: string;\n imagesPath?: string;\n maxDiffThreshold?: number;\n title?: string;\n };\n\n interface Chainable {\n /**\n * Command to create and compare image snapshots.\n * @memberof Cypress.Chainable\n * @example cy.get('.my-element').matchImage();\n */\n matchImage(options?: Cypress.MatchImageOptions): Chainable;\n }\n }\n}\n\nconst constructCypressError = (log: Cypress.Log, err: Error) => {\n // only way to throw & log the message properly in Cypress\n // https://github.com/cypress-io/cypress/blob/5f94cad3cb4126e0567290b957050c33e3a78e3c/packages/driver/src/cypress/error_utils.ts#L214-L216\n (err as unknown as { onFail: (e: Error) => void }).onFail = (err: Error) =>\n log.error(err);\n return err;\n};\n\nconst getImagesDir = (options: Cypress.MatchImageOptions) => {\n const imagesDir =\n options.imagesDir ||\n (Cypress.env(\"pluginVisualRegressionImagesDir\") as string | undefined);\n\n // TODO: remove in 4.0.0\n if (imagesDir) {\n console.warn(\n \"@frsource/cypress-plugin-visual-regression-diff] `imagesDir` option is deprecated, use `imagesPath` instead (https://github.com/FRSOURCE/cypress-plugin-visual-regression-diff#configuration)\"\n );\n }\n\n return imagesDir;\n};\n\nexport const getConfig = (options: Cypress.MatchImageOptions) => {\n const imagesDir = getImagesDir(options);\n\n return {\n scaleFactor:\n Cypress.env(\"pluginVisualRegressionForceDeviceScaleFactor\") === false\n ? 1\n : 1 / window.devicePixelRatio,\n updateImages:\n options.updateImages ||\n (Cypress.env(\"pluginVisualRegressionUpdateImages\") as\n | boolean\n | undefined) ||\n false,\n imagesPath:\n (imagesDir && `{spec_path}/${imagesDir}`) ||\n options.imagesPath ||\n (Cypress.env(\"pluginVisualRegressionImagesPath\") as string | undefined) ||\n \"{spec_path}/__image_snapshots__\",\n maxDiffThreshold:\n options.maxDiffThreshold ||\n (Cypress.env(\"pluginVisualRegressionMaxDiffThreshold\") as\n | number\n | undefined) ||\n 0.01,\n diffConfig:\n options.diffConfig ||\n (Cypress.env(\"pluginVisualRegressionDiffConfig\") as\n | Parameters[5]\n | undefined) ||\n {},\n screenshotConfig:\n options.screenshotConfig ||\n (Cypress.env(\"pluginVisualRegressionScreenshotConfig\") as\n | Partial\n | undefined) ||\n {},\n remoteScreenshotServiceUrl:\n options.remoteScreenshotServiceUrl ||\n (Cypress.env(\"pluginVisualRegressionRemoteScreenshotServiceUrl\") as\n | string\n | undefined),\n };\n};\n\nCypress.Commands.add(\n \"matchImage\",\n { prevSubject: \"optional\" },\n (subject, options = {}) => {\n const $el = subject as JQuery | undefined;\n let title: string;\n\n const {\n scaleFactor,\n updateImages,\n imagesPath,\n maxDiffThreshold,\n diffConfig,\n screenshotConfig,\n remoteScreenshotServiceUrl,\n } = getConfig(options);\n\n return cy\n .then(() =>\n cy.task<{ screenshotPath: string; title: string }>(\n TASK.getScreenshotPathInfo,\n {\n titleFromOptions:\n options.title || Cypress.currentTest.titlePath.join(\" \"),\n imagesPath,\n specPath: Cypress.spec.relative,\n },\n { log: false }\n )\n )\n .then(({ screenshotPath, title: titleFromTask }) => {\n title = titleFromTask;\n\n if (remoteScreenshotServiceUrl) {\n return cy.document().then((doc) => {\n return cy\n .request({\n url: remoteScreenshotServiceUrl,\n method: \"POST\",\n encoding: \"binary\",\n body: {\n html: $el?.html() || doc.body.parentElement?.innerHTML,\n },\n } as Cypress.RequestOptions)\n .then((response) => {\n return cy\n .writeFile(screenshotPath as string, response.body, \"binary\")\n .task<{ path: string }>(TASK.runAfterScreenshotHook, {\n path: screenshotPath,\n name: screenshotPath,\n });\n })\n .then(({ path }) => path);\n });\n } else {\n let imgPath: string;\n return ($el ? cy.wrap($el) : cy)\n .screenshot(screenshotPath, {\n ...screenshotConfig,\n onAfterScreenshot(el, props) {\n imgPath = props.path;\n screenshotConfig.onAfterScreenshot?.(el, props);\n },\n log: false,\n })\n .then(() => imgPath);\n }\n })\n .then((imgPath) =>\n cy\n .task(\n TASK.compareImages,\n {\n scaleFactor,\n imgNew: imgPath,\n imgOld: imgPath.replace(FILE_SUFFIX.actual, \"\"),\n updateImages,\n maxDiffThreshold,\n diffConfig,\n },\n { log: false }\n )\n .then((res) => ({\n res,\n imgPath,\n }))\n )\n .then(({ res, imgPath }) => {\n const log = Cypress.log({\n name: \"log\",\n displayName: \"Match image\",\n $el,\n });\n\n if (!res) {\n log.set(\"message\", \"Unexpected error!\");\n throw constructCypressError(log, new Error(\"Unexpected error!\"));\n }\n\n log.set(\n \"message\",\n `${res.message}${\n res.imgDiffBase64 && res.imgNewBase64 && res.imgOldBase64\n ? `\\n[See comparison](${LINK_PREFIX}${Base64.encode(\n encodeURIComponent(\n JSON.stringify({\n title,\n imgPath,\n imgDiffBase64: res.imgDiffBase64,\n imgNewBase64: res.imgNewBase64,\n imgOldBase64: res.imgOldBase64,\n error: res.error,\n })\n )\n )})`\n : \"\"\n }`\n );\n\n if (res.error) {\n log.set(\"consoleProps\", () => res);\n throw constructCypressError(log, new Error(res.message));\n }\n });\n }\n);\n","import * as Base64 from \"@frsource/base64\";\nimport \"./commands\";\nimport { LINK_PREFIX, OVERLAY_CLASS, TASK } from \"./constants\";\n\n/* c8 ignore start */\nfunction queueClear() {\n (cy as unknown as { queue: { clear: () => void } }).queue.clear();\n (cy as unknown as { state: (k: string, value: unknown) => void }).state(\n \"index\",\n 0\n );\n}\n\nfunction queueRun() {\n // needed to run a task outside of the test processing flow\n (cy as unknown as { queue: { run: () => void } }).queue.run();\n}\n/* c8 ignore stop */\nexport const generateOverlayTemplate = ({\n title,\n imgNewBase64,\n imgOldBase64,\n imgDiffBase64,\n wasImageNotUpdatedYet,\n error,\n}: {\n title: string;\n imgNewBase64: string;\n imgOldBase64: string;\n imgDiffBase64: string;\n wasImageNotUpdatedYet: boolean;\n error: boolean;\n}) => `
\n
\n \n
\n
\n
\n \n

New screenshot (hover mouse away too see the old one):

\n \n
\n

Old screenshot (hover over to see the new one):

\n \n
\n
\n
\n

Diff between new and old screenshot

\n \n
\n
\n
\n`;\n\n/* c8 ignore start */\nbefore(() => {\n if (!top) return null;\n Cypress.$(`.${OVERLAY_CLASS}`, top.document.body).remove();\n});\n\nafter(() => {\n if (!top) return null;\n\n cy.task(TASK.cleanupImages, { log: false });\n\n Cypress.$(top.document.body).on(\n \"click\",\n `a[href^=\"${LINK_PREFIX}\"]`,\n function (e) {\n e.preventDefault();\n if (!top) return false;\n\n const {\n title,\n imgPath,\n imgDiffBase64,\n imgNewBase64,\n imgOldBase64,\n error,\n } = JSON.parse(\n decodeURIComponent(\n Base64.decode(\n e.currentTarget.getAttribute(\"href\").substring(LINK_PREFIX.length)\n )\n )\n );\n queueClear();\n\n cy.task(\n TASK.doesFileExist,\n { path: imgPath },\n { log: false }\n ).then((wasImageNotUpdatedYet) => {\n if (!top) return false;\n queueClear();\n\n Cypress.$(\n generateOverlayTemplate({\n title,\n imgNewBase64,\n imgOldBase64,\n imgDiffBase64,\n error,\n wasImageNotUpdatedYet,\n })\n ).appendTo(top.document.body);\n\n const wrapper = Cypress.$(`.${OVERLAY_CLASS}`, top.document.body);\n wrapper.on(\"click\", 'button[data-type=\"close\"]', function () {\n wrapper.remove();\n });\n\n wrapper.on(\"submit\", \"form\", function (e) {\n e.preventDefault();\n\n cy.task(TASK.approveImage, { img: imgPath }).then(() =>\n wrapper.remove()\n );\n\n queueRun();\n });\n });\n\n queueRun();\n\n return false;\n }\n );\n});\n/* c8 ignore stop */\n"],"names":["PLUGIN_NAME","LINK_PREFIX","OVERLAY_CLASS","FILE_SUFFIX","TASK","getScreenshotPathInfo","compareImages","approveImage","cleanupImages","doesFileExist","runAfterScreenshotHook","constructCypressError","log","err","onFail","error","getImagesDir","options","imagesDir","Cypress","env","console","warn","getConfig","scaleFactor","window","devicePixelRatio","updateImages","imagesPath","maxDiffThreshold","diffConfig","screenshotConfig","remoteScreenshotServiceUrl","Commands","add","prevSubject","subject","$el","title","cy","then","task","titleFromOptions","currentTest","titlePath","join","specPath","spec","relative","screenshotPath","titleFromTask","document","doc","request","url","method","encoding","body","html","parentElement","innerHTML","response","writeFile","path","name","imgPath","wrap","screenshot","onAfterScreenshot","el","props","imgNew","imgOld","replace","actual","res","displayName","set","Error","message","imgDiffBase64","imgNewBase64","imgOldBase64","Base64","encode","encodeURIComponent","JSON","stringify","queueClear","queue","clear","state","queueRun","run","generateOverlayTemplate","wasImageNotUpdatedYet","before","top","$","remove","after","on","e","preventDefault","parse","decodeURIComponent","decode","currentTarget","getAttribute","substring","length","appendTo","wrapper","img"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"support.mjs","sources":["../src/constants.ts","../src/commands.ts","../src/support.ts"],"sourcesContent":["const PLUGIN_NAME = \"cp-visual-regression-diff\";\nexport const LINK_PREFIX = `#${PLUGIN_NAME}-`;\nexport const OVERLAY_CLASS = `${PLUGIN_NAME}-overlay`;\nexport const IMAGE_SNAPSHOT_PREFIX = `__${PLUGIN_NAME}_snapshots__`;\n\nexport enum FILE_SUFFIX {\n diff = \".diff\",\n actual = \".actual\",\n}\n\nexport const TASK = {\n getScreenshotPathInfo: `${PLUGIN_NAME}-getScreenshotPathInfo`,\n compareImages: `${PLUGIN_NAME}-compareImages`,\n approveImage: `${PLUGIN_NAME}-approveImage`,\n cleanupImages: `${PLUGIN_NAME}-cleanupImages`,\n doesFileExist: `${PLUGIN_NAME}-doesFileExist`,\n runAfterScreenshotHook: `${PLUGIN_NAME}-runAfterScreenshotHook`,\n /* c8 ignore next */\n};\n\nexport const PATH_VARIABLES = {\n specPath: \"{spec_path}\",\n unixSystemRootPath: \"{unix_system_root_path}\",\n winSystemRootPath: \"{win_system_root_path}\",\n} as const;\n\nexport const WINDOWS_LIKE_DRIVE_REGEX = /^[A-Z]:$/;\n\nexport const METADATA_KEY = \"FRSOURCE_CPVRD_V\";\n","import { FILE_SUFFIX, LINK_PREFIX, TASK } from \"./constants\";\nimport type pixelmatch from \"pixelmatch\";\nimport * as Base64 from \"@frsource/base64\";\nimport type { CompareImagesTaskReturn } from \"./types\";\n\ndeclare global {\n // eslint-disable-next-line @typescript-eslint/no-namespace\n namespace Cypress {\n type MatchImageOptions = {\n screenshotConfig?: Partial;\n remoteScreenshotServiceUrl?: string;\n diffConfig?: Parameters[5];\n updateImages?: boolean;\n /**\n * @deprecated since version 3.0, use imagesPath instead\n */\n imagesDir?: string;\n imagesPath?: string;\n maxDiffThreshold?: number;\n title?: string;\n matchAgainstPath?: string;\n // IDEA: to be implemented if support for files NOT from filesystem needed\n // matchAgainst?: string | Buffer;\n };\n\n type MatchImageReturn = {\n diffValue: number | undefined;\n imgNewPath: string;\n imgPath: string;\n imgDiffPath: string;\n imgNewBase64: string | undefined;\n imgBase64: string | undefined;\n imgDiffBase64: string | undefined;\n imgNew: InstanceType | undefined;\n img: InstanceType | undefined;\n imgDiff: InstanceType | undefined;\n };\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n interface Chainable {\n /**\n * Command to create and compare image snapshots.\n * @memberof Cypress.Chainable\n * @example cy.get('.my-element').matchImage();\n */\n matchImage(\n options?: Cypress.MatchImageOptions\n ): Chainable;\n }\n }\n}\n\nconst constructCypressError = (log: Cypress.Log, err: Error) => {\n // only way to throw & log the message properly in Cypress\n // https://github.com/cypress-io/cypress/blob/5f94cad3cb4126e0567290b957050c33e3a78e3c/packages/driver/src/cypress/error_utils.ts#L214-L216\n (err as unknown as { onFail: (e: Error) => void }).onFail = (err: Error) =>\n log.error(err);\n return err;\n};\n\nconst getImagesDir = (options: Cypress.MatchImageOptions) => {\n const imagesDir =\n options.imagesDir ||\n (Cypress.env(\"pluginVisualRegressionImagesDir\") as string | undefined);\n\n // TODO: remove in 4.0.0\n if (imagesDir) {\n console.warn(\n \"@frsource/cypress-plugin-visual-regression-diff] `imagesDir` option is deprecated, use `imagesPath` instead (https://github.com/FRSOURCE/cypress-plugin-visual-regression-diff#configuration)\"\n );\n }\n\n return imagesDir;\n};\n\nexport const getConfig = (options: Cypress.MatchImageOptions) => {\n const imagesDir = getImagesDir(options);\n\n return {\n scaleFactor:\n Cypress.env(\"pluginVisualRegressionForceDeviceScaleFactor\") === false\n ? 1\n : 1 / window.devicePixelRatio,\n updateImages:\n options.updateImages ||\n (Cypress.env(\"pluginVisualRegressionUpdateImages\") as\n | boolean\n | undefined) ||\n false,\n imagesPath:\n (imagesDir && `{spec_path}/${imagesDir}`) ||\n options.imagesPath ||\n (Cypress.env(\"pluginVisualRegressionImagesPath\") as string | undefined) ||\n \"{spec_path}/__image_snapshots__\",\n maxDiffThreshold:\n options.maxDiffThreshold ||\n (Cypress.env(\"pluginVisualRegressionMaxDiffThreshold\") as\n | number\n | undefined) ||\n 0.01,\n diffConfig:\n options.diffConfig ||\n (Cypress.env(\"pluginVisualRegressionDiffConfig\") as\n | Parameters[5]\n | undefined) ||\n {},\n screenshotConfig:\n options.screenshotConfig ||\n (Cypress.env(\"pluginVisualRegressionScreenshotConfig\") as\n | Partial\n | undefined) ||\n {},\n remoteScreenshotServiceUrl:\n options.remoteScreenshotServiceUrl ||\n (Cypress.env(\"pluginVisualRegressionRemoteScreenshotServiceUrl\") as\n | string\n | undefined),\n matchAgainstPath: options.matchAgainstPath || undefined,\n };\n};\n\nCypress.Commands.add(\n \"matchImage\",\n { prevSubject: \"optional\" },\n (subject, options = {}) => {\n const $el = subject as JQuery | undefined;\n let title: string;\n\n const {\n scaleFactor,\n updateImages,\n imagesPath,\n maxDiffThreshold,\n diffConfig,\n screenshotConfig,\n remoteScreenshotServiceUrl,\n matchAgainstPath,\n } = getConfig(options);\n\n const currentRetryNumber = (\n cy as unknown as { state: (s: string) => { currentRetry: () => number } }\n )\n .state(\"test\")\n .currentRetry();\n\n return cy\n .then(() =>\n cy.task<{ screenshotPath: string; title: string }>(\n TASK.getScreenshotPathInfo,\n {\n titleFromOptions:\n options.title || Cypress.currentTest.titlePath.join(\" \"),\n imagesPath,\n specPath: Cypress.spec.relative,\n currentRetryNumber,\n },\n { log: false }\n )\n )\n .then(({ screenshotPath, title: titleFromTask }) => {\n title = titleFromTask;\n\n if (remoteScreenshotServiceUrl) {\n return cy.document().then((doc) => {\n return cy\n .request({\n url: remoteScreenshotServiceUrl,\n method: \"POST\",\n encoding: \"binary\",\n body: {\n html: $el?.html() || doc.body.parentElement?.innerHTML,\n },\n } as Cypress.RequestOptions)\n .then((response) => {\n return cy\n .writeFile(screenshotPath as string, response.body, \"binary\")\n .task<{ path: string }>(TASK.runAfterScreenshotHook, {\n path: screenshotPath,\n name: screenshotPath,\n });\n })\n .then(({ path }) => path);\n });\n } else {\n let imgPath: string;\n return ($el ? cy.wrap($el) : cy)\n .screenshot(screenshotPath, {\n ...screenshotConfig,\n onAfterScreenshot(el, props) {\n imgPath = props.path;\n screenshotConfig.onAfterScreenshot?.(el, props);\n },\n log: false,\n })\n .then(() => imgPath);\n }\n })\n .then((imgPath) =>\n cy\n .task(\n TASK.compareImages,\n {\n scaleFactor,\n imgNew: imgPath,\n imgOld:\n matchAgainstPath || imgPath.replace(FILE_SUFFIX.actual, \"\"),\n updateImages,\n maxDiffThreshold,\n diffConfig,\n },\n { log: false }\n )\n .then((res) => ({\n res,\n imgPath,\n }))\n )\n .then(({ res, imgPath }) => {\n const log = Cypress.log({\n name: \"log\",\n displayName: \"Match image\",\n $el,\n });\n\n if (!res) {\n log.set(\"message\", \"Unexpected error!\");\n throw constructCypressError(log, new Error(\"Unexpected error!\"));\n }\n\n log.set(\n \"message\",\n `${res.message}${\n res.imgDiffBase64 && res.imgNewBase64 && res.imgOldBase64\n ? `\\n[See comparison](${LINK_PREFIX}${Base64.encode(\n encodeURIComponent(\n JSON.stringify({\n title,\n imgPath,\n imgDiffBase64: res.imgDiffBase64,\n imgNewBase64: res.imgNewBase64,\n imgOldBase64: res.imgOldBase64,\n error: res.error,\n })\n )\n )})`\n : \"\"\n }`\n );\n\n if (res.error) {\n log.set(\"consoleProps\", () => res);\n throw constructCypressError(log, new Error(res.message));\n }\n\n return {\n diffValue: res.imgDiff,\n imgNewPath: imgPath,\n imgPath: imgPath.replace(FILE_SUFFIX.actual, \"\"),\n imgDiffPath: imgPath.replace(FILE_SUFFIX.actual, FILE_SUFFIX.diff),\n imgNewBase64: res.imgNewBase64,\n imgBase64: res.imgOldBase64,\n imgDiffBase64: res.imgDiffBase64,\n imgNew:\n typeof res.imgNewBase64 === \"string\"\n ? Cypress.Buffer.from(res.imgNewBase64, \"base64\")\n : undefined,\n img:\n typeof res.imgOldBase64 === \"string\"\n ? Cypress.Buffer.from(res.imgOldBase64, \"base64\")\n : undefined,\n imgDiff:\n typeof res.imgDiffBase64 === \"string\"\n ? Cypress.Buffer.from(res.imgDiffBase64, \"base64\")\n : undefined,\n };\n });\n }\n);\n","import * as Base64 from \"@frsource/base64\";\nimport \"./commands\";\nimport { LINK_PREFIX, OVERLAY_CLASS, TASK } from \"./constants\";\n\n/* c8 ignore start */\nfunction queueClear() {\n (cy as unknown as { queue: { clear: () => void } }).queue.clear();\n (cy as unknown as { state: (k: string, value: unknown) => void }).state(\n \"index\",\n 0\n );\n}\n\nfunction queueRun() {\n // needed to run a task outside of the test processing flow\n (cy as unknown as { queue: { run: () => void } }).queue.run();\n}\n/* c8 ignore stop */\nexport const generateOverlayTemplate = ({\n title,\n imgNewBase64,\n imgOldBase64,\n imgDiffBase64,\n wasImageNotUpdatedYet,\n error,\n}: {\n title: string;\n imgNewBase64: string;\n imgOldBase64: string;\n imgDiffBase64: string;\n wasImageNotUpdatedYet: boolean;\n error: boolean;\n}) => `
\n
\n \n
\n
\n
\n \n

New screenshot (hover mouse away too see the old one):

\n \n
\n

Old screenshot (hover over to see the new one):

\n \n
\n
\n
\n

Diff between new and old screenshot

\n \n
\n
\n
\n`;\n\n/* c8 ignore start */\nbefore(() => {\n if (!top) return null;\n Cypress.$(`.${OVERLAY_CLASS}`, top.document.body).remove();\n});\n\nafter(() => {\n if (!top) return null;\n\n cy.task(TASK.cleanupImages, { log: false });\n\n Cypress.$(top.document.body).on(\n \"click\",\n `a[href^=\"${LINK_PREFIX}\"]`,\n function (e) {\n e.preventDefault();\n if (!top) return false;\n\n const {\n title,\n imgPath,\n imgDiffBase64,\n imgNewBase64,\n imgOldBase64,\n error,\n } = JSON.parse(\n decodeURIComponent(\n Base64.decode(\n e.currentTarget.getAttribute(\"href\").substring(LINK_PREFIX.length)\n )\n )\n );\n queueClear();\n\n cy.task(\n TASK.doesFileExist,\n { path: imgPath },\n { log: false }\n ).then((wasImageNotUpdatedYet) => {\n if (!top) return false;\n queueClear();\n\n Cypress.$(\n generateOverlayTemplate({\n title,\n imgNewBase64,\n imgOldBase64,\n imgDiffBase64,\n error,\n wasImageNotUpdatedYet,\n })\n ).appendTo(top.document.body);\n\n const wrapper = Cypress.$(`.${OVERLAY_CLASS}`, top.document.body);\n wrapper.on(\"click\", 'button[data-type=\"close\"]', function () {\n wrapper.remove();\n });\n\n wrapper.on(\"submit\", \"form\", function (e) {\n e.preventDefault();\n\n cy.task(TASK.approveImage, { img: imgPath }).then(() =>\n wrapper.remove()\n );\n\n queueRun();\n });\n });\n\n queueRun();\n\n return false;\n }\n );\n});\n/* c8 ignore stop */\n"],"names":["PLUGIN_NAME","LINK_PREFIX","OVERLAY_CLASS","FILE_SUFFIX","TASK","getScreenshotPathInfo","compareImages","approveImage","cleanupImages","doesFileExist","runAfterScreenshotHook","constructCypressError","log","err","onFail","error","getImagesDir","options","imagesDir","Cypress","env","console","warn","getConfig","scaleFactor","window","devicePixelRatio","updateImages","imagesPath","maxDiffThreshold","diffConfig","screenshotConfig","remoteScreenshotServiceUrl","matchAgainstPath","undefined","Commands","add","prevSubject","subject","$el","title","currentRetryNumber","cy","state","currentRetry","then","task","titleFromOptions","currentTest","titlePath","join","specPath","spec","relative","screenshotPath","titleFromTask","document","doc","request","url","method","encoding","body","html","parentElement","innerHTML","response","writeFile","path","name","imgPath","wrap","screenshot","onAfterScreenshot","el","props","imgNew","imgOld","replace","actual","res","displayName","set","Error","message","imgDiffBase64","imgNewBase64","imgOldBase64","Base64","encode","encodeURIComponent","JSON","stringify","diffValue","imgDiff","imgNewPath","imgDiffPath","diff","imgBase64","Buffer","from","img","queueClear","queue","clear","queueRun","run","generateOverlayTemplate","wasImageNotUpdatedYet","before","top","$","remove","after","on","e","preventDefault","parse","decodeURIComponent","decode","currentTarget","getAttribute","substring","length","appendTo","wrapper"],"mappings":"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"} \ No newline at end of file