Skip to content

Commit c09bab3

Browse files
authored
feat: show comparison for successful tests (#137)
start using base64 images in comparison modal fix topbar text styling remove unused cachedReadFile method extract common typings resolves #104
1 parent 0639c8a commit c09bab3

File tree

4 files changed

+59
-79
lines changed

4 files changed

+59
-79
lines changed

src/commands.ts

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { FILE_SUFFIX, LINK_PREFIX, TASK } from "./constants";
22
import type pixelmatch from "pixelmatch";
33
import * as Base64 from "@frsource/base64";
4+
import type { CompareImagesTaskReturn } from "./types";
45

56
declare global {
67
// eslint-disable-next-line @typescript-eslint/no-namespace
@@ -116,7 +117,7 @@ Cypress.Commands.add(
116117
})
117118
.then((imgPath) =>
118119
cy
119-
.task(
120+
.task<CompareImagesTaskReturn>(
120121
TASK.compareImages,
121122
{
122123
scaleFactor,
@@ -129,12 +130,7 @@ Cypress.Commands.add(
129130
{ log: false }
130131
)
131132
.then((res) => ({
132-
res: res as null | {
133-
error?: boolean;
134-
message?: string;
135-
imgDiff?: number;
136-
maxDiffThreshold?: number;
137-
},
133+
res,
138134
imgPath,
139135
}))
140136
)
@@ -150,22 +146,29 @@ Cypress.Commands.add(
150146
throw constructCypressError(log, new Error("Unexpected error!"));
151147
}
152148

149+
log.set(
150+
"message",
151+
`${res.message}${
152+
res.imgDiffBase64 && res.imgNewBase64 && res.imgOldBase64
153+
? `\n[See comparison](${LINK_PREFIX}${Base64.encode(
154+
encodeURIComponent(
155+
JSON.stringify({
156+
title,
157+
imgPath,
158+
imgDiffBase64: res.imgDiffBase64,
159+
imgNewBase64: res.imgNewBase64,
160+
imgOldBase64: res.imgOldBase64,
161+
error: res.error
162+
})
163+
)
164+
)})`
165+
: ''
166+
}`
167+
);
168+
153169
if (res.error) {
154-
log.set(
155-
"message",
156-
`${res.message}\n[See comparison](${LINK_PREFIX}${Base64.encode(
157-
encodeURIComponent(
158-
JSON.stringify({
159-
title,
160-
imgPath,
161-
})
162-
)
163-
)})`
164-
);
165170
log.set("consoleProps", () => res);
166171
throw constructCypressError(log, new Error(res.message));
167-
} else {
168-
log.set("message", res.message);
169172
}
170173
});
171174
}

src/support.ts

Lines changed: 9 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -22,21 +22,23 @@ export const generateOverlayTemplate = ({
2222
imgOldBase64,
2323
imgDiffBase64,
2424
wasImageNotUpdatedYet,
25+
error,
2526
}: {
2627
title: string;
2728
imgNewBase64: string;
2829
imgOldBase64: string;
2930
imgDiffBase64: string;
3031
wasImageNotUpdatedYet: boolean;
32+
error: boolean
3133
}) => `<div class="${OVERLAY_CLASS} runner" style="position:fixed;z-index:10;top:0;bottom:0;left:0;right:0;display:flex;flex-flow:column">
3234
<header style="position:static">
3335
<nav style="display:flex;width:100%;align-items:center;justify-content:space-between;padding:10px 15px;">
3436
<h2>${title} - screenshot diff</h2>
35-
<form>
37+
<form style="display:flex;align-items:center;gap:5px;text-align:right">
3638
${
3739
wasImageNotUpdatedYet
3840
? `<button type="submit"><i class="fa fa-check"></i> Update screenshot</button>`
39-
: "Image was already updated, rerun test to see new comparison"
41+
: error ? "Image was already updated, rerun test to see new comparison" : ""
4042
}
4143
<button type="button" data-type="close"><i class="fa fa-times"></i> Close</button>
4244
<form>
@@ -64,30 +66,13 @@ export const generateOverlayTemplate = ({
6466
</div>
6567
</div>`;
6668

67-
export function cachedReadFile(
68-
imageCache: Record<string, string>,
69-
path: string,
70-
encoding: Cypress.Encodings
71-
): Cypress.Chainable<string> {
72-
if (imageCache[path])
73-
return Cypress.Promise.resolve(
74-
imageCache[path]
75-
) as unknown as Cypress.Chainable<string>;
76-
77-
return cy
78-
.readFile(path, encoding, { log: false })
79-
.then((file) => (imageCache[path] = file));
80-
}
81-
8269
/* c8 ignore start */
8370
before(() => {
8471
if (!top) return null;
8572
Cypress.$(`.${OVERLAY_CLASS}`, top.document.body).remove();
8673
});
8774

8875
after(() => {
89-
const imageCache: Record<string, string> = {};
90-
9176
if (!top) return null;
9277

9378
Cypress.$(top.document.body).on(
@@ -97,7 +82,7 @@ after(() => {
9782
e.preventDefault();
9883
if (!top) return false;
9984

100-
const { title, imgPath } = JSON.parse(
85+
const { title, imgPath, imgDiffBase64, imgNewBase64, imgOldBase64, error } = JSON.parse(
10186
decodeURIComponent(
10287
Base64.decode(
10388
e.currentTarget.getAttribute("href").substring(LINK_PREFIX.length)
@@ -106,39 +91,10 @@ after(() => {
10691
);
10792
queueClear();
10893

109-
cachedReadFile(imageCache, imgPath, "base64")
110-
.then((imgNew) =>
111-
cachedReadFile(
112-
imageCache,
113-
imgPath.replace(FILE_SUFFIX.actual, ""),
114-
"base64"
115-
).then((imgOld) =>
116-
cachedReadFile(
117-
imageCache,
118-
imgPath.replace(FILE_SUFFIX.actual, FILE_SUFFIX.diff),
119-
"base64"
120-
).then((imgDiff) =>
121-
cy
122-
.task(TASK.doesFileExist, { path: imgPath }, { log: false })
123-
.then(
124-
(wasImageNotUpdatedYet) =>
125-
[
126-
imgNew,
127-
imgOld,
128-
imgDiff,
129-
wasImageNotUpdatedYet as boolean,
130-
] as const
131-
)
132-
)
133-
)
134-
)
94+
cy
95+
.task<boolean>(TASK.doesFileExist, { path: imgPath }, { log: false })
13596
.then(
136-
([
137-
imgNewBase64,
138-
imgOldBase64,
139-
imgDiffBase64,
140-
wasImageNotUpdatedYet,
141-
]) => {
97+
(wasImageNotUpdatedYet) => {
14298
if (!top) return false;
14399
queueClear();
144100

@@ -148,6 +104,7 @@ after(() => {
148104
imgNewBase64,
149105
imgOldBase64,
150106
imgDiffBase64,
107+
error,
151108
wasImageNotUpdatedYet,
152109
})
153110
).appendTo(top.document.body);

src/task.hook.ts

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import moveFile from "move-file";
66
import sanitize from "sanitize-filename";
77
import { FILE_SUFFIX, IMAGE_SNAPSHOT_PREFIX, TASK } from "./constants";
88
import { alignImagesToSameSize, importAndScaleImage } from "./image.utils";
9+
import type { CompareImagesTaskReturn } from "./types";
910

1011
export type CompareImagesCfg = {
1112
scaleFactor: number;
@@ -54,14 +55,10 @@ export const approveImageTask = ({ img }: { img: string }) => {
5455

5556
export const compareImagesTask = async (
5657
cfg: CompareImagesCfg
57-
): Promise<null | {
58-
error?: boolean;
59-
message?: string;
60-
imgDiff?: number;
61-
maxDiffThreshold?: number;
62-
}> => {
58+
): Promise<CompareImagesTaskReturn> => {
6359
const messages = [] as string[];
6460
let imgDiff: number | undefined;
61+
let imgNewBase64: string, imgOldBase64: string, imgDiffBase64: string;
6562
let error = false;
6663

6764
if (fs.existsSync(cfg.imgOld) && !cfg.updateImages) {
@@ -107,15 +104,23 @@ export const compareImagesTask = async (
107104
error = true;
108105
}
109106

107+
const diffBuffer = PNG.sync.write(diff);
108+
imgNewBase64 = PNG.sync.write(imgNew).toString('base64');
109+
imgDiffBase64 = diffBuffer.toString('base64');
110+
imgOldBase64 = PNG.sync.write(imgOld).toString('base64');
111+
110112
if (error) {
111113
fs.writeFileSync(
112114
cfg.imgNew.replace(FILE_SUFFIX.actual, FILE_SUFFIX.diff),
113-
PNG.sync.write(diff)
115+
diffBuffer
114116
);
115117
return {
116118
error,
117119
message: messages.join("\n"),
118120
imgDiff,
121+
imgNewBase64,
122+
imgDiffBase64,
123+
imgOldBase64,
119124
maxDiffThreshold: cfg.maxDiffThreshold,
120125
};
121126
} else {
@@ -125,6 +130,9 @@ export const compareImagesTask = async (
125130
} else {
126131
// there is no "old screenshot" or screenshots should be immediately updated
127132
imgDiff = 0;
133+
imgNewBase64 = '';
134+
imgDiffBase64 = '';
135+
imgOldBase64 = '';
128136
moveFile.sync(cfg.imgNew, cfg.imgOld);
129137
}
130138

@@ -139,6 +147,9 @@ export const compareImagesTask = async (
139147
return {
140148
message: messages.join("\n"),
141149
imgDiff,
150+
imgNewBase64,
151+
imgDiffBase64,
152+
imgOldBase64,
142153
maxDiffThreshold: cfg.maxDiffThreshold,
143154
};
144155
}

src/types.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
export type CompareImagesTaskReturn = null | {
2+
error?: boolean;
3+
message?: string;
4+
imgDiff?: number;
5+
imgNewBase64?: string;
6+
imgDiffBase64?: string;
7+
imgOldBase64?: string;
8+
maxDiffThreshold?: number;
9+
};

0 commit comments

Comments
 (0)