Skip to content

Commit 2aef358

Browse files
authored
feat: createMissingImages option (#222)
update tests simplify task.hook code relates #204
1 parent af71297 commit 2aef358

File tree

5 files changed

+62
-18
lines changed

5 files changed

+62
-18
lines changed

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,9 @@ cy.matchImage({
179179
diffConfig: {
180180
threshold: 0.01,
181181
},
182+
// whether to create missing baseline images automatically
183+
// default: true
184+
createMissingImages: false,
182185
// whether to update images automatically, without making a diff - useful for CI
183186
// default: false
184187
updateImages: true,

src/__snapshots__/task.hook.test.ts.snap

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.

src/commands.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ declare global {
99
type MatchImageOptions = {
1010
screenshotConfig?: Partial<Cypress.ScreenshotDefaultsOptions>;
1111
diffConfig?: Parameters<typeof pixelmatch>[5];
12+
createMissingImages?: boolean;
1213
updateImages?: boolean;
1314
/**
1415
* @deprecated since version 3.0, use imagesPath instead
@@ -87,6 +88,12 @@ export const getConfig = (options: Cypress.MatchImageOptions) => {
8788
Cypress.env("pluginVisualRegressionForceDeviceScaleFactor") === false
8889
? 1
8990
: 1 / window.devicePixelRatio,
91+
createMissingImages:
92+
options.createMissingImages ||
93+
(Cypress.env("pluginVisualRegressionCreateMissingImages") as
94+
| boolean
95+
| undefined) ||
96+
true,
9097
updateImages:
9198
options.updateImages ||
9299
(Cypress.env("pluginVisualRegressionUpdateImages") as
@@ -125,6 +132,7 @@ Cypress.Commands.add(
125132

126133
const {
127134
scaleFactor,
135+
createMissingImages,
128136
updateImages,
129137
imagesPath,
130138
maxDiffThreshold,
@@ -178,6 +186,7 @@ Cypress.Commands.add(
178186
imgNew: imgPath,
179187
imgOld:
180188
matchAgainstPath || imgPath.replace(FILE_SUFFIX.actual, ""),
189+
createMissingImages,
181190
updateImages,
182191
maxDiffThreshold,
183192
diffConfig,

src/task.hook.test.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ const newFileContent = "new file content";
2222

2323
const generateConfig = async (cfg: Partial<CompareImagesCfg>) => ({
2424
updateImages: false,
25+
createMissingImages: true,
2526
scaleFactor: 1,
2627
title: "some title",
2728
imgNew: await writeTmpFixture((await file()).path, newImgFixture),
@@ -48,6 +49,7 @@ describe("getScreenshotPathInfoTask", () => {
4849
titleFromOptions: "some-title-withśpęćiał人物",
4950
imagesPath: "nested/images/dir",
5051
specPath,
52+
currentRetryNumber: 0,
5153
})
5254
).toEqual({
5355
screenshotPath:
@@ -62,6 +64,7 @@ describe("getScreenshotPathInfoTask", () => {
6264
titleFromOptions: "some-title",
6365
imagesPath: "{spec_path}/images/dir",
6466
specPath,
67+
currentRetryNumber: 0,
6568
})
6669
).toEqual({
6770
screenshotPath:
@@ -76,6 +79,7 @@ describe("getScreenshotPathInfoTask", () => {
7679
titleFromOptions: "some-title",
7780
imagesPath: "/images/dir",
7881
specPath,
82+
currentRetryNumber: 0,
7983
})
8084
).toEqual({
8185
screenshotPath:
@@ -88,6 +92,7 @@ describe("getScreenshotPathInfoTask", () => {
8892
titleFromOptions: "some-title",
8993
imagesPath: "C:/images/dir",
9094
specPath,
95+
currentRetryNumber: 0,
9196
})
9297
).toEqual({
9398
screenshotPath:
@@ -104,6 +109,7 @@ describe("cleanupImagesTask", () => {
104109
titleFromOptions: "some-file",
105110
imagesPath: "images",
106111
specPath: "some/spec/path",
112+
currentRetryNumber: 0,
107113
});
108114
return path.join(
109115
projectRoot,
@@ -180,6 +186,7 @@ describe("compareImagesTask", () => {
180186
expect(
181187
compareImagesTask(await generateConfig({ updateImages: true }))
182188
).resolves.toEqual({
189+
error: false,
183190
message:
184191
"Image diff factor (0%) is within boundaries of maximum threshold option 0.5.",
185192
imgDiff: 0,
@@ -198,6 +205,7 @@ describe("compareImagesTask", () => {
198205
await fs.unlink(cfg.imgOld);
199206

200207
await expect(compareImagesTask(cfg)).resolves.toEqual({
208+
error: false,
201209
message:
202210
"Image diff factor (0%) is within boundaries of maximum threshold option 0.5.",
203211
imgDiff: 0,
@@ -207,6 +215,26 @@ describe("compareImagesTask", () => {
207215
maxDiffThreshold: 0.5,
208216
});
209217
});
218+
219+
describe("when createMissingImages=false", () => {
220+
it("rejects with error message", async () => {
221+
const cfg = await generateConfig({
222+
updateImages: false,
223+
createMissingImages: false,
224+
});
225+
await fs.unlink(cfg.imgOld);
226+
227+
await expect(compareImagesTask(cfg)).resolves.toEqual({
228+
error: true,
229+
message: `Baseline image is missing at path: "${cfg.imgOld}". Provide a baseline image or enable "createMissingImages" option in plugin configuration.`,
230+
imgDiff: 0,
231+
imgDiffBase64: "",
232+
imgNewBase64: "",
233+
imgOldBase64: "",
234+
maxDiffThreshold: 0.5,
235+
});
236+
});
237+
});
210238
});
211239

212240
describe("when old screenshot exists", () => {

src/task.hook.ts

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ export type CompareImagesCfg = {
2222
title: string;
2323
imgNew: string;
2424
imgOld: string;
25+
createMissingImages: boolean;
2526
updateImages: boolean;
2627
maxDiffThreshold: number;
2728
diffConfig: PixelmatchOptions;
@@ -130,15 +131,6 @@ export const compareImagesTask = async (
130131
cfg.imgNew.replace(FILE_SUFFIX.actual, FILE_SUFFIX.diff),
131132
diffBuffer
132133
);
133-
return {
134-
error,
135-
message: messages.join("\n"),
136-
imgDiff,
137-
imgNewBase64,
138-
imgDiffBase64,
139-
imgOldBase64,
140-
maxDiffThreshold: cfg.maxDiffThreshold,
141-
};
142134
} else {
143135
if (rawImgOld && !isImageCurrentVersion(rawImgOldBuffer)) {
144136
writePNG(cfg.imgNew, rawImgNewBuffer);
@@ -154,19 +146,30 @@ export const compareImagesTask = async (
154146
imgNewBase64 = "";
155147
imgDiffBase64 = "";
156148
imgOldBase64 = "";
157-
writePNG(cfg.imgNew, rawImgNewBuffer);
158-
moveFile.sync(cfg.imgNew, cfg.imgOld);
149+
if (cfg.createMissingImages) {
150+
writePNG(cfg.imgNew, rawImgNewBuffer);
151+
moveFile.sync(cfg.imgNew, cfg.imgOld);
152+
} else {
153+
error = true;
154+
messages.unshift(
155+
`Baseline image is missing at path: "${cfg.imgOld}". Provide a baseline image or enable "createMissingImages" option in plugin configuration.`
156+
);
157+
}
159158
}
160159

161160
if (typeof imgDiff !== "undefined") {
162-
messages.unshift(
163-
`Image diff factor (${round(
164-
imgDiff
165-
)}%) is within boundaries of maximum threshold option ${
166-
cfg.maxDiffThreshold
167-
}.`
168-
);
161+
if (!error) {
162+
messages.unshift(
163+
`Image diff factor (${round(
164+
imgDiff
165+
)}%) is within boundaries of maximum threshold option ${
166+
cfg.maxDiffThreshold
167+
}.`
168+
);
169+
}
170+
169171
return {
172+
error,
170173
message: messages.join("\n"),
171174
imgDiff,
172175
imgNewBase64,

0 commit comments

Comments
 (0)