@recursica/adapter-tester 4.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 +17 -12
- package/dist/adapter-tester.schema.json.d.ts +20 -8
- package/dist/cli.cjs +25 -17
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +289 -213
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +19 -6
- 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 +11 -5
- package/dist/fileConfig.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 +28 -4
- 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.js +227 -201
- package/dist/testing.js.map +1 -1
- package/package.json +1 -1
- package/src/adapter-tester.schema.json +20 -8
- package/dist/mantineSourceOfTruth-BUb5MZy0.cjs.map +0 -1
- package/dist/mantineSourceOfTruth-BUkqMNEo.js.map +0 -1
package/dist/testing.js
CHANGED
|
@@ -1,327 +1,353 @@
|
|
|
1
|
-
import { expect as
|
|
2
|
-
import { existsSync as
|
|
3
|
-
import
|
|
4
|
-
import { PNG as
|
|
5
|
-
import { join as
|
|
6
|
-
import { a as
|
|
7
|
-
function
|
|
8
|
-
const
|
|
9
|
-
if (
|
|
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
10
|
return { diffPixels: 1 / 0, diffImage: null };
|
|
11
|
-
const
|
|
12
|
-
return { diffPixels:
|
|
13
|
-
n.data,
|
|
14
|
-
r.data,
|
|
11
|
+
const s = new P({ width: o.width, height: o.height });
|
|
12
|
+
return { diffPixels: re(
|
|
15
13
|
o.data,
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
r.data,
|
|
15
|
+
s.data,
|
|
16
|
+
o.width,
|
|
17
|
+
o.height,
|
|
18
18
|
{ threshold: 0.1 }
|
|
19
|
-
), diffImage:
|
|
19
|
+
), diffImage: P.sync.write(s) };
|
|
20
20
|
}
|
|
21
|
-
const
|
|
22
|
-
$schema:
|
|
23
|
-
$id:
|
|
24
|
-
title:
|
|
25
|
-
description:
|
|
26
|
-
type:
|
|
27
|
-
additionalProperties:
|
|
28
|
-
},
|
|
29
|
-
|
|
30
|
-
const
|
|
31
|
-
function
|
|
32
|
-
if (
|
|
33
|
-
const
|
|
34
|
-
var
|
|
35
|
-
const
|
|
36
|
-
return ` - ${r.instancePath || "root"} ${r.message}${
|
|
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}`;
|
|
37
37
|
}).join(`
|
|
38
38
|
`);
|
|
39
39
|
throw new Error(`Invalid ${t}:
|
|
40
|
-
${
|
|
40
|
+
${o}`);
|
|
41
41
|
}
|
|
42
|
-
function
|
|
43
|
-
return
|
|
42
|
+
function A(e) {
|
|
43
|
+
return G(e, "manifest.json");
|
|
44
44
|
}
|
|
45
|
-
function
|
|
46
|
-
return
|
|
45
|
+
function W(e) {
|
|
46
|
+
return G(e, "manifest.json.lock");
|
|
47
47
|
}
|
|
48
|
-
function
|
|
49
|
-
return
|
|
48
|
+
function S(e, t) {
|
|
49
|
+
return G(e, `${t}.png`);
|
|
50
50
|
}
|
|
51
|
-
function
|
|
52
|
-
const t =
|
|
53
|
-
if (!
|
|
54
|
-
const
|
|
55
|
-
return
|
|
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;
|
|
56
56
|
}
|
|
57
|
-
function
|
|
58
|
-
const
|
|
59
|
-
|
|
57
|
+
function fe(e, t) {
|
|
58
|
+
const o = A(e);
|
|
59
|
+
F(t, o);
|
|
60
60
|
const r = {};
|
|
61
|
-
for (const
|
|
62
|
-
r[
|
|
63
|
-
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
`),
|
|
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
67
|
}
|
|
68
|
-
const
|
|
69
|
-
function
|
|
68
|
+
const pe = 25, ge = 15e3;
|
|
69
|
+
function me(e) {
|
|
70
70
|
return new Promise((t) => setTimeout(t, e));
|
|
71
71
|
}
|
|
72
|
-
async function
|
|
73
|
-
|
|
74
|
-
const t =
|
|
72
|
+
async function we(e) {
|
|
73
|
+
b(e, { recursive: !0 });
|
|
74
|
+
const t = W(e), o = Date.now() + ge;
|
|
75
75
|
for (; ; )
|
|
76
76
|
try {
|
|
77
|
-
|
|
77
|
+
Q(Z(t, "wx"));
|
|
78
78
|
return;
|
|
79
79
|
} catch (r) {
|
|
80
80
|
if (r.code !== "EEXIST") throw r;
|
|
81
|
-
if (Date.now() >=
|
|
81
|
+
if (Date.now() >= o)
|
|
82
82
|
throw new Error(
|
|
83
83
|
`Timed out waiting for the manifest lock at "${t}" — delete it if a previous run crashed while holding it.`
|
|
84
84
|
);
|
|
85
|
-
await
|
|
85
|
+
await me(pe);
|
|
86
86
|
}
|
|
87
87
|
}
|
|
88
|
-
function
|
|
89
|
-
|
|
88
|
+
function ye(e) {
|
|
89
|
+
te(W(e), { force: !0 });
|
|
90
90
|
}
|
|
91
|
-
async function
|
|
92
|
-
await
|
|
91
|
+
async function X(e, t, o) {
|
|
92
|
+
await we(e);
|
|
93
93
|
try {
|
|
94
|
-
const r =
|
|
95
|
-
return
|
|
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
96
|
} finally {
|
|
97
|
-
|
|
97
|
+
ye(e);
|
|
98
98
|
}
|
|
99
99
|
}
|
|
100
|
-
function
|
|
101
|
-
|
|
100
|
+
function ve(e, t, o) {
|
|
101
|
+
b(e, { recursive: !0 }), E(S(e, t), o);
|
|
102
102
|
}
|
|
103
|
-
async function
|
|
104
|
-
const
|
|
105
|
-
(
|
|
103
|
+
async function Te(e, t) {
|
|
104
|
+
const o = j(e), r = Object.keys(o).filter(
|
|
105
|
+
(s) => !t.has(s)
|
|
106
106
|
);
|
|
107
|
-
for (const
|
|
108
|
-
const
|
|
109
|
-
|
|
107
|
+
for (const s of r) {
|
|
108
|
+
const i = S(e, s);
|
|
109
|
+
v(i) && Y(i), await X(e, s, () => {
|
|
110
110
|
});
|
|
111
111
|
}
|
|
112
112
|
return r;
|
|
113
113
|
}
|
|
114
|
-
const
|
|
115
|
-
async function
|
|
116
|
-
var
|
|
117
|
-
const
|
|
118
|
-
if (!
|
|
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)
|
|
119
119
|
throw new Error(
|
|
120
|
-
`Could not reach npm registry for ${e}: ${
|
|
120
|
+
`Could not reach npm registry for ${e}: ${o.statusText}`
|
|
121
121
|
);
|
|
122
|
-
const r = await
|
|
123
|
-
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)
|
|
124
124
|
throw new Error(
|
|
125
125
|
`${e} has no version or dist-tag "${t}" on the npm registry.`
|
|
126
126
|
);
|
|
127
|
-
return
|
|
127
|
+
return s;
|
|
128
128
|
}
|
|
129
|
-
function
|
|
129
|
+
function ke(e) {
|
|
130
130
|
return `packages/${e.split("/").pop()}`;
|
|
131
131
|
}
|
|
132
|
-
async function
|
|
132
|
+
async function xe(e) {
|
|
133
133
|
if (e.type === "local")
|
|
134
|
-
return
|
|
135
|
-
manifest:
|
|
136
|
-
async readImage(
|
|
137
|
-
const
|
|
138
|
-
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;
|
|
139
139
|
}
|
|
140
140
|
} : (console.warn(
|
|
141
141
|
`No golden baseline found yet at ${e.dir} — source-of-truth divergence check skipped for this run.`
|
|
142
142
|
), null);
|
|
143
143
|
let t;
|
|
144
144
|
try {
|
|
145
|
-
t = await
|
|
145
|
+
t = await Oe(
|
|
146
146
|
e.packageName,
|
|
147
147
|
e.versionSpec
|
|
148
148
|
);
|
|
149
|
-
} catch (
|
|
149
|
+
} catch (a) {
|
|
150
150
|
return console.warn(
|
|
151
151
|
`Could not resolve ${e.packageName}@${e.versionSpec} — source-of-truth divergence check skipped for this run.`,
|
|
152
|
-
|
|
152
|
+
a
|
|
153
153
|
), null;
|
|
154
154
|
}
|
|
155
|
-
const
|
|
156
|
-
let
|
|
157
|
-
const d =
|
|
158
|
-
if (
|
|
159
|
-
|
|
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);
|
|
160
160
|
else {
|
|
161
|
-
let
|
|
161
|
+
let a;
|
|
162
162
|
try {
|
|
163
|
-
|
|
163
|
+
a = await fetch(`${s}/manifest.json`);
|
|
164
164
|
} catch (f) {
|
|
165
165
|
return console.warn(
|
|
166
166
|
`Could not reach GitHub to fetch ${r}'s golden baseline — source-of-truth divergence check skipped for this run.`,
|
|
167
167
|
f
|
|
168
168
|
), null;
|
|
169
169
|
}
|
|
170
|
-
if (!
|
|
170
|
+
if (!a.ok)
|
|
171
171
|
return console.warn(
|
|
172
172
|
`No golden baseline published for ${r} — source-of-truth divergence check skipped for this run.`
|
|
173
173
|
), null;
|
|
174
|
-
const
|
|
175
|
-
|
|
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;
|
|
176
176
|
}
|
|
177
177
|
return {
|
|
178
|
-
manifest:
|
|
179
|
-
async readImage(
|
|
180
|
-
const
|
|
181
|
-
if (
|
|
182
|
-
const
|
|
183
|
-
if (!
|
|
184
|
-
const f = Buffer.from(await
|
|
185
|
-
return
|
|
178
|
+
manifest: i,
|
|
179
|
+
async readImage(a) {
|
|
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;
|
|
186
186
|
}
|
|
187
187
|
};
|
|
188
188
|
}
|
|
189
|
-
const
|
|
190
|
-
function
|
|
189
|
+
const be = ["Theme", "Tokens", "Introduction"];
|
|
190
|
+
function B(e, t) {
|
|
191
191
|
return e === t || e.startsWith(t);
|
|
192
192
|
}
|
|
193
|
-
async function
|
|
194
|
-
let
|
|
193
|
+
async function Se(e, t) {
|
|
194
|
+
let o;
|
|
195
195
|
try {
|
|
196
|
-
const
|
|
197
|
-
if (!
|
|
196
|
+
const r = await fetch(`${e.url}/index.json`);
|
|
197
|
+
if (!r.ok)
|
|
198
198
|
throw new Error(
|
|
199
|
-
`Failed to fetch Storybook index: ${
|
|
199
|
+
`Failed to fetch Storybook index: ${r.statusText}`
|
|
200
200
|
);
|
|
201
|
-
const
|
|
202
|
-
|
|
203
|
-
(
|
|
204
|
-
(
|
|
205
|
-
)
|
|
206
|
-
),
|
|
207
|
-
} 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) {
|
|
208
208
|
throw console.error(
|
|
209
209
|
"Failed to load Storybook index from",
|
|
210
210
|
`${e.url}/index.json`,
|
|
211
|
-
|
|
211
|
+
r
|
|
212
212
|
), new Error(
|
|
213
213
|
`Storybook target "${e.name}" is not responsive or index.json is missing. Please ensure its Storybook is running.`
|
|
214
214
|
);
|
|
215
215
|
}
|
|
216
|
-
return
|
|
216
|
+
return o;
|
|
217
217
|
}
|
|
218
|
-
function
|
|
218
|
+
function K(e, t, o) {
|
|
219
219
|
let r;
|
|
220
|
-
for (const
|
|
221
|
-
|
|
222
|
-
return r !== void 0 ? t[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;
|
|
223
223
|
}
|
|
224
|
-
async function
|
|
225
|
-
const t = e.isSourceOfTruthAdapter ? e.targets[0] : e.targets.find((
|
|
224
|
+
async function Ie(e) {
|
|
225
|
+
const t = e.isSourceOfTruthAdapter ? e.targets[0] : e.targets.find((n) => !n.sourceOfTruth);
|
|
226
226
|
if (!t)
|
|
227
227
|
throw new Error(
|
|
228
228
|
"adapter-tester config has no non-sourceOfTruth target to run the golden check against."
|
|
229
229
|
);
|
|
230
|
-
const
|
|
231
|
-
(
|
|
232
|
-
),
|
|
233
|
-
Object.entries(r).filter(([,
|
|
234
|
-
), d =
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
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
238
|
);
|
|
239
|
-
if (
|
|
240
|
-
const
|
|
241
|
-
|
|
242
|
-
new Set(
|
|
239
|
+
if (h === "update-golden") {
|
|
240
|
+
const n = await Te(
|
|
241
|
+
a,
|
|
242
|
+
new Set(M.map((u) => u.id))
|
|
243
243
|
);
|
|
244
|
-
|
|
245
|
-
`Pruned ${
|
|
244
|
+
n.length > 0 && console.warn(
|
|
245
|
+
`Pruned ${n.length} orphaned golden(s) no longer in Storybook: ${n.join(", ")}`
|
|
246
246
|
);
|
|
247
247
|
}
|
|
248
|
-
const
|
|
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";
|
|
249
267
|
return {
|
|
250
268
|
ownTargetName: t.name,
|
|
251
|
-
suiteLabel:
|
|
252
|
-
stories:
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
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`,
|
|
257
276
|
{ waitUntil: "networkidle" }
|
|
258
|
-
), await
|
|
259
|
-
const
|
|
260
|
-
let
|
|
261
|
-
if (
|
|
262
|
-
|
|
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 ? {
|
|
263
282
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
264
|
-
sourceOfTruthCreatedAt:
|
|
265
|
-
} : { createdAt: (/* @__PURE__ */ new Date()).toISOString() },
|
|
283
|
+
sourceOfTruthCreatedAt: g.sourceOfTruthCreatedAt
|
|
284
|
+
} : { createdAt: (/* @__PURE__ */ new Date()).toISOString() }, g || l.annotations.push({
|
|
266
285
|
type: "golden-created",
|
|
267
|
-
description: `No golden existed yet for "${
|
|
286
|
+
description: `No golden existed yet for "${n.id}" — captured one from this run.`
|
|
268
287
|
});
|
|
269
|
-
else if (
|
|
270
|
-
const
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
),
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
e.
|
|
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
|
|
277
296
|
);
|
|
278
|
-
|
|
279
|
-
body:
|
|
297
|
+
w >= y && (await l.attach("expected", {
|
|
298
|
+
body: m,
|
|
280
299
|
contentType: "image/png"
|
|
281
|
-
}), await
|
|
282
|
-
body:
|
|
300
|
+
}), await l.attach("actual", {
|
|
301
|
+
body: I,
|
|
283
302
|
contentType: "image/png"
|
|
284
|
-
}), k && await
|
|
303
|
+
}), k && await l.attach("diff", {
|
|
285
304
|
body: k,
|
|
286
305
|
contentType: "image/png"
|
|
287
|
-
})),
|
|
288
|
-
|
|
289
|
-
`"${
|
|
290
|
-
).toBeLessThan(
|
|
306
|
+
})), J.soft(
|
|
307
|
+
w,
|
|
308
|
+
`"${n.id}" has drifted from its own golden image (${w} mismatched pixels, threshold ${y})`
|
|
309
|
+
).toBeLessThan(y);
|
|
291
310
|
}
|
|
292
|
-
if (
|
|
293
|
-
const
|
|
294
|
-
if (
|
|
295
|
-
if (
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
sourceOfTruthCreatedAt:
|
|
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
|
|
299
318
|
};
|
|
300
319
|
else {
|
|
301
|
-
const k =
|
|
320
|
+
const k = x(C), { diffPixels: y, diffImage: L } = R(
|
|
302
321
|
k,
|
|
303
|
-
|
|
304
|
-
),
|
|
305
|
-
|
|
306
|
-
|
|
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,
|
|
307
330
|
contentType: "image/png"
|
|
308
|
-
}), await
|
|
331
|
+
}), await l.attach("actual", {
|
|
309
332
|
body: k,
|
|
310
333
|
contentType: "image/png"
|
|
311
|
-
}),
|
|
312
|
-
body:
|
|
334
|
+
}), L && await l.attach("diff", {
|
|
335
|
+
body: L,
|
|
313
336
|
contentType: "image/png"
|
|
314
|
-
}),
|
|
337
|
+
}), l.annotations.push({
|
|
315
338
|
type: "source-of-truth-divergence",
|
|
316
|
-
description: `"${
|
|
317
|
-
}))
|
|
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);
|
|
318
344
|
}
|
|
319
345
|
}
|
|
320
|
-
await
|
|
346
|
+
await X(a, n.id, () => $);
|
|
321
347
|
}
|
|
322
348
|
};
|
|
323
349
|
}
|
|
324
350
|
export {
|
|
325
|
-
|
|
351
|
+
Ie as resolveVisualRegressionPlan
|
|
326
352
|
};
|
|
327
353
|
//# sourceMappingURL=testing.js.map
|