@brightspace-ui/testing 1.38.1 → 1.38.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/browser/vdiff.js +2 -5
- package/src/server/visual-diff-plugin.js +104 -87
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@brightspace-ui/testing",
|
|
3
3
|
"description": "Utilities for testing front-end components and applications",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"version": "1.38.
|
|
5
|
+
"version": "1.38.3",
|
|
6
6
|
"repository": "https://github.com/BrightspaceUI/testing.git",
|
|
7
7
|
"scripts": {
|
|
8
8
|
"lint": "npm run lint:eslint && npm run lint:style",
|
package/src/browser/vdiff.js
CHANGED
|
@@ -90,11 +90,8 @@ async function ScreenshotAndCompare(opts = {}) {
|
|
|
90
90
|
}
|
|
91
91
|
const slowDuration = this.test.slow();
|
|
92
92
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
this.test.timeout(0);
|
|
96
|
-
result = await executeServerCommand('brightspace-visual-diff-compare-resize', { name });
|
|
97
|
-
}
|
|
93
|
+
this.test.timeout(0);
|
|
94
|
+
const result = await executeServerCommand('brightspace-visual-diff-compare', { name, fullPage, rect, slowDuration });
|
|
98
95
|
|
|
99
96
|
if (window.d2lTest) document.documentElement.classList.remove('screenshot');
|
|
100
97
|
|
|
@@ -51,24 +51,60 @@ async function clearDiffPaths(dir) {
|
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
+
function getResizedPng(xName, yName, original, newSize) {
|
|
55
|
+
const xOffsets = {
|
|
56
|
+
left: 0,
|
|
57
|
+
center: Math.floor((newSize.width - original.width) / 2),
|
|
58
|
+
right: newSize.width - original.width
|
|
59
|
+
};
|
|
60
|
+
const yOffsets = {
|
|
61
|
+
top: 0,
|
|
62
|
+
center: Math.floor((newSize.height - original.height) / 2),
|
|
63
|
+
bottom: newSize.height - original.height
|
|
64
|
+
};
|
|
65
|
+
const resized = new PNG(newSize);
|
|
66
|
+
PNG.bitblt(original, resized, 0, 0, original.width, original.height, xOffsets[xName], yOffsets[yName]);
|
|
67
|
+
return resized;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
async function getBestResizePng(screenshotImage, goldenImage) {
|
|
71
|
+
const newWidth = Math.max(screenshotImage.width, goldenImage.width);
|
|
72
|
+
const newHeight = Math.max(screenshotImage.height, goldenImage.height);
|
|
73
|
+
const newSize = { width: newWidth, height: newHeight };
|
|
74
|
+
|
|
75
|
+
const newScreenshots = await createComparisonPNGs(screenshotImage, newSize);
|
|
76
|
+
const newGoldens = await createComparisonPNGs(goldenImage, newSize);
|
|
77
|
+
|
|
78
|
+
let bestIndex = -1;
|
|
79
|
+
let bestDiffImage = null;
|
|
80
|
+
let bestPixelsDiff = Number.MAX_SAFE_INTEGER;
|
|
81
|
+
for (let i = 0; i < newScreenshots.length; i++) {
|
|
82
|
+
const { diff, pixelsDiff } = getPixelsDiff(newScreenshots[i].png, newGoldens[i].png);
|
|
83
|
+
|
|
84
|
+
if (pixelsDiff < bestPixelsDiff) {
|
|
85
|
+
bestIndex = i;
|
|
86
|
+
bestDiffImage = diff;
|
|
87
|
+
bestPixelsDiff = pixelsDiff;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return {
|
|
92
|
+
screenshot: newScreenshots[bestIndex],
|
|
93
|
+
golden: newGoldens[bestIndex],
|
|
94
|
+
diff: bestDiffImage,
|
|
95
|
+
pixelsDiff: bestPixelsDiff
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
54
99
|
async function createComparisonPNGs(original, newSize) {
|
|
55
100
|
const resizedPNGs = [];
|
|
56
|
-
[
|
|
57
|
-
|
|
58
|
-
{ name: 'center', coord: Math.floor((newSize.height - original.height) / 2) },
|
|
59
|
-
{ name: 'bottom', coord: newSize.height - original.height }
|
|
60
|
-
].forEach(y => {
|
|
61
|
-
[
|
|
62
|
-
{ name: 'left', coord: 0 },
|
|
63
|
-
{ name: 'center', coord: Math.floor((newSize.width - original.width) / 2) },
|
|
64
|
-
{ name: 'right', coord: newSize.width - original.width }
|
|
65
|
-
].forEach(x => { // TODO: position added for reports, remove/adjust as needed
|
|
101
|
+
[ 'top', 'center', 'bottom' ].forEach(y => {
|
|
102
|
+
['left', 'center', 'right'].forEach(x => {
|
|
66
103
|
if (original.width === newSize.width && original.height === newSize.height) {
|
|
67
|
-
resizedPNGs.push({ png: original, position: `${y
|
|
104
|
+
resizedPNGs.push({ png: original, position: `${y}-${x}` });
|
|
68
105
|
} else {
|
|
69
|
-
const resized =
|
|
70
|
-
|
|
71
|
-
resizedPNGs.push({ png: resized, position: `${y.name}-${x.name}` });
|
|
106
|
+
const resized = getResizedPng(x, y, original, newSize);
|
|
107
|
+
resizedPNGs.push({ png: resized, position: `${y}-${x}` });
|
|
72
108
|
}
|
|
73
109
|
});
|
|
74
110
|
});
|
|
@@ -76,6 +112,14 @@ async function createComparisonPNGs(original, newSize) {
|
|
|
76
112
|
return resizedPNGs;
|
|
77
113
|
}
|
|
78
114
|
|
|
115
|
+
function getPixelsDiff(screenshotImage, goldenImage) {
|
|
116
|
+
const diff = new PNG({ width: screenshotImage.width, height: screenshotImage.height });
|
|
117
|
+
const pixelsDiff = pixelmatch(
|
|
118
|
+
screenshotImage.data, goldenImage.data, diff.data, screenshotImage.width, screenshotImage.height, { diffMask: true, threshold: DEFAULT_TOLERANCE }
|
|
119
|
+
);
|
|
120
|
+
return { diff, pixelsDiff };
|
|
121
|
+
}
|
|
122
|
+
|
|
79
123
|
async function tryMoveFile(srcFileName, destFileName) {
|
|
80
124
|
await mkdir(dirname(destFileName), { recursive: true });
|
|
81
125
|
try {
|
|
@@ -135,39 +179,43 @@ export function visualDiff({ updateGoldens = false, runSubset = false } = {}) {
|
|
|
135
179
|
const screenshotFile = join(newPath, PATHS.FAIL, browser, newName);
|
|
136
180
|
const screenshotFileName = `${screenshotFile}.png`;
|
|
137
181
|
|
|
138
|
-
if (command
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
182
|
+
if (command !== 'brightspace-visual-diff-compare') return;
|
|
183
|
+
if (!isCI) { // CI will be a fresh .vdiff folder each time and only one run
|
|
184
|
+
if (session.testRun !== currentRun) {
|
|
185
|
+
currentRun = session.testRun;
|
|
186
|
+
clearedDirs.clear();
|
|
187
|
+
}
|
|
144
188
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
}
|
|
149
|
-
await clearedDirs.get(newPath);
|
|
189
|
+
if (runSubset || currentRun > 0) {
|
|
190
|
+
if (!clearedDirs.has(newPath)) {
|
|
191
|
+
clearedDirs.set(newPath, clearDir(updateGoldens, newPath));
|
|
150
192
|
}
|
|
193
|
+
await clearedDirs.get(newPath);
|
|
151
194
|
}
|
|
195
|
+
}
|
|
152
196
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
};
|
|
197
|
+
const screenshotOpts = {
|
|
198
|
+
animations: 'disabled'
|
|
199
|
+
};
|
|
157
200
|
|
|
158
|
-
|
|
159
|
-
|
|
201
|
+
if (payload.fullPage) screenshotOpts.fullPage = true;
|
|
202
|
+
if (payload.rect) screenshotOpts.clip = payload.rect;
|
|
160
203
|
|
|
204
|
+
async function takeScreenshot() {
|
|
205
|
+
const path = updateGoldens ? goldenFileName : screenshotFileName;
|
|
161
206
|
const page = session.browser.getPage(session.id);
|
|
162
|
-
await page.screenshot(screenshotOpts);
|
|
207
|
+
return await page.screenshot({ path, ...screenshotOpts });
|
|
208
|
+
}
|
|
163
209
|
|
|
164
|
-
|
|
165
|
-
return { pass: true };
|
|
166
|
-
}
|
|
210
|
+
const screenshotFileBuffer = await takeScreenshot();
|
|
167
211
|
|
|
168
|
-
|
|
212
|
+
if (updateGoldens) {
|
|
213
|
+
return { pass: true };
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const rootLength = join(rootDir, PATHS.VDIFF_ROOT).length + 1;
|
|
169
217
|
|
|
170
|
-
|
|
218
|
+
async function runCompareTest() {
|
|
171
219
|
const screenshotImage = PNG.sync.read(screenshotFileBuffer);
|
|
172
220
|
infoManager.set({
|
|
173
221
|
slowDuration: payload.slowDuration,
|
|
@@ -207,10 +255,7 @@ export function visualDiff({ updateGoldens = false, runSubset = false } = {}) {
|
|
|
207
255
|
return { pass: true };
|
|
208
256
|
}
|
|
209
257
|
|
|
210
|
-
const diff =
|
|
211
|
-
const pixelsDiff = pixelmatch(
|
|
212
|
-
screenshotImage.data, goldenImage.data, diff.data, screenshotImage.width, screenshotImage.height, { diffMask: true, threshold: DEFAULT_TOLERANCE }
|
|
213
|
-
);
|
|
258
|
+
const { diff, pixelsDiff } = getPixelsDiff(screenshotImage, goldenImage);
|
|
214
259
|
|
|
215
260
|
if (pixelsDiff !== 0) {
|
|
216
261
|
infoManager.set({
|
|
@@ -232,54 +277,26 @@ export function visualDiff({ updateGoldens = false, runSubset = false } = {}) {
|
|
|
232
277
|
return { pass: false, message: 'Image diff is clean but the images do not have the same bytes.' };
|
|
233
278
|
}
|
|
234
279
|
} else {
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
const currentDiff = new PNG(newSize);
|
|
253
|
-
const currentPixelsDiff = pixelmatch(
|
|
254
|
-
newScreenshots[i].png.data, newGoldens[i].png.data, currentDiff.data, currentDiff.width, currentDiff.height, { diffMask: true, threshold: DEFAULT_TOLERANCE }
|
|
255
|
-
);
|
|
256
|
-
|
|
257
|
-
if (currentPixelsDiff < pixelsDiff) {
|
|
258
|
-
bestIndex = i;
|
|
259
|
-
bestDiffImage = currentDiff;
|
|
260
|
-
pixelsDiff = currentPixelsDiff;
|
|
261
|
-
}
|
|
280
|
+
const { screenshot, golden, diff, pixelsDiff } = await getBestResizePng(screenshotImage, goldenImage);
|
|
281
|
+
|
|
282
|
+
await writeFile(`${screenshotFile}-resized-screenshot.png`, PNG.sync.write(screenshot.png));
|
|
283
|
+
await writeFile(`${screenshotFile}-resized-golden.png`, PNG.sync.write(golden.png));
|
|
284
|
+
await writeFile(`${screenshotFile}-diff.png`, PNG.sync.write(diff));
|
|
285
|
+
infoManager.set({
|
|
286
|
+
diff: `${screenshotFile.substring(rootLength)}-diff.png`,
|
|
287
|
+
golden: {
|
|
288
|
+
path: `${screenshotFile.substring(rootLength)}-resized-golden.png`
|
|
289
|
+
},
|
|
290
|
+
new: {
|
|
291
|
+
path: `${screenshotFile.substring(rootLength)}-resized-screenshot.png`
|
|
292
|
+
},
|
|
293
|
+
pixelsDiff
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
return { pass: false, message: `Images are not the same size. When resized, ${pixelsDiff} pixels are different.` };
|
|
262
297
|
}
|
|
263
|
-
|
|
264
|
-
await writeFile(`${screenshotFile}-resized-screenshot.png`, PNG.sync.write(newScreenshots[bestIndex].png));
|
|
265
|
-
await writeFile(`${screenshotFile}-resized-golden.png`, PNG.sync.write(newGoldens[bestIndex].png));
|
|
266
|
-
await writeFile(`${screenshotFile}-diff.png`, PNG.sync.write(bestDiffImage));
|
|
267
|
-
|
|
268
|
-
const rootLength = join(rootDir, PATHS.VDIFF_ROOT).length + 1;
|
|
269
|
-
infoManager.set({
|
|
270
|
-
diff: `${screenshotFile.substring(rootLength)}-diff.png`,
|
|
271
|
-
golden: {
|
|
272
|
-
path: `${screenshotFile.substring(rootLength)}-resized-golden.png`
|
|
273
|
-
},
|
|
274
|
-
new: {
|
|
275
|
-
path: `${screenshotFile.substring(rootLength)}-resized-screenshot.png`
|
|
276
|
-
},
|
|
277
|
-
pixelsDiff
|
|
278
|
-
});
|
|
279
|
-
|
|
280
|
-
return { pass: false, message: `Images are not the same size. When resized, ${pixelsDiff} pixels are different.` };
|
|
281
298
|
}
|
|
282
|
-
|
|
299
|
+
return await runCompareTest();
|
|
283
300
|
}
|
|
284
301
|
};
|
|
285
302
|
}
|