First Commit
This commit is contained in:
338
node_modules/playwright/lib/matchers/toMatchSnapshot.js
generated
vendored
Normal file
338
node_modules/playwright/lib/matchers/toMatchSnapshot.js
generated
vendored
Normal file
@@ -0,0 +1,338 @@
|
||||
"use strict";
|
||||
var __create = Object.create;
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __getProtoOf = Object.getPrototypeOf;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
||||
// If the importer is in node compatibility mode or this is not an ESM
|
||||
// file that has been converted to a CommonJS file using a Babel-
|
||||
// compatible transform (i.e. "__esModule" has not been set), then set
|
||||
// "default" to the CommonJS "module.exports" for node compatibility.
|
||||
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
||||
mod
|
||||
));
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
var toMatchSnapshot_exports = {};
|
||||
__export(toMatchSnapshot_exports, {
|
||||
toHaveScreenshot: () => toHaveScreenshot,
|
||||
toHaveScreenshotStepTitle: () => toHaveScreenshotStepTitle,
|
||||
toMatchSnapshot: () => toMatchSnapshot
|
||||
});
|
||||
module.exports = __toCommonJS(toMatchSnapshot_exports);
|
||||
var import_fs = __toESM(require("fs"));
|
||||
var import_path = __toESM(require("path"));
|
||||
var import_utils = require("playwright-core/lib/utils");
|
||||
var import_utils2 = require("playwright-core/lib/utils");
|
||||
var import_utilsBundle = require("playwright-core/lib/utilsBundle");
|
||||
var import_util = require("../util");
|
||||
var import_matcherHint = require("./matcherHint");
|
||||
var import_globals = require("../common/globals");
|
||||
const NonConfigProperties = [
|
||||
"clip",
|
||||
"fullPage",
|
||||
"mask",
|
||||
"maskColor",
|
||||
"omitBackground",
|
||||
"timeout"
|
||||
];
|
||||
class SnapshotHelper {
|
||||
constructor(testInfo, matcherName, locator, anonymousSnapshotExtension, configOptions, nameOrOptions, optOptions) {
|
||||
let name;
|
||||
if (Array.isArray(nameOrOptions) || typeof nameOrOptions === "string") {
|
||||
name = nameOrOptions;
|
||||
this.options = { ...optOptions };
|
||||
} else {
|
||||
const { name: nameFromOptions, ...options } = nameOrOptions;
|
||||
this.options = options;
|
||||
name = nameFromOptions;
|
||||
}
|
||||
this.name = Array.isArray(name) ? name.join(import_path.default.sep) : name || "";
|
||||
const resolvedPaths = testInfo._resolveSnapshotPaths(matcherName === "toHaveScreenshot" ? "screenshot" : "snapshot", name, "updateSnapshotIndex", anonymousSnapshotExtension);
|
||||
this.expectedPath = resolvedPaths.absoluteSnapshotPath;
|
||||
this.attachmentBaseName = resolvedPaths.relativeOutputPath;
|
||||
const outputBasePath = testInfo._getOutputPath(resolvedPaths.relativeOutputPath);
|
||||
this.legacyExpectedPath = (0, import_util.addSuffixToFilePath)(outputBasePath, "-expected");
|
||||
this.previousPath = (0, import_util.addSuffixToFilePath)(outputBasePath, "-previous");
|
||||
this.actualPath = (0, import_util.addSuffixToFilePath)(outputBasePath, "-actual");
|
||||
this.diffPath = (0, import_util.addSuffixToFilePath)(outputBasePath, "-diff");
|
||||
const filteredConfigOptions = { ...configOptions };
|
||||
for (const prop of NonConfigProperties)
|
||||
delete filteredConfigOptions[prop];
|
||||
this.options = {
|
||||
...filteredConfigOptions,
|
||||
...this.options
|
||||
};
|
||||
if (this.options._comparator) {
|
||||
this.options.comparator = this.options._comparator;
|
||||
delete this.options._comparator;
|
||||
}
|
||||
if (this.options.maxDiffPixels !== void 0 && this.options.maxDiffPixels < 0)
|
||||
throw new Error("`maxDiffPixels` option value must be non-negative integer");
|
||||
if (this.options.maxDiffPixelRatio !== void 0 && (this.options.maxDiffPixelRatio < 0 || this.options.maxDiffPixelRatio > 1))
|
||||
throw new Error("`maxDiffPixelRatio` option value must be between 0 and 1");
|
||||
this.matcherName = matcherName;
|
||||
this.locator = locator;
|
||||
this.updateSnapshots = testInfo.config.updateSnapshots;
|
||||
this.mimeType = import_utilsBundle.mime.getType(import_path.default.basename(this.expectedPath)) ?? "application/octet-stream";
|
||||
this.comparator = (0, import_utils.getComparator)(this.mimeType);
|
||||
this.testInfo = testInfo;
|
||||
this.kind = this.mimeType.startsWith("image/") ? "Screenshot" : "Snapshot";
|
||||
}
|
||||
createMatcherResult(message, pass, log) {
|
||||
const unfiltered = {
|
||||
name: this.matcherName,
|
||||
expected: this.expectedPath,
|
||||
actual: this.actualPath,
|
||||
diff: this.diffPath,
|
||||
pass,
|
||||
message: () => message,
|
||||
log
|
||||
};
|
||||
return Object.fromEntries(Object.entries(unfiltered).filter(([_, v]) => v !== void 0));
|
||||
}
|
||||
handleMissingNegated() {
|
||||
const isWriteMissingMode = this.updateSnapshots !== "none";
|
||||
const message = `A snapshot doesn't exist at ${this.expectedPath}${isWriteMissingMode ? `, matchers using ".not" won't write them automatically.` : "."}`;
|
||||
return this.createMatcherResult(message, true);
|
||||
}
|
||||
handleDifferentNegated() {
|
||||
return this.createMatcherResult("", false);
|
||||
}
|
||||
handleMatchingNegated() {
|
||||
const message = [
|
||||
import_utils2.colors.red(`${this.kind} comparison failed:`),
|
||||
"",
|
||||
indent("Expected result should be different from the actual one.", " ")
|
||||
].join("\n");
|
||||
return this.createMatcherResult(message, true);
|
||||
}
|
||||
handleMissing(actual, step) {
|
||||
const isWriteMissingMode = this.updateSnapshots !== "none";
|
||||
if (isWriteMissingMode)
|
||||
writeFileSync(this.expectedPath, actual);
|
||||
step?._attachToStep({ name: (0, import_util.addSuffixToFilePath)(this.attachmentBaseName, "-expected"), contentType: this.mimeType, path: this.expectedPath });
|
||||
writeFileSync(this.actualPath, actual);
|
||||
step?._attachToStep({ name: (0, import_util.addSuffixToFilePath)(this.attachmentBaseName, "-actual"), contentType: this.mimeType, path: this.actualPath });
|
||||
const message = `A snapshot doesn't exist at ${this.expectedPath}${isWriteMissingMode ? ", writing actual." : "."}`;
|
||||
if (this.updateSnapshots === "all" || this.updateSnapshots === "changed") {
|
||||
console.log(message);
|
||||
return this.createMatcherResult(message, true);
|
||||
}
|
||||
if (this.updateSnapshots === "missing") {
|
||||
this.testInfo._hasNonRetriableError = true;
|
||||
this.testInfo._failWithError(new Error(message));
|
||||
return this.createMatcherResult("", true);
|
||||
}
|
||||
return this.createMatcherResult(message, false);
|
||||
}
|
||||
handleDifferent(actual, expected, previous, diff, header, diffError, log, step) {
|
||||
const output = [`${header}${indent(diffError, " ")}`];
|
||||
if (this.name) {
|
||||
output.push("");
|
||||
output.push(` Snapshot: ${this.name}`);
|
||||
}
|
||||
if (expected !== void 0) {
|
||||
writeFileSync(this.legacyExpectedPath, expected);
|
||||
step?._attachToStep({ name: (0, import_util.addSuffixToFilePath)(this.attachmentBaseName, "-expected"), contentType: this.mimeType, path: this.expectedPath });
|
||||
}
|
||||
if (previous !== void 0) {
|
||||
writeFileSync(this.previousPath, previous);
|
||||
step?._attachToStep({ name: (0, import_util.addSuffixToFilePath)(this.attachmentBaseName, "-previous"), contentType: this.mimeType, path: this.previousPath });
|
||||
}
|
||||
if (actual !== void 0) {
|
||||
writeFileSync(this.actualPath, actual);
|
||||
step?._attachToStep({ name: (0, import_util.addSuffixToFilePath)(this.attachmentBaseName, "-actual"), contentType: this.mimeType, path: this.actualPath });
|
||||
}
|
||||
if (diff !== void 0) {
|
||||
writeFileSync(this.diffPath, diff);
|
||||
step?._attachToStep({ name: (0, import_util.addSuffixToFilePath)(this.attachmentBaseName, "-diff"), contentType: this.mimeType, path: this.diffPath });
|
||||
}
|
||||
if (log?.length)
|
||||
output.push((0, import_util.callLogText)(log));
|
||||
else
|
||||
output.push("");
|
||||
return this.createMatcherResult(output.join("\n"), false, log);
|
||||
}
|
||||
handleMatching() {
|
||||
return this.createMatcherResult("", true);
|
||||
}
|
||||
}
|
||||
function toMatchSnapshot(received, nameOrOptions = {}, optOptions = {}) {
|
||||
const testInfo = (0, import_globals.currentTestInfo)();
|
||||
if (!testInfo)
|
||||
throw new Error(`toMatchSnapshot() must be called during the test`);
|
||||
if (received instanceof Promise)
|
||||
throw new Error("An unresolved Promise was passed to toMatchSnapshot(), make sure to resolve it by adding await to it.");
|
||||
if (testInfo._projectInternal.ignoreSnapshots)
|
||||
return { pass: !this.isNot, message: () => "", name: "toMatchSnapshot", expected: nameOrOptions };
|
||||
const configOptions = testInfo._projectInternal.expect?.toMatchSnapshot || {};
|
||||
const helper = new SnapshotHelper(
|
||||
testInfo,
|
||||
"toMatchSnapshot",
|
||||
void 0,
|
||||
"." + determineFileExtension(received),
|
||||
configOptions,
|
||||
nameOrOptions,
|
||||
optOptions
|
||||
);
|
||||
if (this.isNot) {
|
||||
if (!import_fs.default.existsSync(helper.expectedPath))
|
||||
return helper.handleMissingNegated();
|
||||
const isDifferent = !!helper.comparator(received, import_fs.default.readFileSync(helper.expectedPath), helper.options);
|
||||
return isDifferent ? helper.handleDifferentNegated() : helper.handleMatchingNegated();
|
||||
}
|
||||
if (!import_fs.default.existsSync(helper.expectedPath))
|
||||
return helper.handleMissing(received, this._stepInfo);
|
||||
const expected = import_fs.default.readFileSync(helper.expectedPath);
|
||||
if (helper.updateSnapshots === "all") {
|
||||
if (!(0, import_utils.compareBuffersOrStrings)(received, expected))
|
||||
return helper.handleMatching();
|
||||
writeFileSync(helper.expectedPath, received);
|
||||
console.log(helper.expectedPath + " is not the same, writing actual.");
|
||||
return helper.createMatcherResult(helper.expectedPath + " running with --update-snapshots, writing actual.", true);
|
||||
}
|
||||
if (helper.updateSnapshots === "changed") {
|
||||
const result2 = helper.comparator(received, expected, helper.options);
|
||||
if (!result2)
|
||||
return helper.handleMatching();
|
||||
writeFileSync(helper.expectedPath, received);
|
||||
console.log(helper.expectedPath + " does not match, writing actual.");
|
||||
return helper.createMatcherResult(helper.expectedPath + " running with --update-snapshots, writing actual.", true);
|
||||
}
|
||||
const result = helper.comparator(received, expected, helper.options);
|
||||
if (!result)
|
||||
return helper.handleMatching();
|
||||
const receiver = (0, import_utils.isString)(received) ? "string" : "Buffer";
|
||||
const header = (0, import_matcherHint.matcherHint)(this, void 0, "toMatchSnapshot", receiver, void 0, void 0, void 0);
|
||||
return helper.handleDifferent(received, expected, void 0, result.diff, header, result.errorMessage, void 0, this._stepInfo);
|
||||
}
|
||||
function toHaveScreenshotStepTitle(nameOrOptions = {}, optOptions = {}) {
|
||||
let name;
|
||||
if (typeof nameOrOptions === "object" && !Array.isArray(nameOrOptions))
|
||||
name = nameOrOptions.name;
|
||||
else
|
||||
name = nameOrOptions;
|
||||
return Array.isArray(name) ? name.join(import_path.default.sep) : name || "";
|
||||
}
|
||||
async function toHaveScreenshot(pageOrLocator, nameOrOptions = {}, optOptions = {}) {
|
||||
const testInfo = (0, import_globals.currentTestInfo)();
|
||||
if (!testInfo)
|
||||
throw new Error(`toHaveScreenshot() must be called during the test`);
|
||||
if (testInfo._projectInternal.ignoreSnapshots)
|
||||
return { pass: !this.isNot, message: () => "", name: "toHaveScreenshot", expected: nameOrOptions };
|
||||
(0, import_util.expectTypes)(pageOrLocator, ["Page", "Locator"], "toHaveScreenshot");
|
||||
const [page, locator] = pageOrLocator.constructor.name === "Page" ? [pageOrLocator, void 0] : [pageOrLocator.page(), pageOrLocator];
|
||||
const configOptions = testInfo._projectInternal.expect?.toHaveScreenshot || {};
|
||||
const helper = new SnapshotHelper(testInfo, "toHaveScreenshot", locator, void 0, configOptions, nameOrOptions, optOptions);
|
||||
if (!helper.expectedPath.toLowerCase().endsWith(".png"))
|
||||
throw new Error(`Screenshot name "${import_path.default.basename(helper.expectedPath)}" must have '.png' extension`);
|
||||
(0, import_util.expectTypes)(pageOrLocator, ["Page", "Locator"], "toHaveScreenshot");
|
||||
const style = await loadScreenshotStyles(helper.options.stylePath);
|
||||
const timeout = helper.options.timeout ?? this.timeout;
|
||||
const expectScreenshotOptions = {
|
||||
locator,
|
||||
animations: helper.options.animations ?? "disabled",
|
||||
caret: helper.options.caret ?? "hide",
|
||||
clip: helper.options.clip,
|
||||
fullPage: helper.options.fullPage,
|
||||
mask: helper.options.mask,
|
||||
maskColor: helper.options.maskColor,
|
||||
omitBackground: helper.options.omitBackground,
|
||||
scale: helper.options.scale ?? "css",
|
||||
style,
|
||||
isNot: !!this.isNot,
|
||||
timeout,
|
||||
comparator: helper.options.comparator,
|
||||
maxDiffPixels: helper.options.maxDiffPixels,
|
||||
maxDiffPixelRatio: helper.options.maxDiffPixelRatio,
|
||||
threshold: helper.options.threshold
|
||||
};
|
||||
const hasSnapshot = import_fs.default.existsSync(helper.expectedPath);
|
||||
if (this.isNot) {
|
||||
if (!hasSnapshot)
|
||||
return helper.handleMissingNegated();
|
||||
expectScreenshotOptions.expected = await import_fs.default.promises.readFile(helper.expectedPath);
|
||||
const isDifferent = !(await page._expectScreenshot(expectScreenshotOptions)).errorMessage;
|
||||
return isDifferent ? helper.handleDifferentNegated() : helper.handleMatchingNegated();
|
||||
}
|
||||
if (helper.updateSnapshots === "none" && !hasSnapshot)
|
||||
return helper.createMatcherResult(`A snapshot doesn't exist at ${helper.expectedPath}.`, false);
|
||||
const receiver = locator ? "locator" : "page";
|
||||
if (!hasSnapshot) {
|
||||
const { actual: actual2, previous: previous2, diff: diff2, errorMessage: errorMessage2, log: log2, timedOut: timedOut2 } = await page._expectScreenshot(expectScreenshotOptions);
|
||||
if (errorMessage2) {
|
||||
const header2 = (0, import_matcherHint.matcherHint)(this, locator, "toHaveScreenshot", receiver, void 0, void 0, timedOut2 ? timeout : void 0);
|
||||
return helper.handleDifferent(actual2, void 0, previous2, diff2, header2, errorMessage2, log2, this._stepInfo);
|
||||
}
|
||||
return helper.handleMissing(actual2, this._stepInfo);
|
||||
}
|
||||
const expected = await import_fs.default.promises.readFile(helper.expectedPath);
|
||||
expectScreenshotOptions.expected = helper.updateSnapshots === "all" ? void 0 : expected;
|
||||
const { actual, previous, diff, errorMessage, log, timedOut } = await page._expectScreenshot(expectScreenshotOptions);
|
||||
const writeFiles = () => {
|
||||
writeFileSync(helper.expectedPath, actual);
|
||||
writeFileSync(helper.actualPath, actual);
|
||||
console.log(helper.expectedPath + " is re-generated, writing actual.");
|
||||
return helper.createMatcherResult(helper.expectedPath + " running with --update-snapshots, writing actual.", true);
|
||||
};
|
||||
if (!errorMessage) {
|
||||
if (helper.updateSnapshots === "all" && actual && (0, import_utils.compareBuffersOrStrings)(actual, expected)) {
|
||||
console.log(helper.expectedPath + " is re-generated, writing actual.");
|
||||
return writeFiles();
|
||||
}
|
||||
return helper.handleMatching();
|
||||
}
|
||||
if (helper.updateSnapshots === "changed" || helper.updateSnapshots === "all")
|
||||
return writeFiles();
|
||||
const header = (0, import_matcherHint.matcherHint)(this, void 0, "toHaveScreenshot", receiver, void 0, void 0, timedOut ? timeout : void 0);
|
||||
return helper.handleDifferent(actual, expectScreenshotOptions.expected, previous, diff, header, errorMessage, log, this._stepInfo);
|
||||
}
|
||||
function writeFileSync(aPath, content) {
|
||||
import_fs.default.mkdirSync(import_path.default.dirname(aPath), { recursive: true });
|
||||
import_fs.default.writeFileSync(aPath, content);
|
||||
}
|
||||
function indent(lines, tab) {
|
||||
return lines.replace(/^(?=.+$)/gm, tab);
|
||||
}
|
||||
function determineFileExtension(file) {
|
||||
if (typeof file === "string")
|
||||
return "txt";
|
||||
if (compareMagicBytes(file, [137, 80, 78, 71, 13, 10, 26, 10]))
|
||||
return "png";
|
||||
if (compareMagicBytes(file, [255, 216, 255]))
|
||||
return "jpg";
|
||||
return "dat";
|
||||
}
|
||||
function compareMagicBytes(file, magicBytes) {
|
||||
return Buffer.compare(Buffer.from(magicBytes), file.slice(0, magicBytes.length)) === 0;
|
||||
}
|
||||
async function loadScreenshotStyles(stylePath) {
|
||||
if (!stylePath)
|
||||
return;
|
||||
const stylePaths = Array.isArray(stylePath) ? stylePath : [stylePath];
|
||||
const styles = await Promise.all(stylePaths.map(async (stylePath2) => {
|
||||
const text = await import_fs.default.promises.readFile(stylePath2, "utf8");
|
||||
return text.trim();
|
||||
}));
|
||||
return styles.join("\n").trim() || void 0;
|
||||
}
|
||||
// Annotate the CommonJS export names for ESM import in node:
|
||||
0 && (module.exports = {
|
||||
toHaveScreenshot,
|
||||
toHaveScreenshotStepTitle,
|
||||
toMatchSnapshot
|
||||
});
|
Reference in New Issue
Block a user