artes 1.5.6 → 1.5.8
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/docs/stepDefinitions.md
CHANGED
|
@@ -309,6 +309,12 @@
|
|
|
309
309
|
- User expects `{string}` should have `{string}` id
|
|
310
310
|
- User expects `{string}` should have `{string}` JavaScript property with `{string}` value
|
|
311
311
|
- User expects `{string}` should have `{string}` role
|
|
312
|
+
- User expects that full page match with `{string}` screenshot
|
|
313
|
+
- User expects that full page match with `{string}` screenshot with {float}% difference
|
|
314
|
+
- User expects that page match with `{string}` screenshot
|
|
315
|
+
- User expects that page match with `{string}` screenshot with `{float}`% difference
|
|
316
|
+
- User expects that `{string}` element match with `{string}` screenshot
|
|
317
|
+
- User expects that `{string}` element match with `{string}` screenshot with `{float}`% difference
|
|
312
318
|
- User expects `{string}` should have a screenshot
|
|
313
319
|
- User expects `{string}` should match `{string}` text
|
|
314
320
|
- User expects `{string}` should have `{string}` value
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "artes",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.8",
|
|
4
4
|
"description": "The simplest way to automate UI and API tests using Cucumber-style steps.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -30,7 +30,10 @@
|
|
|
30
30
|
"deasync": "^0.1.31",
|
|
31
31
|
"playwright": "^1.58.2",
|
|
32
32
|
"ffmpeg-static": "^5.3.0",
|
|
33
|
-
"ffprobe-static": "^3.1.0"
|
|
33
|
+
"ffprobe-static": "^3.1.0",
|
|
34
|
+
"pixelmatch": "^5.3.0",
|
|
35
|
+
"pngjs": "^7.0.0",
|
|
36
|
+
"sharp": "^0.34.5"
|
|
34
37
|
},
|
|
35
38
|
"repository": {
|
|
36
39
|
"type": "git",
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
require("allure-cucumberjs");
|
|
5
|
+
const allure = require("allure-js-commons");
|
|
6
|
+
const sharp = require("sharp");
|
|
7
|
+
const pixelmatch = require("pixelmatch");
|
|
8
|
+
const { PNG } = require('pngjs');
|
|
9
|
+
const { moduleConfig } = require('artes/src/helper/imports/commons');
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
async function screenComparer(baselineFilename, screenshotFn, options = {}) {
|
|
13
|
+
const {
|
|
14
|
+
maxDiffPercent = 0.01,
|
|
15
|
+
threshold = 0.1,
|
|
16
|
+
} = options;
|
|
17
|
+
|
|
18
|
+
const baselinePath = path.join(moduleConfig.projectPath, baselineFilename);
|
|
19
|
+
const actualPath = path.join(moduleConfig.projectPath,"visualComparison", `actual_${baselineFilename}`);
|
|
20
|
+
const diffPath = path.join(moduleConfig.projectPath,"visualComparison", `diff_${baselineFilename}`);
|
|
21
|
+
|
|
22
|
+
await screenshotFn(actualPath);
|
|
23
|
+
|
|
24
|
+
const baselineMeta = await sharp(baselinePath).metadata();
|
|
25
|
+
const actualMeta = await sharp(actualPath).metadata();
|
|
26
|
+
|
|
27
|
+
// if (baselineMeta.width !== actualMeta.width || baselineMeta.height !== actualMeta.height) {
|
|
28
|
+
// console.warn(`⚠️ Dimension mismatch! Baseline: ${baselineMeta.width}x${baselineMeta.height} | Actual: ${actualMeta.width}x${actualMeta.height}`);
|
|
29
|
+
// }
|
|
30
|
+
|
|
31
|
+
const width = actualMeta.width;
|
|
32
|
+
const height = actualMeta.height;
|
|
33
|
+
|
|
34
|
+
const baselineBuffer = await sharp(baselinePath)
|
|
35
|
+
.resize(width, height, { fit: "fill" })
|
|
36
|
+
.ensureAlpha()
|
|
37
|
+
.raw()
|
|
38
|
+
.toBuffer();
|
|
39
|
+
|
|
40
|
+
const actualBuffer = await sharp(actualPath)
|
|
41
|
+
.resize(width, height, { fit: "fill" })
|
|
42
|
+
.ensureAlpha()
|
|
43
|
+
.raw()
|
|
44
|
+
.toBuffer();
|
|
45
|
+
|
|
46
|
+
const diffImg = new PNG({ width, height });
|
|
47
|
+
|
|
48
|
+
const mismatchedPixels = pixelmatch(
|
|
49
|
+
baselineBuffer,
|
|
50
|
+
actualBuffer,
|
|
51
|
+
diffImg.data,
|
|
52
|
+
width,
|
|
53
|
+
height,
|
|
54
|
+
{ threshold, includeAA: false }
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
fs.writeFileSync(diffPath, PNG.sync.write(diffImg));
|
|
58
|
+
|
|
59
|
+
const totalPixels = width * height;
|
|
60
|
+
const mismatchRatio = mismatchedPixels / totalPixels;
|
|
61
|
+
|
|
62
|
+
const expectedBase64 = (await sharp(baselinePath).resize(width, height, { fit: "fill" }).png().toBuffer()).toString("base64");
|
|
63
|
+
const actualBase64 = (await sharp(actualPath).png().toBuffer()).toString("base64");
|
|
64
|
+
const diffBase64 = (await sharp(diffPath).png().toBuffer()).toString("base64");
|
|
65
|
+
|
|
66
|
+
const content = JSON.stringify({
|
|
67
|
+
expected: `data:image/png;base64,${expectedBase64}`,
|
|
68
|
+
actual: `data:image/png;base64,${actualBase64}`,
|
|
69
|
+
diff: `data:image/png;base64,${diffBase64}`,
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
await allure.attachment("Screenshot diff details", ` Mismatched pixels: ${mismatchedPixels} / ${totalPixels} (${(mismatchRatio * 100).toFixed(2)}%) Max allowed: ${(maxDiffPercent * 100)}%`, "text/plain" )
|
|
73
|
+
await allure.attachment("Screenshot diff", content, "application/vnd.allure.image.diff");
|
|
74
|
+
|
|
75
|
+
if (fs.existsSync(path.join(moduleConfig.projectPath,"visualComparison"))) fs.rmSync(path.join(moduleConfig.projectPath,"visualComparison"), {recursive: true, force: true});
|
|
76
|
+
|
|
77
|
+
if (mismatchRatio > maxDiffPercent) {
|
|
78
|
+
throw new Error(
|
|
79
|
+
`Screenshot mismatch: ${(mismatchRatio * 100).toFixed(2)}% pixels differ (max allowed: ${(maxDiffPercent * 100)}%)`
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
module.exports= { screenComparer}
|
|
@@ -186,13 +186,6 @@ const assert = {
|
|
|
186
186
|
typeof selector === "string" ? element(selector) : await selector,
|
|
187
187
|
).toHaveRole(role, options);
|
|
188
188
|
},
|
|
189
|
-
shouldHaveScreenshot: async (selector, options) => {
|
|
190
|
-
options = options ?? {};
|
|
191
|
-
|
|
192
|
-
await expect(
|
|
193
|
-
typeof selector === "string" ? element(selector) : await selector,
|
|
194
|
-
).toHaveScreenshot(options);
|
|
195
|
-
},
|
|
196
189
|
shouldHaveText: async (selector, text, options) => {
|
|
197
190
|
options = options ?? {};
|
|
198
191
|
|
|
@@ -7,6 +7,7 @@ const {
|
|
|
7
7
|
context,
|
|
8
8
|
resolveVariable
|
|
9
9
|
} = require("../helper/imports/commons");
|
|
10
|
+
const { screenComparer } = require("artes/src/helper/controller/screenComparer");
|
|
10
11
|
const { assert, frame } = require("../helper/stepFunctions/exporter");
|
|
11
12
|
const Ajv = require("ajv");
|
|
12
13
|
|
|
@@ -266,13 +267,50 @@ Then("User expects {int} th of {string} should have {string} role", async functi
|
|
|
266
267
|
await assert.shouldHaveId(nthElement, role);
|
|
267
268
|
});
|
|
268
269
|
|
|
269
|
-
|
|
270
|
-
Then(
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
);
|
|
270
|
+
|
|
271
|
+
Then('User expects that full page match with {string} screenshot', async function (baselineFilename) {
|
|
272
|
+
await screenComparer( baselineFilename,
|
|
273
|
+
(actualPath) => context.page.screenshot({ path: actualPath, fullPage: true }),
|
|
274
|
+
{ maxDiffPercent: 0.01 }
|
|
275
|
+
);
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
Then('User expects that full page match with {string} screenshot with {float}% difference', async function (baselineFilename, maxDiff) {
|
|
279
|
+
await screenComparer( baselineFilename,
|
|
280
|
+
(actualPath) => context.page.screenshot({ path: actualPath, fullPage: true }),
|
|
281
|
+
{ maxDiffPercent: maxDiff / 100 }
|
|
282
|
+
);
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
Then('User expects that page match with {string} screenshot', async function (baselineFilename) {
|
|
287
|
+
await screenComparer(baselineFilename,
|
|
288
|
+
(actualPath) => context.page.screenshot({ path: actualPath, fullPage: false }),
|
|
289
|
+
{ maxDiffPercent: 0.01 }
|
|
290
|
+
);
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
Then('User expects that page match with {string} screenshot with {float}% difference', async function (baselineFilename, maxDiff) {
|
|
294
|
+
await screenComparer( baselineFilename,
|
|
295
|
+
(actualPath) => context.page.screenshot({ path: actualPath, fullPage: false }),
|
|
296
|
+
{ maxDiffPercent: maxDiff / 100 }
|
|
297
|
+
);
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
Then('User expects that {string} element match with {string} screenshot', async function (selector, baselineFilename) {
|
|
302
|
+
await screenComparer( baselineFilename,
|
|
303
|
+
(actualPath) => element(selector).screenshot({ path: actualPath }),
|
|
304
|
+
{ maxDiffPercent: 0.01 }
|
|
305
|
+
);
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
Then('User expects that {string} element match with {string} screenshot with {float}% difference', async function (selector, baselineFilename, maxDiff) {
|
|
309
|
+
await screenComparer( baselineFilename,
|
|
310
|
+
(actualPath) => element(selector).screenshot({ path: actualPath }),
|
|
311
|
+
{ maxDiffPercent: maxDiff / 100 }
|
|
312
|
+
);
|
|
313
|
+
});
|
|
276
314
|
|
|
277
315
|
// Check if a selector should have specific text
|
|
278
316
|
Then(
|