@rettangoli/vt 1.0.0-rc13 → 1.0.0-rc15
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/README.md
CHANGED
|
@@ -141,15 +141,15 @@ Screenshot naming:
|
|
|
141
141
|
A pre-built Docker image with `rtgl` and Playwright browsers is available:
|
|
142
142
|
|
|
143
143
|
```bash
|
|
144
|
-
docker pull han4wluc/rtgl:playwright-v1.57.0-rtgl-v1.0.0-
|
|
144
|
+
docker pull han4wluc/rtgl:playwright-v1.57.0-rtgl-v1.0.0-rc27
|
|
145
145
|
```
|
|
146
146
|
|
|
147
147
|
Run commands against a local project:
|
|
148
148
|
|
|
149
149
|
```bash
|
|
150
|
-
docker run --rm -v "$(pwd):/workspace" han4wluc/rtgl:playwright-v1.57.0-rtgl-v1.0.0-
|
|
151
|
-
docker run --rm -v "$(pwd):/workspace" han4wluc/rtgl:playwright-v1.57.0-rtgl-v1.0.0-
|
|
152
|
-
docker run --rm -v "$(pwd):/workspace" han4wluc/rtgl:playwright-v1.57.0-rtgl-v1.0.0-
|
|
150
|
+
docker run --rm -v "$(pwd):/workspace" han4wluc/rtgl:playwright-v1.57.0-rtgl-v1.0.0-rc27 rtgl vt screenshot
|
|
151
|
+
docker run --rm -v "$(pwd):/workspace" han4wluc/rtgl:playwright-v1.57.0-rtgl-v1.0.0-rc27 rtgl vt report
|
|
152
|
+
docker run --rm -v "$(pwd):/workspace" han4wluc/rtgl:playwright-v1.57.0-rtgl-v1.0.0-rc27 rtgl vt accept
|
|
153
153
|
```
|
|
154
154
|
|
|
155
155
|
Note:
|
package/package.json
CHANGED
package/src/cli/report.js
CHANGED
|
@@ -2,10 +2,11 @@ import fs from "fs";
|
|
|
2
2
|
import path from "path";
|
|
3
3
|
import crypto from "crypto";
|
|
4
4
|
import { cp } from "node:fs/promises";
|
|
5
|
+
import { load as loadYaml } from "js-yaml";
|
|
5
6
|
import pixelmatch from "pixelmatch";
|
|
6
7
|
import sharp from "sharp";
|
|
7
|
-
import { readYaml } from "../common.js";
|
|
8
|
-
import { validateVtConfig } from "../validation.js";
|
|
8
|
+
import { extractFrontMatter, readYaml } from "../common.js";
|
|
9
|
+
import { validateFiniteNumber, validateVtConfig } from "../validation.js";
|
|
9
10
|
import { resolveReportOptions } from "./report-options.js";
|
|
10
11
|
import {
|
|
11
12
|
buildAllRelativePaths,
|
|
@@ -17,6 +18,7 @@ import {
|
|
|
17
18
|
filterRelativeScreenshotPathsBySelectors,
|
|
18
19
|
hasSelectors,
|
|
19
20
|
} from "../selector-filter.js";
|
|
21
|
+
import { stripViewportSuffix } from "../viewport.js";
|
|
20
22
|
|
|
21
23
|
const libraryTemplatesPath = new URL("./templates", import.meta.url).pathname;
|
|
22
24
|
|
|
@@ -35,6 +37,64 @@ function getAllFiles(dir, fileList = []) {
|
|
|
35
37
|
return fileList;
|
|
36
38
|
}
|
|
37
39
|
|
|
40
|
+
function normalizePathForLookup(filePath) {
|
|
41
|
+
return String(filePath)
|
|
42
|
+
.replace(/\\/g, "/")
|
|
43
|
+
.replace(/^\.?\//, "");
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function toSpecItemKey(relativeSpecPath) {
|
|
47
|
+
const normalized = normalizePathForLookup(relativeSpecPath);
|
|
48
|
+
const ext = path.extname(normalized);
|
|
49
|
+
return normalized.slice(0, normalized.length - ext.length);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function toScreenshotItemKey(relativeScreenshotPath) {
|
|
53
|
+
const normalized = normalizePathForLookup(relativeScreenshotPath).replace(/\.webp$/i, "");
|
|
54
|
+
const withoutOrdinal = normalized.replace(/-\d{1,3}$/i, "");
|
|
55
|
+
return stripViewportSuffix(withoutOrdinal);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function loadFrontMatterDiffThresholdOverrides(specsDir) {
|
|
59
|
+
const overrides = new Map();
|
|
60
|
+
if (!fs.existsSync(specsDir)) {
|
|
61
|
+
return overrides;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const specFiles = getAllFiles(specsDir);
|
|
65
|
+
for (const specFilePath of specFiles) {
|
|
66
|
+
const fileContent = fs.readFileSync(specFilePath, "utf8");
|
|
67
|
+
const { frontMatter } = extractFrontMatter(fileContent);
|
|
68
|
+
if (!frontMatter) {
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const relativePath = path.relative(specsDir, specFilePath);
|
|
73
|
+
const frontMatterData = loadYaml(frontMatter);
|
|
74
|
+
if (
|
|
75
|
+
frontMatterData === null
|
|
76
|
+
|| frontMatterData === undefined
|
|
77
|
+
|| typeof frontMatterData !== "object"
|
|
78
|
+
|| Array.isArray(frontMatterData)
|
|
79
|
+
) {
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (frontMatterData.diffThreshold === undefined || frontMatterData.diffThreshold === null) {
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
validateFiniteNumber(
|
|
88
|
+
frontMatterData.diffThreshold,
|
|
89
|
+
`${relativePath}: frontMatter.diffThreshold`,
|
|
90
|
+
{ min: 0, max: 100 },
|
|
91
|
+
);
|
|
92
|
+
overrides.set(toSpecItemKey(relativePath), frontMatterData.diffThreshold);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return overrides;
|
|
96
|
+
}
|
|
97
|
+
|
|
38
98
|
async function calculateImageHash(imagePath) {
|
|
39
99
|
const imageBuffer = fs.readFileSync(imagePath);
|
|
40
100
|
const hash = crypto.createHash("md5").update(imageBuffer).digest("hex");
|
|
@@ -137,10 +197,19 @@ async function main(options = {}) {
|
|
|
137
197
|
const templatePath = path.join(libraryTemplatesPath, "report.html");
|
|
138
198
|
const outputPath = path.join(siteOutputPath, "report.html");
|
|
139
199
|
const jsonReportPath = path.join(".rettangoli", "vt", "report.json");
|
|
200
|
+
const specsDir = path.join(vtPath, "specs");
|
|
201
|
+
|
|
202
|
+
let diffThresholdOverridesBySpec = new Map();
|
|
203
|
+
if (compareMethod === "pixelmatch") {
|
|
204
|
+
diffThresholdOverridesBySpec = loadFrontMatterDiffThresholdOverrides(specsDir);
|
|
205
|
+
}
|
|
140
206
|
|
|
141
207
|
console.log(`Comparison method: ${compareMethod}`);
|
|
142
208
|
if (compareMethod === "pixelmatch") {
|
|
143
209
|
console.log(` color threshold: ${colorThreshold}, diff threshold: ${diffThreshold}%`);
|
|
210
|
+
if (diffThresholdOverridesBySpec.size > 0) {
|
|
211
|
+
console.log(` frontmatter diff threshold overrides: ${diffThresholdOverridesBySpec.size}`);
|
|
212
|
+
}
|
|
144
213
|
}
|
|
145
214
|
|
|
146
215
|
if (!fs.existsSync(originalReferenceDir)) {
|
|
@@ -204,6 +273,9 @@ async function main(options = {}) {
|
|
|
204
273
|
let error = false;
|
|
205
274
|
let similarity = null;
|
|
206
275
|
let diffPixels = null;
|
|
276
|
+
const itemKey = toScreenshotItemKey(relativePath);
|
|
277
|
+
const itemDiffThreshold = diffThresholdOverridesBySpec.get(itemKey);
|
|
278
|
+
const effectiveDiffThreshold = itemDiffThreshold ?? diffThreshold;
|
|
207
279
|
|
|
208
280
|
if (candidateExists && referenceExists) {
|
|
209
281
|
const diffDirPath = path.dirname(diffPath);
|
|
@@ -216,7 +288,7 @@ async function main(options = {}) {
|
|
|
216
288
|
referencePath,
|
|
217
289
|
compareMethod,
|
|
218
290
|
diffPath,
|
|
219
|
-
{ colorThreshold, diffThreshold },
|
|
291
|
+
{ colorThreshold, diffThreshold: effectiveDiffThreshold },
|
|
220
292
|
);
|
|
221
293
|
if (comparison.error) {
|
|
222
294
|
comparisonErrors.push(
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="UTF-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
-
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@rettangoli/ui@1.0.0-
|
|
7
|
-
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@rettangoli/ui@1.0.0-
|
|
6
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@rettangoli/ui@1.0.0-rc15/dist/themes/base.css">
|
|
7
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@rettangoli/ui@1.0.0-rc15/dist/themes/theme-rtgl-slate.css">
|
|
8
8
|
<script>
|
|
9
9
|
window.rtglIcons = {
|
|
10
10
|
text: `<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M4 12H20M4 8H20M4 16H12" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>`,
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
}
|
|
41
41
|
</script>
|
|
42
42
|
<script src="https://cdn.jsdelivr.net/npm/construct-style-sheets-polyfill@3.1.0/dist/adoptedStyleSheets.min.js"></script>
|
|
43
|
-
<script src="https://cdn.jsdelivr.net/npm/@rettangoli/ui@1.0.0-
|
|
43
|
+
<script src="https://cdn.jsdelivr.net/npm/@rettangoli/ui@1.0.0-rc15/dist/rettangoli-iife-ui.min.js"></script>
|
|
44
44
|
<script src="/public/main.js"></script>
|
|
45
45
|
</head>
|
|
46
46
|
<body class="dark">
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
<head>
|
|
5
5
|
<meta charset="UTF-8">
|
|
6
6
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
7
|
-
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@rettangoli/ui@1.0.0-
|
|
8
|
-
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@rettangoli/ui@1.0.0-
|
|
7
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@rettangoli/ui@1.0.0-rc15/dist/themes/base.css">
|
|
8
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@rettangoli/ui@1.0.0-rc15/dist/themes/theme-rtgl-slate.css">
|
|
9
9
|
<script>
|
|
10
10
|
window.addEventListener('DOMContentLoaded', () => {
|
|
11
11
|
if (location.hash) {
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
});
|
|
18
18
|
</script>
|
|
19
19
|
<script src="https://cdn.jsdelivr.net/npm/construct-style-sheets-polyfill@3.1.0/dist/adoptedStyleSheets.min.js"></script>
|
|
20
|
-
<script src="https://cdn.jsdelivr.net/npm/@rettangoli/ui@1.0.0-
|
|
20
|
+
<script src="https://cdn.jsdelivr.net/npm/@rettangoli/ui@1.0.0-rc15/dist/rettangoli-iife-ui.min.js"></script>
|
|
21
21
|
|
|
22
22
|
<style>
|
|
23
23
|
pre {
|
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
<head>
|
|
5
5
|
<meta charset="UTF-8">
|
|
6
6
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
7
|
-
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@rettangoli/ui@1.0.0-
|
|
8
|
-
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@rettangoli/ui@1.0.0-
|
|
7
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@rettangoli/ui@1.0.0-rc15/dist/themes/base.css">
|
|
8
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@rettangoli/ui@1.0.0-rc15/dist/themes/theme-rtgl-slate.css">
|
|
9
9
|
<script src="https://cdn.jsdelivr.net/npm/construct-style-sheets-polyfill@3.1.0/dist/adoptedStyleSheets.min.js"></script>
|
|
10
|
-
<script src="https://cdn.jsdelivr.net/npm/@rettangoli/ui@1.0.0-
|
|
10
|
+
<script src="https://cdn.jsdelivr.net/npm/@rettangoli/ui@1.0.0-rc15/dist/rettangoli-iife-ui.min.js"></script>
|
|
11
11
|
<style>
|
|
12
12
|
code {
|
|
13
13
|
white-space: pre-wrap;
|