@recursica/adapter-tester 3.0.0 → 5.0.0
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 +47 -27
- package/dist/adapter-tester.schema.json.d.ts +36 -15
- package/dist/cli.cjs +41 -20
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +344 -218
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +38 -14
- package/dist/config.d.ts.map +1 -1
- package/dist/devServer.d.ts +1 -1
- package/dist/devServer.d.ts.map +1 -1
- package/dist/fileConfig.d.ts +25 -10
- package/dist/fileConfig.d.ts.map +1 -1
- package/dist/golden/diffPng.d.ts +12 -7
- package/dist/golden/diffPng.d.ts.map +1 -1
- package/dist/golden/manifestStore.d.ts +19 -1
- package/dist/golden/manifestStore.d.ts.map +1 -1
- package/dist/harness/mantineSourceOfTruth.d.ts +10 -1
- package/dist/harness/mantineSourceOfTruth.d.ts.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/{mantineSourceOfTruth-BUkqMNEo.js → mantineSourceOfTruth-DE7XOgea.js} +36 -34
- package/dist/mantineSourceOfTruth-DE7XOgea.js.map +1 -0
- package/dist/{mantineSourceOfTruth-BUb5MZy0.cjs → mantineSourceOfTruth-Dpe4mlmF.cjs} +6 -6
- package/dist/mantineSourceOfTruth-Dpe4mlmF.cjs.map +1 -0
- package/dist/portDiscovery.d.ts +39 -0
- package/dist/portDiscovery.d.ts.map +1 -0
- package/dist/testing/runVisualRegression.d.ts +69 -20
- package/dist/testing/runVisualRegression.d.ts.map +1 -1
- package/dist/testing.cjs +4 -3
- package/dist/testing.cjs.map +1 -1
- package/dist/testing.d.ts +1 -1
- package/dist/testing.d.ts.map +1 -1
- package/dist/testing.js +286 -174
- package/dist/testing.js.map +1 -1
- package/package.json +2 -6
- package/src/adapter-tester.schema.json +36 -15
- package/dist/mantineSourceOfTruth-BUb5MZy0.cjs.map +0 -1
- package/dist/mantineSourceOfTruth-BUkqMNEo.js.map +0 -1
package/dist/testing.js
CHANGED
|
@@ -1,95 +1,148 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { existsSync as
|
|
3
|
-
import
|
|
4
|
-
import { PNG as
|
|
5
|
-
import { join as
|
|
6
|
-
import { a as
|
|
7
|
-
function
|
|
8
|
-
const
|
|
9
|
-
if (
|
|
10
|
-
return 1 / 0;
|
|
11
|
-
const
|
|
12
|
-
return
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
1
|
+
import { expect as J } from "@playwright/test";
|
|
2
|
+
import { existsSync as v, unlinkSync as Y, readFileSync as x, mkdirSync as b, writeFileSync as E, closeSync as Q, openSync as Z, renameSync as ee, rmSync as te } from "node:fs";
|
|
3
|
+
import re from "pixelmatch";
|
|
4
|
+
import { PNG as P } from "pngjs";
|
|
5
|
+
import { join as G } from "node:path";
|
|
6
|
+
import { a as oe, i as ne } from "./index-DqQzFSAH.js";
|
|
7
|
+
function R(e, t) {
|
|
8
|
+
const o = P.sync.read(e), r = P.sync.read(t);
|
|
9
|
+
if (o.width !== r.width || o.height !== r.height)
|
|
10
|
+
return { diffPixels: 1 / 0, diffImage: null };
|
|
11
|
+
const s = new P({ width: o.width, height: o.height });
|
|
12
|
+
return { diffPixels: re(
|
|
13
|
+
o.data,
|
|
14
|
+
r.data,
|
|
15
|
+
s.data,
|
|
16
|
+
o.width,
|
|
17
|
+
o.height,
|
|
18
|
+
{ threshold: 0.1 }
|
|
19
|
+
), diffImage: P.sync.write(s) };
|
|
20
|
+
}
|
|
21
|
+
const se = "http://json-schema.org/draft-07/schema#", ie = "https://github.com/borderux/recursica/tree/main/packages/adapter-tester/src/golden/manifest.schema.json", ae = "test/golden/manifest.json", ce = "Tracks golden (baseline) image metadata for @recursica/adapter-tester's golden-image visual regression checks. One manifest lives alongside its adapter's test/golden/<story-id>.png files, keyed by story id.", de = "object", he = { type: "object", additionalProperties: !1, required: ["createdAt"], properties: { createdAt: { type: "string", format: "date-time", description: "When this story's own golden PNG was last captured, via --update-golden, --approve-divergence, or first-run auto-create." }, sourceOfTruthCreatedAt: { type: "string", format: "date-time", description: "The source-of-truth adapter's (mantine) manifest `createdAt` for this story at the time this adapter's divergence from it was last reviewed via --approve-divergence. Omitted on the source-of-truth adapter's own manifest, and omitted here until the first approval. If mantine's current `createdAt` for this story is newer than this value, the divergence is flagged again for re-review." } } }, ue = {
|
|
22
|
+
$schema: se,
|
|
23
|
+
$id: ie,
|
|
24
|
+
title: ae,
|
|
25
|
+
description: ce,
|
|
26
|
+
type: de,
|
|
27
|
+
additionalProperties: he
|
|
28
|
+
}, le = ne, V = new oe.Ajv({ allErrors: !0, strict: !0 });
|
|
29
|
+
le(V);
|
|
30
|
+
const U = V.compile(ue);
|
|
31
|
+
function F(e, t) {
|
|
32
|
+
if (U(e)) return;
|
|
33
|
+
const o = (U.errors ?? []).map((r) => {
|
|
34
|
+
var i;
|
|
35
|
+
const s = (i = r.params) != null && i.additionalProperty ? ` '${r.params.additionalProperty}'` : "";
|
|
36
|
+
return ` - ${r.instancePath || "root"} ${r.message}${s}`;
|
|
32
37
|
}).join(`
|
|
33
38
|
`);
|
|
34
39
|
throw new Error(`Invalid ${t}:
|
|
35
|
-
${
|
|
36
|
-
}
|
|
37
|
-
function
|
|
38
|
-
return
|
|
39
|
-
}
|
|
40
|
-
function
|
|
41
|
-
return
|
|
42
|
-
}
|
|
43
|
-
function
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
S(t, r);
|
|
52
|
-
const s = {};
|
|
53
|
-
for (const o of Object.keys(t).sort())
|
|
54
|
-
s[o] = t[o];
|
|
55
|
-
w(e, { recursive: !0 }), y(r, JSON.stringify(s, null, 2) + `
|
|
56
|
-
`);
|
|
40
|
+
${o}`);
|
|
41
|
+
}
|
|
42
|
+
function A(e) {
|
|
43
|
+
return G(e, "manifest.json");
|
|
44
|
+
}
|
|
45
|
+
function W(e) {
|
|
46
|
+
return G(e, "manifest.json.lock");
|
|
47
|
+
}
|
|
48
|
+
function S(e, t) {
|
|
49
|
+
return G(e, `${t}.png`);
|
|
50
|
+
}
|
|
51
|
+
function j(e) {
|
|
52
|
+
const t = A(e);
|
|
53
|
+
if (!v(t)) return {};
|
|
54
|
+
const o = JSON.parse(x(t, "utf8"));
|
|
55
|
+
return F(o, t), o;
|
|
57
56
|
}
|
|
58
|
-
function
|
|
59
|
-
|
|
57
|
+
function fe(e, t) {
|
|
58
|
+
const o = A(e);
|
|
59
|
+
F(t, o);
|
|
60
|
+
const r = {};
|
|
61
|
+
for (const i of Object.keys(t).sort())
|
|
62
|
+
r[i] = t[i];
|
|
63
|
+
b(e, { recursive: !0 });
|
|
64
|
+
const s = `${o}.tmp-${process.pid}-${Math.random().toString(36).slice(2)}`;
|
|
65
|
+
E(s, JSON.stringify(r, null, 2) + `
|
|
66
|
+
`), ee(s, o);
|
|
67
|
+
}
|
|
68
|
+
const pe = 25, ge = 15e3;
|
|
69
|
+
function me(e) {
|
|
70
|
+
return new Promise((t) => setTimeout(t, e));
|
|
71
|
+
}
|
|
72
|
+
async function we(e) {
|
|
73
|
+
b(e, { recursive: !0 });
|
|
74
|
+
const t = W(e), o = Date.now() + ge;
|
|
75
|
+
for (; ; )
|
|
76
|
+
try {
|
|
77
|
+
Q(Z(t, "wx"));
|
|
78
|
+
return;
|
|
79
|
+
} catch (r) {
|
|
80
|
+
if (r.code !== "EEXIST") throw r;
|
|
81
|
+
if (Date.now() >= o)
|
|
82
|
+
throw new Error(
|
|
83
|
+
`Timed out waiting for the manifest lock at "${t}" — delete it if a previous run crashed while holding it.`
|
|
84
|
+
);
|
|
85
|
+
await me(pe);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
function ye(e) {
|
|
89
|
+
te(W(e), { force: !0 });
|
|
90
|
+
}
|
|
91
|
+
async function X(e, t, o) {
|
|
92
|
+
await we(e);
|
|
93
|
+
try {
|
|
94
|
+
const r = j(e), s = o(r[t]);
|
|
95
|
+
return s === void 0 ? delete r[t] : r[t] = s, fe(e, r), s;
|
|
96
|
+
} finally {
|
|
97
|
+
ye(e);
|
|
98
|
+
}
|
|
60
99
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
100
|
+
function ve(e, t, o) {
|
|
101
|
+
b(e, { recursive: !0 }), E(S(e, t), o);
|
|
102
|
+
}
|
|
103
|
+
async function Te(e, t) {
|
|
104
|
+
const o = j(e), r = Object.keys(o).filter(
|
|
105
|
+
(s) => !t.has(s)
|
|
106
|
+
);
|
|
107
|
+
for (const s of r) {
|
|
108
|
+
const i = S(e, s);
|
|
109
|
+
v(i) && Y(i), await X(e, s, () => {
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
return r;
|
|
113
|
+
}
|
|
114
|
+
const $e = "borderux/recursica";
|
|
115
|
+
async function Oe(e, t) {
|
|
116
|
+
var i, d;
|
|
117
|
+
const o = await fetch(`https://registry.npmjs.org/${e}`);
|
|
118
|
+
if (!o.ok)
|
|
66
119
|
throw new Error(
|
|
67
|
-
`Could not reach npm registry for ${e}: ${
|
|
120
|
+
`Could not reach npm registry for ${e}: ${o.statusText}`
|
|
68
121
|
);
|
|
69
|
-
const
|
|
70
|
-
if (!
|
|
122
|
+
const r = await o.json(), s = ((i = r["dist-tags"]) == null ? void 0 : i[t]) ?? ((d = r.versions) != null && d[t] ? t : void 0);
|
|
123
|
+
if (!s)
|
|
71
124
|
throw new Error(
|
|
72
125
|
`${e} has no version or dist-tag "${t}" on the npm registry.`
|
|
73
126
|
);
|
|
74
|
-
return
|
|
127
|
+
return s;
|
|
75
128
|
}
|
|
76
|
-
function
|
|
129
|
+
function ke(e) {
|
|
77
130
|
return `packages/${e.split("/").pop()}`;
|
|
78
131
|
}
|
|
79
|
-
async function
|
|
132
|
+
async function xe(e) {
|
|
80
133
|
if (e.type === "local")
|
|
81
|
-
return
|
|
82
|
-
manifest:
|
|
83
|
-
async readImage(
|
|
84
|
-
const
|
|
85
|
-
return
|
|
134
|
+
return v(A(e.dir)) ? {
|
|
135
|
+
manifest: j(e.dir),
|
|
136
|
+
async readImage(h) {
|
|
137
|
+
const c = S(e.dir, h);
|
|
138
|
+
return v(c) ? x(c) : null;
|
|
86
139
|
}
|
|
87
140
|
} : (console.warn(
|
|
88
141
|
`No golden baseline found yet at ${e.dir} — source-of-truth divergence check skipped for this run.`
|
|
89
142
|
), null);
|
|
90
143
|
let t;
|
|
91
144
|
try {
|
|
92
|
-
t = await
|
|
145
|
+
t = await Oe(
|
|
93
146
|
e.packageName,
|
|
94
147
|
e.versionSpec
|
|
95
148
|
);
|
|
@@ -99,143 +152,202 @@ async function te(e) {
|
|
|
99
152
|
a
|
|
100
153
|
), null;
|
|
101
154
|
}
|
|
102
|
-
const
|
|
103
|
-
let
|
|
104
|
-
const
|
|
105
|
-
if (
|
|
106
|
-
|
|
155
|
+
const o = G(e.cacheDir, t), r = `${e.packageName}@${t}`, s = `https://raw.githubusercontent.com/${$e}/${r}/${ke(e.packageName)}/test/golden`;
|
|
156
|
+
let i;
|
|
157
|
+
const d = A(o);
|
|
158
|
+
if (v(d))
|
|
159
|
+
i = j(o);
|
|
107
160
|
else {
|
|
108
161
|
let a;
|
|
109
162
|
try {
|
|
110
|
-
a = await fetch(`${
|
|
111
|
-
} catch (
|
|
163
|
+
a = await fetch(`${s}/manifest.json`);
|
|
164
|
+
} catch (f) {
|
|
112
165
|
return console.warn(
|
|
113
|
-
`Could not reach GitHub to fetch ${
|
|
114
|
-
|
|
166
|
+
`Could not reach GitHub to fetch ${r}'s golden baseline — source-of-truth divergence check skipped for this run.`,
|
|
167
|
+
f
|
|
115
168
|
), null;
|
|
116
169
|
}
|
|
117
170
|
if (!a.ok)
|
|
118
171
|
return console.warn(
|
|
119
|
-
`No golden baseline published for ${
|
|
172
|
+
`No golden baseline published for ${r} — source-of-truth divergence check skipped for this run.`
|
|
120
173
|
), null;
|
|
121
|
-
const
|
|
122
|
-
|
|
174
|
+
const h = await a.text(), c = JSON.parse(h);
|
|
175
|
+
F(c, `${s}/manifest.json`), b(o, { recursive: !0 }), E(d, h), i = c;
|
|
123
176
|
}
|
|
124
177
|
return {
|
|
125
|
-
manifest:
|
|
178
|
+
manifest: i,
|
|
126
179
|
async readImage(a) {
|
|
127
|
-
const
|
|
128
|
-
if (
|
|
129
|
-
const
|
|
130
|
-
if (!
|
|
131
|
-
const
|
|
132
|
-
return
|
|
180
|
+
const h = S(o, a);
|
|
181
|
+
if (v(h)) return x(h);
|
|
182
|
+
const c = await fetch(`${s}/${a}.png`);
|
|
183
|
+
if (!c.ok) return null;
|
|
184
|
+
const f = Buffer.from(await c.arrayBuffer());
|
|
185
|
+
return b(o, { recursive: !0 }), E(h, f), f;
|
|
133
186
|
}
|
|
134
187
|
};
|
|
135
188
|
}
|
|
136
|
-
const
|
|
137
|
-
function
|
|
189
|
+
const be = ["Theme", "Tokens", "Introduction"];
|
|
190
|
+
function B(e, t) {
|
|
138
191
|
return e === t || e.startsWith(t);
|
|
139
192
|
}
|
|
140
|
-
async function
|
|
141
|
-
let
|
|
193
|
+
async function Se(e, t) {
|
|
194
|
+
let o;
|
|
142
195
|
try {
|
|
143
|
-
const
|
|
144
|
-
if (!
|
|
196
|
+
const r = await fetch(`${e.url}/index.json`);
|
|
197
|
+
if (!r.ok)
|
|
145
198
|
throw new Error(
|
|
146
|
-
`Failed to fetch Storybook index: ${
|
|
199
|
+
`Failed to fetch Storybook index: ${r.statusText}`
|
|
147
200
|
);
|
|
148
|
-
const
|
|
149
|
-
|
|
150
|
-
(
|
|
151
|
-
(
|
|
152
|
-
)
|
|
153
|
-
),
|
|
154
|
-
} catch (
|
|
201
|
+
const i = (await r.json()).entries || {};
|
|
202
|
+
o = Object.values(i).filter(
|
|
203
|
+
(d) => d.type === "story" && !t.some(
|
|
204
|
+
(a) => d.title === a || d.title.startsWith(`${a}/`)
|
|
205
|
+
)
|
|
206
|
+
), o.sort((d, a) => d.id.localeCompare(a.id));
|
|
207
|
+
} catch (r) {
|
|
155
208
|
throw console.error(
|
|
156
209
|
"Failed to load Storybook index from",
|
|
157
210
|
`${e.url}/index.json`,
|
|
158
|
-
|
|
211
|
+
r
|
|
159
212
|
), new Error(
|
|
160
213
|
`Storybook target "${e.name}" is not responsive or index.json is missing. Please ensure its Storybook is running.`
|
|
161
214
|
);
|
|
162
215
|
}
|
|
163
|
-
return
|
|
216
|
+
return o;
|
|
164
217
|
}
|
|
165
|
-
function
|
|
166
|
-
let
|
|
167
|
-
for (const
|
|
168
|
-
|
|
169
|
-
return
|
|
218
|
+
function K(e, t, o) {
|
|
219
|
+
let r;
|
|
220
|
+
for (const s of Object.keys(t))
|
|
221
|
+
B(e, s) && (!r || s.length > r.length) && (r = s);
|
|
222
|
+
return r !== void 0 ? t[r] : o;
|
|
170
223
|
}
|
|
171
|
-
async function
|
|
224
|
+
async function Ie(e) {
|
|
172
225
|
const t = e.isSourceOfTruthAdapter ? e.targets[0] : e.targets.find((n) => !n.sourceOfTruth);
|
|
173
226
|
if (!t)
|
|
174
227
|
throw new Error(
|
|
175
228
|
"adapter-tester config has no non-sourceOfTruth target to run the golden check against."
|
|
176
229
|
);
|
|
177
|
-
const
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
),
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
230
|
+
const o = e.excludeTitlePrefixes ?? be, r = e.stories ?? {}, s = Object.keys(r).filter(
|
|
231
|
+
(n) => r[n].exclude
|
|
232
|
+
), i = Object.fromEntries(
|
|
233
|
+
Object.entries(r).filter(([, n]) => n.goldenThreshold !== void 0).map(([n, u]) => [n, u.goldenThreshold])
|
|
234
|
+
), d = Object.fromEntries(
|
|
235
|
+
Object.entries(r).filter(([, n]) => n.sourceOfTruthThreshold !== void 0).map(([n, u]) => [n, u.sourceOfTruthThreshold])
|
|
236
|
+
), a = e.goldenDir, h = e.goldenMode, c = e.checkMode, f = await Se(t, o), M = f.filter(
|
|
237
|
+
(n) => !s.some((u) => B(n.id, u))
|
|
238
|
+
);
|
|
239
|
+
if (h === "update-golden") {
|
|
240
|
+
const n = await Te(
|
|
241
|
+
a,
|
|
242
|
+
new Set(M.map((u) => u.id))
|
|
243
|
+
);
|
|
244
|
+
n.length > 0 && console.warn(
|
|
245
|
+
`Pruned ${n.length} orphaned golden(s) no longer in Storybook: ${n.join(", ")}`
|
|
246
|
+
);
|
|
247
|
+
}
|
|
248
|
+
const p = c !== "divergence" || e.isSourceOfTruthAdapter || !e.sourceOfTruthGolden ? null : await xe(e.sourceOfTruthGolden), q = new Set(f.map((n) => n.id)), T = p ? Object.keys(p.manifest).filter(
|
|
249
|
+
(n) => !q.has(n) && !s.some((u) => B(n, u))
|
|
250
|
+
).sort() : [];
|
|
251
|
+
T.length > 0 && console.error(
|
|
252
|
+
`[adapter-tester] ${T.length} stor(y/ies) exist in the source of truth but are missing here: ${T.join(", ")}. Add the missing story, or mark it \`exclude: true\` under \`stories\` in adapter-tester.config.json if intentional.`
|
|
253
|
+
), console.log(
|
|
254
|
+
[
|
|
255
|
+
`[adapter-tester] target: "${t.name}" (${t.url})`,
|
|
256
|
+
`[adapter-tester] checkMode: "${c}" (${c === "divergence" ? "this project's golden vs source-of-truth's golden" : "live render vs this project's own golden"})`,
|
|
257
|
+
`[adapter-tester] goldenMode: "${h}"`,
|
|
258
|
+
`[adapter-tester] goldenThresholdPixels: ${e.goldenThresholdPixels}`,
|
|
259
|
+
`[adapter-tester] sourceOfTruthThresholdPixels: ${e.sourceOfTruthThresholdPixels}`,
|
|
260
|
+
c === "divergence" ? e.isSourceOfTruthAdapter ? "[adapter-tester] sourceOfTruthGolden: skipped — this is the source-of-truth adapter, nothing to diverge from" : e.sourceOfTruthGolden ? p ? `[adapter-tester] sourceOfTruthGolden: resolved, ${Object.keys(p.manifest).length} golden(s) available (config: ${JSON.stringify(e.sourceOfTruthGolden)})` : `[adapter-tester] sourceOfTruthGolden: unavailable — no baseline found or unreachable (config: ${JSON.stringify(e.sourceOfTruthGolden)}); divergence check will skip every story` : "[adapter-tester] sourceOfTruthGolden: skipped — no sourceOfTruthGolden configured" : '[adapter-tester] sourceOfTruthGolden: not used in "own" checkMode',
|
|
261
|
+
`[adapter-tester] stories: ${M.length} to check (excluded: ${s.length}, title prefixes excluded: ${o.join(", ") || "none"})`,
|
|
262
|
+
`[adapter-tester] story parity with source of truth: ${T.length === 0 ? "OK" : `${T.length} missing (see error above)`}`
|
|
263
|
+
].join(`
|
|
264
|
+
`)
|
|
265
|
+
);
|
|
266
|
+
const H = c === "divergence" ? "Source-of-Truth Divergence Check" : "Own-Drift Golden Image Check";
|
|
267
|
+
return {
|
|
268
|
+
ownTargetName: t.name,
|
|
269
|
+
suiteLabel: H,
|
|
270
|
+
stories: M,
|
|
271
|
+
missingFromSourceOfTruth: T,
|
|
272
|
+
checkStory: async (n, u, l) => {
|
|
273
|
+
const O = await u.newPage();
|
|
274
|
+
await O.setViewportSize({ width: 800, height: 600 }), await O.goto(
|
|
275
|
+
`${t.url}/iframe.html?id=${n.id}&viewMode=story`,
|
|
276
|
+
{ waitUntil: "networkidle" }
|
|
277
|
+
), await O.waitForSelector("#storybook-root"), await O.waitForTimeout(300);
|
|
278
|
+
const I = await O.screenshot(), C = S(a, n.id), g = j(a)[n.id], z = h !== "check" || !g || !v(C);
|
|
279
|
+
let $;
|
|
280
|
+
if (z)
|
|
281
|
+
ve(a, n.id, I), $ = g != null && g.sourceOfTruthCreatedAt ? {
|
|
282
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
283
|
+
sourceOfTruthCreatedAt: g.sourceOfTruthCreatedAt
|
|
284
|
+
} : { createdAt: (/* @__PURE__ */ new Date()).toISOString() }, g || l.annotations.push({
|
|
285
|
+
type: "golden-created",
|
|
286
|
+
description: `No golden existed yet for "${n.id}" — captured one from this run.`
|
|
287
|
+
});
|
|
288
|
+
else if ($ = g, c === "own") {
|
|
289
|
+
const m = x(C), { diffPixels: w, diffImage: k } = R(
|
|
290
|
+
I,
|
|
291
|
+
m
|
|
292
|
+
), y = K(
|
|
293
|
+
n.id,
|
|
294
|
+
i,
|
|
295
|
+
e.goldenThresholdPixels
|
|
296
|
+
);
|
|
297
|
+
w >= y && (await l.attach("expected", {
|
|
298
|
+
body: m,
|
|
299
|
+
contentType: "image/png"
|
|
300
|
+
}), await l.attach("actual", {
|
|
301
|
+
body: I,
|
|
302
|
+
contentType: "image/png"
|
|
303
|
+
}), k && await l.attach("diff", {
|
|
304
|
+
body: k,
|
|
305
|
+
contentType: "image/png"
|
|
306
|
+
})), J.soft(
|
|
307
|
+
w,
|
|
308
|
+
`"${n.id}" has drifted from its own golden image (${w} mismatched pixels, threshold ${y})`
|
|
309
|
+
).toBeLessThan(y);
|
|
310
|
+
}
|
|
311
|
+
if (p) {
|
|
312
|
+
const m = p.manifest[n.id], w = m ? await p.readImage(n.id) : null;
|
|
313
|
+
if (m && w)
|
|
314
|
+
if (h === "approve-divergence")
|
|
315
|
+
$ = {
|
|
316
|
+
...$,
|
|
317
|
+
sourceOfTruthCreatedAt: m.createdAt
|
|
318
|
+
};
|
|
319
|
+
else {
|
|
320
|
+
const k = x(C), { diffPixels: y, diffImage: L } = R(
|
|
321
|
+
k,
|
|
322
|
+
w
|
|
323
|
+
), N = K(
|
|
324
|
+
n.id,
|
|
325
|
+
d,
|
|
326
|
+
e.sourceOfTruthThresholdPixels
|
|
327
|
+
), _ = $.sourceOfTruthCreatedAt, D = y < N || _ !== void 0 && _ >= m.createdAt;
|
|
328
|
+
D || (await l.attach("expected", {
|
|
329
|
+
body: w,
|
|
330
|
+
contentType: "image/png"
|
|
331
|
+
}), await l.attach("actual", {
|
|
332
|
+
body: k,
|
|
333
|
+
contentType: "image/png"
|
|
334
|
+
}), L && await l.attach("diff", {
|
|
335
|
+
body: L,
|
|
336
|
+
contentType: "image/png"
|
|
337
|
+
}), l.annotations.push({
|
|
338
|
+
type: "source-of-truth-divergence",
|
|
339
|
+
description: `"${n.id}" differs from the source of truth's golden by ${y} mismatched pixels (threshold ${N}) and hasn't been reviewed — run with --approve-divergence if this is intentional, or fix the adapter styling.`
|
|
340
|
+
})), J.soft(
|
|
341
|
+
D,
|
|
342
|
+
`"${n.id}" differs from the source of truth's golden by ${y} mismatched pixels (threshold ${N}) and hasn't been reviewed — run with --approve-divergence if this is intentional, or fix the adapter styling.`
|
|
343
|
+
).toBe(!0);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
await X(a, n.id, () => $);
|
|
347
|
+
}
|
|
348
|
+
};
|
|
237
349
|
}
|
|
238
350
|
export {
|
|
239
|
-
|
|
351
|
+
Ie as resolveVisualRegressionPlan
|
|
240
352
|
};
|
|
241
353
|
//# sourceMappingURL=testing.js.map
|