tuffgal 0.2.0-alpha.2 → 0.2.0-alpha.4
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/CHANGELOG.md +41 -19
- package/README.md +6 -6
- package/dist/cli.d.ts +5 -5
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +12 -5
- package/dist/cli.js.map +1 -1
- package/dist/commands/init.d.ts +1 -1
- package/dist/commands/init.js +6 -6
- package/dist/commands/supervise.d.ts +3 -3
- package/dist/commands/supervise.js +8 -4
- package/dist/commands/supervise.js.map +1 -1
- package/dist/config.d.ts +29 -13
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +5 -2
- package/dist/config.js.map +1 -1
- package/dist/coverage/screens.d.ts +10 -5
- package/dist/coverage/screens.d.ts.map +1 -1
- package/dist/coverage/screens.js +18 -8
- package/dist/coverage/screens.js.map +1 -1
- package/dist/reporter/assets/report.css +11 -11
- package/dist/reporter/assets/report.js +81 -21
- package/dist/reporter/template.js +56 -45
- package/dist/reporter/template.js.map +1 -1
- package/dist/runner/approve.d.ts +5 -5
- package/dist/runner/approve.js +5 -5
- package/dist/runner/approveFrom.d.ts +8 -8
- package/dist/runner/approveFrom.js +32 -31
- package/dist/runner/approveFrom.js.map +1 -1
- package/dist/runner/breakpointPasses.d.ts +16 -9
- package/dist/runner/breakpointPasses.d.ts.map +1 -1
- package/dist/runner/breakpointPasses.js +17 -9
- package/dist/runner/breakpointPasses.js.map +1 -1
- package/dist/runner/bridges/devServers.d.ts +10 -1
- package/dist/runner/bridges/devServers.d.ts.map +1 -1
- package/dist/runner/bridges/devServers.js +16 -8
- package/dist/runner/bridges/devServers.js.map +1 -1
- package/dist/runner/coverage.d.ts +3 -3
- package/dist/runner/coverage.js +5 -5
- package/dist/runner/coverage.js.map +1 -1
- package/dist/runner/exitCode.d.ts +7 -7
- package/dist/runner/exitCode.js +7 -7
- package/dist/runner/interpolate.js +1 -1
- package/dist/runner/interpolate.js.map +1 -1
- package/dist/runner/manifest.d.ts +16 -16
- package/dist/runner/manifest.js +12 -12
- package/dist/runner/mode.d.ts +2 -2
- package/dist/runner/mode.js +4 -4
- package/dist/runner/orphanScan.d.ts +3 -3
- package/dist/runner/orphanScan.js +5 -5
- package/dist/runner/orphanScan.js.map +1 -1
- package/dist/runner/resolveLocator.d.ts +5 -5
- package/dist/runner/resolveLocator.js +6 -6
- package/dist/runner/resolveLocator.js.map +1 -1
- package/dist/runner/run.d.ts +55 -18
- package/dist/runner/run.d.ts.map +1 -1
- package/dist/runner/run.js +118 -67
- package/dist/runner/run.js.map +1 -1
- package/dist/runner/runAction.d.ts +4 -4
- package/dist/runner/runAction.d.ts.map +1 -1
- package/dist/runner/runAction.js +72 -34
- package/dist/runner/runAction.js.map +1 -1
- package/dist/runner/runStory.d.ts +29 -18
- package/dist/runner/runStory.d.ts.map +1 -1
- package/dist/runner/runStory.js +38 -42
- package/dist/runner/runStory.js.map +1 -1
- package/dist/runner/scheduler.d.ts +11 -0
- package/dist/runner/scheduler.d.ts.map +1 -1
- package/dist/runner/scheduler.js +1 -1
- package/dist/runner/scheduler.js.map +1 -1
- package/dist/runner/steps/intercept.d.ts +6 -4
- package/dist/runner/steps/intercept.d.ts.map +1 -1
- package/dist/runner/steps/intercept.js.map +1 -1
- package/dist/runner/steps/navigate.d.ts +5 -2
- package/dist/runner/steps/navigate.d.ts.map +1 -1
- package/dist/runner/steps/navigate.js +17 -3
- package/dist/runner/steps/navigate.js.map +1 -1
- package/dist/runner/steps/read.d.ts +1 -1
- package/dist/runner/steps/read.js +1 -1
- package/dist/runner/steps/scroll.d.ts +1 -1
- package/dist/runner/steps/scroll.d.ts.map +1 -1
- package/dist/runner/steps/scroll.js +3 -2
- package/dist/runner/steps/scroll.js.map +1 -1
- package/dist/schema/action.d.ts +2 -2
- package/dist/schema/action.d.ts.map +1 -1
- package/dist/schema/action.js +58 -13
- package/dist/schema/action.js.map +1 -1
- package/dist/schema/load.js +1 -1
- package/dist/schema/load.js.map +1 -1
- package/dist/schema/result.d.ts +22 -22
- package/dist/schema/result.d.ts.map +1 -1
- package/dist/schema/result.js +1 -1
- package/dist/schema/story.d.ts +1 -1
- package/dist/schema/story.js +5 -5
- package/dist/screenshots/baselineStore.d.ts +44 -21
- package/dist/screenshots/baselineStore.d.ts.map +1 -1
- package/dist/screenshots/baselineStore.js +59 -28
- package/dist/screenshots/baselineStore.js.map +1 -1
- package/dist/screenshots/capture.d.ts +35 -4
- package/dist/screenshots/capture.d.ts.map +1 -1
- package/dist/screenshots/capture.js +61 -9
- package/dist/screenshots/capture.js.map +1 -1
- package/dist/screenshots/diff.d.ts +57 -8
- package/dist/screenshots/diff.d.ts.map +1 -1
- package/dist/screenshots/diff.js +78 -28
- package/dist/screenshots/diff.js.map +1 -1
- package/dist/util.d.ts +23 -2
- package/dist/util.d.ts.map +1 -1
- package/dist/util.js +42 -2
- package/dist/util.js.map +1 -1
- package/package.json +4 -8
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { lstat, readFile, readdir, rm } from 'node:fs/promises';
|
|
2
2
|
import { join, relative, sep } from 'node:path';
|
|
3
3
|
import { PNG } from 'pngjs';
|
|
4
|
-
import { ACTION_NAME_PATTERN, BREAKPOINT_SEGMENT_PATTERN,
|
|
4
|
+
import { ACTION_NAME_PATTERN, BREAKPOINT_SEGMENT_PATTERN, writeDurablePng, writeText, } from "../screenshots/baselineStore.js";
|
|
5
5
|
import { CAPTURE_SCHEMA, MANIFEST_FILENAME, SCHEMA_VERSION, validateManifestShape, } from "./manifest.js";
|
|
6
6
|
import { A11Y_SUFFIX, LEGACY_A11Y, LEGACY_BREAKPOINT, LEGACY_PNG, } from "./orphanScan.js";
|
|
7
7
|
import { parseRunResult } from "../schema/result.js";
|
|
8
8
|
/**
|
|
9
9
|
* Error thrown when the candidate tree fails a trust-boundary check. Carries no
|
|
10
|
-
* extra data
|
|
10
|
+
* extra data. The message is the whole contract. Distinct type so the CLI can
|
|
11
11
|
* present it plainly; every throw here happens BEFORE any write, so the promise
|
|
12
12
|
* rejecting guarantees `paths.baselines` was not touched.
|
|
13
13
|
*/
|
|
@@ -23,11 +23,11 @@ export class ApproveFromError extends Error {
|
|
|
23
23
|
* `paths.baselines` set, and writes `<baselines>/manifest.json` from the
|
|
24
24
|
* candidate run's captured environment.
|
|
25
25
|
*
|
|
26
|
-
* TRUST BOUNDARY. `<dir>` is an untrusted artifact
|
|
26
|
+
* TRUST BOUNDARY. `<dir>` is an untrusted artifact. A human or bot unzipped it
|
|
27
27
|
* from CI. This is the only path that writes committed baselines, so it is
|
|
28
28
|
* fail-closed and validate-all-then-write:
|
|
29
29
|
* 1. `results.json` must parse, describe a clean CI run (`mode: 'ci'` with
|
|
30
|
-
* `totals.failed === 0
|
|
30
|
+
* `totals.failed === 0`, never promote a local or broken run's partial
|
|
31
31
|
* tree, see {@link assertPromotableRun}), and carry a well-shaped
|
|
32
32
|
* `environment.actual` block (validated against the manifest shape, not
|
|
33
33
|
* just present).
|
|
@@ -37,18 +37,18 @@ export class ApproveFromError extends Error {
|
|
|
37
37
|
* entry aborts with {@link ApproveFromError} and zero filesystem changes.
|
|
38
38
|
*
|
|
39
39
|
* Every candidate file's bytes are read once during phase 1 and RETAINED for
|
|
40
|
-
* phase 2, which writes exactly those bytes
|
|
40
|
+
* phase 2, which writes exactly those bytes. The sources are never re-read, so
|
|
41
41
|
* the committed baseline is provably the payload that passed validation (no
|
|
42
42
|
* decode-swap / symlink-swap window between the check and the write).
|
|
43
43
|
*
|
|
44
|
-
* PNGs are written through {@link
|
|
45
|
-
* promoted baseline is losslessly recompressed and provably decodable in
|
|
46
|
-
* step
|
|
44
|
+
* PNGs are written through {@link writeDurablePng} (decode→recompress→encode),
|
|
45
|
+
* so the promoted baseline is losslessly recompressed and provably decodable in
|
|
46
|
+
* one step, never a raw `copyFile` of unvalidated artifact bytes.
|
|
47
47
|
*/
|
|
48
48
|
export async function approveFrom(config, options) {
|
|
49
49
|
const candidateDir = options.from;
|
|
50
50
|
await assertRealDirectory(candidateDir);
|
|
51
|
-
// Phase 1
|
|
51
|
+
// Phase 1: validate the whole tree and build a write plan. Every source is
|
|
52
52
|
// read exactly ONCE here and its bytes are retained on the plan; no writes yet.
|
|
53
53
|
const result = await readCandidateResults(candidateDir);
|
|
54
54
|
assertPromotableRun(result);
|
|
@@ -58,12 +58,12 @@ export async function approveFrom(config, options) {
|
|
|
58
58
|
const pruneTargets = options.prune
|
|
59
59
|
? computePruneTargets(result, config.paths.baselines)
|
|
60
60
|
: [];
|
|
61
|
-
// Phase 2
|
|
61
|
+
// Phase 2: every check passed; commit the RETAINED bytes. Nothing is re-read
|
|
62
62
|
// from the candidate tree here, so the bytes committed are exactly the bytes
|
|
63
63
|
// that were validated (no decode-swap / symlink-swap window).
|
|
64
64
|
for (const write of plan) {
|
|
65
65
|
if (write.kind === 'png') {
|
|
66
|
-
await
|
|
66
|
+
await writeDurablePng(write.destination, write.bytes);
|
|
67
67
|
}
|
|
68
68
|
else {
|
|
69
69
|
await writeText(write.destination, write.bytes.toString('utf8'));
|
|
@@ -122,39 +122,39 @@ async function readCandidateResults(dir) {
|
|
|
122
122
|
/**
|
|
123
123
|
* Refuses to promote a candidate tree that did not come from a clean CI run.
|
|
124
124
|
* Three fail-closed gates, all derived from the candidate's own `results.json`:
|
|
125
|
-
* - `mode !== 'ci'
|
|
125
|
+
* - `mode !== 'ci'`: a local (advisory) run's candidate tree is rendered
|
|
126
126
|
* against the per-machine cache on the developer's own platform, so
|
|
127
127
|
* promoting it commits cross-platform pixels the CI gate would immediately
|
|
128
128
|
* re-flag. Only a CI-mode run's renders are eligible for the committed set.
|
|
129
|
-
* - `totals.failed` is not a number
|
|
129
|
+
* - `totals.failed` is not a number: `parseRunResult` validates only that
|
|
130
130
|
* `stories` is an array, so a truncated or foreign artifact can reach here
|
|
131
131
|
* with `totals` (or `totals.failed`) missing or non-numeric. Reading it
|
|
132
132
|
* unguarded would either throw a raw `TypeError` (not an `ApproveFromError`,
|
|
133
133
|
* breaking the trust-boundary contract) or, worse, evaluate `undefined > 0`
|
|
134
134
|
* to `false` and SILENTLY pass the gate. A non-numeric `failed` is therefore
|
|
135
135
|
* an explicit fail-closed refusal, not an assumed-zero.
|
|
136
|
-
* - `totals.failed > 0
|
|
136
|
+
* - `totals.failed > 0`: a run with failed stories produced a PARTIAL tree
|
|
137
137
|
* (broken stories wrote no candidate, or wrote a candidate mid-failure), so
|
|
138
138
|
* promoting it would commit an incomplete baseline set. A broken run is
|
|
139
139
|
* never a source of truth.
|
|
140
140
|
* All abort before any write. `mode` is read defensively (older artifacts may
|
|
141
|
-
* omit it)
|
|
141
|
+
* omit it). A missing `mode` is treated as non-`ci` and refused, since only a
|
|
142
142
|
* current CI run stamps `mode: 'ci'`.
|
|
143
143
|
*/
|
|
144
144
|
function assertPromotableRun(result) {
|
|
145
145
|
if (result.mode !== 'ci') {
|
|
146
146
|
throw new ApproveFromError(`Candidate results.json was produced by a ${result.mode ?? 'pre-mode'} ` +
|
|
147
|
-
'run, not a CI run
|
|
147
|
+
'run, not a CI run; only `mode: "ci"` candidates may be promoted into ' +
|
|
148
148
|
'committed baselines. Re-run under `tuffgal run --ci`.');
|
|
149
149
|
}
|
|
150
150
|
if (typeof result.totals?.failed !== 'number') {
|
|
151
|
-
throw new ApproveFromError('Candidate results.json is missing a numeric totals.failed count
|
|
151
|
+
throw new ApproveFromError('Candidate results.json is missing a numeric totals.failed count. The ' +
|
|
152
152
|
'artifact is truncated or was not produced by tuffgal. Refusing to ' +
|
|
153
153
|
'promote a run whose pass/fail status cannot be verified.');
|
|
154
154
|
}
|
|
155
155
|
if (result.totals.failed > 0) {
|
|
156
156
|
throw new ApproveFromError(`Candidate results.json reports ${result.totals.failed} failed ` +
|
|
157
|
-
'story(ies)
|
|
157
|
+
'story(ies); a broken run produces a partial candidate tree that must ' +
|
|
158
158
|
'never be promoted. Fix the failures and re-run before approving.');
|
|
159
159
|
}
|
|
160
160
|
}
|
|
@@ -176,7 +176,7 @@ function assertPromotableRun(result) {
|
|
|
176
176
|
function extractEnvironment(result) {
|
|
177
177
|
const actual = result.environment?.actual;
|
|
178
178
|
if (!actual) {
|
|
179
|
-
throw new ApproveFromError('Candidate results.json has no environment block
|
|
179
|
+
throw new ApproveFromError('Candidate results.json has no environment block; it was produced by a ' +
|
|
180
180
|
'pre-manifest tuffgal. Re-run with a manifest-aware version before ' +
|
|
181
181
|
'approving, so baselines/manifest.json can be written.');
|
|
182
182
|
}
|
|
@@ -191,7 +191,7 @@ function extractEnvironment(result) {
|
|
|
191
191
|
* Enforces the whole allow-list: top level holds only `results.json` and action
|
|
192
192
|
* directories; each action directory holds only `<breakpoint>.png` /
|
|
193
193
|
* `<breakpoint>.a11y.yaml` (or legacy `0.png` / `a11y.yaml`). Every other shape
|
|
194
|
-
*
|
|
194
|
+
* (stray extensions, nested dirs, dotfiles, symlinks, traversal names) aborts.
|
|
195
195
|
* Every PNG is decoded here so a corrupt payload fails validation, not a write.
|
|
196
196
|
*/
|
|
197
197
|
async function planWrites(candidateDir, baselinesDir) {
|
|
@@ -209,7 +209,7 @@ async function planWrites(candidateDir, baselinesDir) {
|
|
|
209
209
|
'(only results.json and action directories are allowed)');
|
|
210
210
|
}
|
|
211
211
|
if (!ACTION_NAME_PATTERN.test(entry.name)) {
|
|
212
|
-
throw new ApproveFromError(`Invalid action directory name "${entry.name}"
|
|
212
|
+
throw new ApproveFromError(`Invalid action directory name "${entry.name}": must be ` +
|
|
213
213
|
'lowercase-kebab ([a-z0-9-]+)');
|
|
214
214
|
}
|
|
215
215
|
plan.push(...(await planActionDir(candidateDir, baselinesDir, entry.name)));
|
|
@@ -219,7 +219,7 @@ async function planWrites(candidateDir, baselinesDir) {
|
|
|
219
219
|
/**
|
|
220
220
|
* Validates one action directory's contents and returns its planned writes. Each
|
|
221
221
|
* source file is read exactly once here (after its symlink/name checks pass) and
|
|
222
|
-
* its bytes are retained on the {@link PlannedWrite} for phase 2
|
|
222
|
+
* its bytes are retained on the {@link PlannedWrite} for phase 2. The source is
|
|
223
223
|
* never re-read, closing the validate-then-swap TOCTOU window.
|
|
224
224
|
*/
|
|
225
225
|
async function planActionDir(candidateDir, baselinesDir, action) {
|
|
@@ -235,11 +235,11 @@ async function planActionDir(candidateDir, baselinesDir, action) {
|
|
|
235
235
|
'(action directories hold only PNG + a11y.yaml files)');
|
|
236
236
|
}
|
|
237
237
|
const kind = classifyCandidateFile(file.name, `${action}/${file.name}`);
|
|
238
|
-
// Read once, after the symlink check, and retain the bytes
|
|
238
|
+
// Read once, after the symlink check, and retain the bytes. Phase 2 writes
|
|
239
239
|
// exactly these, never re-reading `source`.
|
|
240
240
|
const bytes = await readFile(source);
|
|
241
|
-
// The destination is derived purely from validated names
|
|
242
|
-
// path string in the artifact
|
|
241
|
+
// The destination is derived purely from validated names (never from any
|
|
242
|
+
// path string in the artifact), so it always lands inside <baselines>.
|
|
243
243
|
plan.push({
|
|
244
244
|
source,
|
|
245
245
|
destination: join(baselinesDir, action, file.name),
|
|
@@ -253,10 +253,11 @@ async function planActionDir(candidateDir, baselinesDir, action) {
|
|
|
253
253
|
* Decodes every planned PNG's RETAINED bytes (validation phase) so a corrupt or
|
|
254
254
|
* non-PNG payload aborts the whole approve with zero writes. Decoding the bytes
|
|
255
255
|
* already held on the plan (not a fresh read) is what makes the decode-check and
|
|
256
|
-
* the eventual write see the same payload. `
|
|
257
|
-
* SWALLOWS a decode failure (it falls back to writing the given bytes),
|
|
258
|
-
* the right behaviour for a trusted capture but wrong for an untrusted
|
|
259
|
-
*
|
|
256
|
+
* the eventual write see the same payload. `writeDurablePng`'s own recompress
|
|
257
|
+
* step SWALLOWS a decode failure (it falls back to writing the given bytes),
|
|
258
|
+
* which is the right behaviour for a trusted capture but wrong for an untrusted
|
|
259
|
+
* artifact. A corrupt candidate PNG must fail closed, not land verbatim as a
|
|
260
|
+
* baseline.
|
|
260
261
|
*/
|
|
261
262
|
async function assertAllPngsDecode(plan) {
|
|
262
263
|
for (const write of plan) {
|
|
@@ -314,7 +315,7 @@ function assertSafeName(name, context) {
|
|
|
314
315
|
throw new ApproveFromError(`Path separator in candidate entry name "${name}" under ${context}`);
|
|
315
316
|
}
|
|
316
317
|
}
|
|
317
|
-
/** Aborts if `path` is a symlink
|
|
318
|
+
/** Aborts if `path` is a symlink. Never follow a link out of the tree. */
|
|
318
319
|
async function assertNotSymlink(path) {
|
|
319
320
|
const stats = await lstat(path);
|
|
320
321
|
if (stats.isSymbolicLink()) {
|
|
@@ -324,7 +325,7 @@ async function assertNotSymlink(path) {
|
|
|
324
325
|
/**
|
|
325
326
|
* Recomputes the local prune targets for `--prune` from the candidate run's
|
|
326
327
|
* `results.deleted`, entirely under the resolved `baselinesDir`. The artifact's
|
|
327
|
-
* own `baselinePaths[]` strings are ignored
|
|
328
|
+
* own `baselinePaths[]` strings are ignored. They describe the CI machine's
|
|
328
329
|
* filesystem and could point anywhere. Instead each entry's `action` +
|
|
329
330
|
* `breakpoint` is re-validated and re-rooted here, so a prune can only ever
|
|
330
331
|
* delete files inside this repo's baselines directory.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"approveFrom.js","sourceRoot":"","sources":["../../src/runner/approveFrom.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AAChE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAChD,OAAO,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AAE5B,OAAO,EACL,mBAAmB,EACnB,0BAA0B,EAC1B,
|
|
1
|
+
{"version":3,"file":"approveFrom.js","sourceRoot":"","sources":["../../src/runner/approveFrom.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,15 +2,15 @@ import type { ResolvedBreakpoint, ResolvedConfig } from '../config.ts';
|
|
|
2
2
|
import type { StoryResult } from '../schema/result.ts';
|
|
3
3
|
import type { ScheduledStory } from './scheduler.ts';
|
|
4
4
|
/**
|
|
5
|
-
* True when `item` renders at `breakpoint
|
|
5
|
+
* True when `item` renders at `breakpoint`, i.e. its resolved run set (its own
|
|
6
6
|
* `breakpoints` override, else the project default) contains a breakpoint with
|
|
7
7
|
* the same name AND dimensions.
|
|
8
8
|
*/
|
|
9
9
|
export declare function storyRendersAt(item: ScheduledStory, config: ResolvedConfig, breakpoint: ResolvedBreakpoint): boolean;
|
|
10
10
|
/**
|
|
11
11
|
* The ordered list of breakpoint passes a run executes. Multi-breakpoint runs
|
|
12
|
-
* are driven as one pass per breakpoint
|
|
13
|
-
* schedule
|
|
12
|
+
* are driven as one pass per breakpoint (a full reset/seed then the whole
|
|
13
|
+
* schedule) so each breakpoint sees a pristine database instead of inheriting
|
|
14
14
|
* the previous breakpoint's mutations (the password a `mobile` pass changed no
|
|
15
15
|
* longer leaks into the `desktop` pass). Order follows `config.breakpoints`
|
|
16
16
|
* first so the default run keeps its configured order, then appends any extra
|
|
@@ -18,12 +18,19 @@ export declare function storyRendersAt(item: ScheduledStory, config: ResolvedCon
|
|
|
18
18
|
*/
|
|
19
19
|
export declare function resolveBreakpointPasses(stories: ScheduledStory[], config: ResolvedConfig): ResolvedBreakpoint[];
|
|
20
20
|
/**
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
21
|
+
* Splits a pass's stories into the two need-sets the run consumes separately,
|
|
22
|
+
* because the SCHEDULER and the AUTH loader have opposite requirements:
|
|
23
|
+
*
|
|
24
|
+
* - `needs` (SCHEDULER-facing) is stripped to only labels whose producer also
|
|
25
|
+
* runs THIS pass. A need whose producer renders at a different breakpoint
|
|
26
|
+
* would otherwise never clear and deadlock the drain.
|
|
27
|
+
* - `authNeeds` (AUTH-facing) retains the story's ORIGINAL full needs, so
|
|
28
|
+
* `resolveStorageStateForNeeds` still loads the auth state a
|
|
29
|
+
* differently-breakpointed producer persisted to disk in its own pass. That
|
|
30
|
+
* off-disk state is what actually satisfies the dependency; stripping this
|
|
31
|
+
* set too would silently render the consumer LOGGED-OUT.
|
|
32
|
+
*
|
|
33
|
+
* `produces` is left intact so failure cascades still propagate within the pass.
|
|
27
34
|
*/
|
|
28
35
|
export declare function adaptNeedsForPass(participating: ScheduledStory[]): ScheduledStory[];
|
|
29
36
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"breakpointPasses.d.ts","sourceRoot":"","sources":["../../src/runner/breakpointPasses.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACvE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAYrD;;;;GAIG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,cAAc,EACpB,MAAM,EAAE,cAAc,EACtB,UAAU,EAAE,kBAAkB,GAC7B,OAAO,CAGT;AAED;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,cAAc,EAAE,EACzB,MAAM,EAAE,cAAc,GACrB,kBAAkB,EAAE,CActB;AAED
|
|
1
|
+
{"version":3,"file":"breakpointPasses.d.ts","sourceRoot":"","sources":["../../src/runner/breakpointPasses.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACvE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAYrD;;;;GAIG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,cAAc,EACpB,MAAM,EAAE,cAAc,EACtB,UAAU,EAAE,kBAAkB,GAC7B,OAAO,CAGT;AAED;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,cAAc,EAAE,EACzB,MAAM,EAAE,cAAc,GACrB,kBAAkB,EAAE,CActB;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,iBAAiB,CAC/B,aAAa,EAAE,cAAc,EAAE,GAC9B,cAAc,EAAE,CAUlB;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,WAAW,EAAE,GAAG,WAAW,CA6BnE"}
|
|
@@ -8,7 +8,7 @@ function passKey(breakpoint) {
|
|
|
8
8
|
return `${breakpoint.name}@${breakpoint.width}x${breakpoint.height}`;
|
|
9
9
|
}
|
|
10
10
|
/**
|
|
11
|
-
* True when `item` renders at `breakpoint
|
|
11
|
+
* True when `item` renders at `breakpoint`, i.e. its resolved run set (its own
|
|
12
12
|
* `breakpoints` override, else the project default) contains a breakpoint with
|
|
13
13
|
* the same name AND dimensions.
|
|
14
14
|
*/
|
|
@@ -18,8 +18,8 @@ export function storyRendersAt(item, config, breakpoint) {
|
|
|
18
18
|
}
|
|
19
19
|
/**
|
|
20
20
|
* The ordered list of breakpoint passes a run executes. Multi-breakpoint runs
|
|
21
|
-
* are driven as one pass per breakpoint
|
|
22
|
-
* schedule
|
|
21
|
+
* are driven as one pass per breakpoint (a full reset/seed then the whole
|
|
22
|
+
* schedule) so each breakpoint sees a pristine database instead of inheriting
|
|
23
23
|
* the previous breakpoint's mutations (the password a `mobile` pass changed no
|
|
24
24
|
* longer leaks into the `desktop` pass). Order follows `config.breakpoints`
|
|
25
25
|
* first so the default run keeps its configured order, then appends any extra
|
|
@@ -44,12 +44,19 @@ export function resolveBreakpointPasses(stories, config) {
|
|
|
44
44
|
return passes;
|
|
45
45
|
}
|
|
46
46
|
/**
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
47
|
+
* Splits a pass's stories into the two need-sets the run consumes separately,
|
|
48
|
+
* because the SCHEDULER and the AUTH loader have opposite requirements:
|
|
49
|
+
*
|
|
50
|
+
* - `needs` (SCHEDULER-facing) is stripped to only labels whose producer also
|
|
51
|
+
* runs THIS pass. A need whose producer renders at a different breakpoint
|
|
52
|
+
* would otherwise never clear and deadlock the drain.
|
|
53
|
+
* - `authNeeds` (AUTH-facing) retains the story's ORIGINAL full needs, so
|
|
54
|
+
* `resolveStorageStateForNeeds` still loads the auth state a
|
|
55
|
+
* differently-breakpointed producer persisted to disk in its own pass. That
|
|
56
|
+
* off-disk state is what actually satisfies the dependency; stripping this
|
|
57
|
+
* set too would silently render the consumer LOGGED-OUT.
|
|
58
|
+
*
|
|
59
|
+
* `produces` is left intact so failure cascades still propagate within the pass.
|
|
53
60
|
*/
|
|
54
61
|
export function adaptNeedsForPass(participating) {
|
|
55
62
|
const producesInPass = new Set();
|
|
@@ -60,6 +67,7 @@ export function adaptNeedsForPass(participating) {
|
|
|
60
67
|
return participating.map((item) => ({
|
|
61
68
|
...item,
|
|
62
69
|
needs: item.needs.filter((label) => producesInPass.has(label)),
|
|
70
|
+
authNeeds: item.needs,
|
|
63
71
|
}));
|
|
64
72
|
}
|
|
65
73
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"breakpointPasses.js","sourceRoot":"","sources":["../../src/runner/breakpointPasses.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAEhE;;;;GAIG;AACH,SAAS,OAAO,CAAC,UAA8B;IAC7C,OAAO,GAAG,UAAU,CAAC,IAAI,IAAI,UAAU,CAAC,KAAK,IAAI,UAAU,CAAC,MAAM,EAAE,CAAC;AACvE,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAC5B,IAAoB,EACpB,MAAsB,EACtB,UAA8B;IAE9B,MAAM,GAAG,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAChC,OAAO,aAAa,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,GAAG,CAAC,CAAC;AAC7E,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,uBAAuB,CACrC,OAAyB,EACzB,MAAsB;IAEtB,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,MAAM,GAAyB,EAAE,CAAC;IACxC,MAAM,GAAG,GAAG,CAAC,EAAsB,EAAQ,EAAE;QAC3C,MAAM,GAAG,GAAG,OAAO,CAAC,EAAE,CAAC,CAAC;QACxB,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,OAAO;QAC1B,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACd,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAClB,CAAC,CAAC;IACF,KAAK,MAAM,EAAE,IAAI,MAAM,CAAC,WAAW;QAAE,GAAG,CAAC,EAAE,CAAC,CAAC;IAC7C,KAAK,MAAM,IAAI,IAAI,OAAO,EAAE,CAAC;QAC3B,KAAK,MAAM,EAAE,IAAI,aAAa,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC;YAAE,GAAG,CAAC,EAAE,CAAC,CAAC;IAC9D,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED
|
|
1
|
+
{"version":3,"file":"breakpointPasses.js","sourceRoot":"","sources":["../../src/runner/breakpointPasses.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,7 +5,8 @@ export interface ManagedDevServers {
|
|
|
5
5
|
/**
|
|
6
6
|
* Spawns the consumer-declared `devServers.command` in a new process group,
|
|
7
7
|
* tees its combined output to `<report>/dev-servers.log`, and waits until
|
|
8
|
-
* every declared health-check URL
|
|
8
|
+
* every declared health-check URL returns a non-5xx HTTP response (proving the
|
|
9
|
+
* server is serving routes, not just that its socket is bound).
|
|
9
10
|
* Returns a handle whose `stop()` method tears the whole tree down with
|
|
10
11
|
* the configured signal (default SIGTERM) followed by SIGKILL after the
|
|
11
12
|
* grace window.
|
|
@@ -13,4 +14,12 @@ export interface ManagedDevServers {
|
|
|
13
14
|
* Used by the CLI's `--manage-servers` flag.
|
|
14
15
|
*/
|
|
15
16
|
export declare function startManagedDevServers(config: ResolvedConfig): Promise<ManagedDevServers>;
|
|
17
|
+
/**
|
|
18
|
+
* Polls `url` with an HTTP readiness probe until it returns a non-5xx response,
|
|
19
|
+
* `getEarlyExit` reports the child died, or `timeoutMs` elapses. Early exit is
|
|
20
|
+
* checked before every probe so a crashed dev-server command surfaces its own
|
|
21
|
+
* error in preference to the generic timeout. `probe` and `pollIntervalMs` are
|
|
22
|
+
* injectable for tests; production uses the real HTTP probe and 500ms cadence.
|
|
23
|
+
*/
|
|
24
|
+
export declare function waitForUrl(url: string, timeoutMs: number, getEarlyExit: () => Error | undefined, probe?: (url: string, timeoutMs: number) => Promise<boolean>, pollIntervalMs?: number): Promise<void>;
|
|
16
25
|
//# sourceMappingURL=devServers.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"devServers.d.ts","sourceRoot":"","sources":["../../../src/runner/bridges/devServers.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"devServers.d.ts","sourceRoot":"","sources":["../../../src/runner/bridges/devServers.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAStD,MAAM,WAAW,iBAAiB;IAChC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACvB;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,sBAAsB,CAC1C,MAAM,EAAE,cAAc,GACrB,OAAO,CAAC,iBAAiB,CAAC,CA2D5B;AA0CD;;;;;;GAMG;AACH,wBAAsB,UAAU,CAC9B,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,KAAK,GAAG,SAAS,EACrC,KAAK,GAAE,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAa,EACvE,cAAc,GAAE,MAA+B,GAC9C,OAAO,CAAC,IAAI,CAAC,CAgBf"}
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import { spawn } from 'node:child_process';
|
|
2
2
|
import { createWriteStream, mkdirSync } from 'node:fs';
|
|
3
3
|
import { join, resolve } from 'node:path';
|
|
4
|
-
import {
|
|
4
|
+
import { probeHttp, sleep } from "../../util.js";
|
|
5
5
|
const READY_PROBE_TIMEOUT_MS = 1_500;
|
|
6
|
+
const READY_POLL_INTERVAL_MS = 500;
|
|
6
7
|
const DEFAULT_READY_TIMEOUT_MS = 60_000;
|
|
7
8
|
const DEFAULT_SHUTDOWN_GRACE_MS = 5_000;
|
|
8
9
|
/**
|
|
9
10
|
* Spawns the consumer-declared `devServers.command` in a new process group,
|
|
10
11
|
* tees its combined output to `<report>/dev-servers.log`, and waits until
|
|
11
|
-
* every declared health-check URL
|
|
12
|
+
* every declared health-check URL returns a non-5xx HTTP response (proving the
|
|
13
|
+
* server is serving routes, not just that its socket is bound).
|
|
12
14
|
* Returns a handle whose `stop()` method tears the whole tree down with
|
|
13
15
|
* the configured signal (default SIGTERM) followed by SIGKILL after the
|
|
14
16
|
* grace window.
|
|
@@ -98,20 +100,26 @@ async function stopChild(child, config) {
|
|
|
98
100
|
}, graceMs);
|
|
99
101
|
});
|
|
100
102
|
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
+
/**
|
|
104
|
+
* Polls `url` with an HTTP readiness probe until it returns a non-5xx response,
|
|
105
|
+
* `getEarlyExit` reports the child died, or `timeoutMs` elapses. Early exit is
|
|
106
|
+
* checked before every probe so a crashed dev-server command surfaces its own
|
|
107
|
+
* error in preference to the generic timeout. `probe` and `pollIntervalMs` are
|
|
108
|
+
* injectable for tests; production uses the real HTTP probe and 500ms cadence.
|
|
109
|
+
*/
|
|
110
|
+
export async function waitForUrl(url, timeoutMs, getEarlyExit, probe = probeHttp, pollIntervalMs = READY_POLL_INTERVAL_MS) {
|
|
103
111
|
const deadline = Date.now() + timeoutMs;
|
|
104
112
|
while (Date.now() < deadline) {
|
|
105
113
|
const earlyExit = getEarlyExit();
|
|
106
114
|
if (earlyExit) {
|
|
107
115
|
throw earlyExit;
|
|
108
116
|
}
|
|
109
|
-
const
|
|
110
|
-
if (
|
|
117
|
+
const ready = await probe(url, READY_PROBE_TIMEOUT_MS);
|
|
118
|
+
if (ready) {
|
|
111
119
|
return;
|
|
112
120
|
}
|
|
113
|
-
await sleep(
|
|
121
|
+
await sleep(pollIntervalMs);
|
|
114
122
|
}
|
|
115
|
-
throw new Error(`Health-check URL ${url}
|
|
123
|
+
throw new Error(`Health-check URL ${url} did not return a non-5xx HTTP response within ${timeoutMs}ms`);
|
|
116
124
|
}
|
|
117
125
|
//# sourceMappingURL=devServers.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"devServers.js","sourceRoot":"","sources":["../../../src/runner/bridges/devServers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAqB,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACvD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAE1C,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"devServers.js","sourceRoot":"","sources":["../../../src/runner/bridges/devServers.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,13 +2,13 @@ import type { Page } from 'playwright';
|
|
|
2
2
|
/**
|
|
3
3
|
* Collects V8 JS + CSS coverage from every Playwright page the harness
|
|
4
4
|
* opens during a run, then hands the aggregate to monocart-coverage-reports
|
|
5
|
-
* for V8, Istanbul, and console summary output. Disabled by default
|
|
5
|
+
* for V8, Istanbul, and console summary output. Disabled by default. Turn
|
|
6
6
|
* on with `tuffgal run --coverage`.
|
|
7
7
|
*
|
|
8
8
|
* Two stages:
|
|
9
|
-
* 1. `startForPage(page)
|
|
9
|
+
* 1. `startForPage(page)`: call after every `newPage` so coverage spans
|
|
10
10
|
* every navigation the story performs.
|
|
11
|
-
* 2. `stopForPage(page)
|
|
11
|
+
* 2. `stopForPage(page)`: call before `context.close()` to drain the
|
|
12
12
|
* entries into the aggregate.
|
|
13
13
|
*
|
|
14
14
|
* `generate()` runs once at end-of-run.
|
package/dist/runner/coverage.js
CHANGED
|
@@ -3,13 +3,13 @@ const PLAYWRIGHT_COVERAGE_OPTIONS = { resetOnNavigation: false };
|
|
|
3
3
|
/**
|
|
4
4
|
* Collects V8 JS + CSS coverage from every Playwright page the harness
|
|
5
5
|
* opens during a run, then hands the aggregate to monocart-coverage-reports
|
|
6
|
-
* for V8, Istanbul, and console summary output. Disabled by default
|
|
6
|
+
* for V8, Istanbul, and console summary output. Disabled by default. Turn
|
|
7
7
|
* on with `tuffgal run --coverage`.
|
|
8
8
|
*
|
|
9
9
|
* Two stages:
|
|
10
|
-
* 1. `startForPage(page)
|
|
10
|
+
* 1. `startForPage(page)`: call after every `newPage` so coverage spans
|
|
11
11
|
* every navigation the story performs.
|
|
12
|
-
* 2. `stopForPage(page)
|
|
12
|
+
* 2. `stopForPage(page)`: call before `context.close()` to drain the
|
|
13
13
|
* entries into the aggregate.
|
|
14
14
|
*
|
|
15
15
|
* `generate()` runs once at end-of-run.
|
|
@@ -58,9 +58,9 @@ export class CoverageCollector {
|
|
|
58
58
|
await this.mcr.add([...js, ...css]);
|
|
59
59
|
}
|
|
60
60
|
catch (error) {
|
|
61
|
-
// A page may already be closing when we stop
|
|
61
|
+
// A page may already be closing when we stop. Best effort, do not
|
|
62
62
|
// fail the run because we missed coverage on one tab.
|
|
63
|
-
process.stderr.write(`coverage: stopForPage failed
|
|
63
|
+
process.stderr.write(`coverage: stopForPage failed: ${error instanceof Error ? error.message : String(error)}\n`);
|
|
64
64
|
}
|
|
65
65
|
}
|
|
66
66
|
async generate() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"coverage.js","sourceRoot":"","sources":["../../src/runner/coverage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAMjC,MAAM,2BAA2B,GAAG,EAAE,iBAAiB,EAAE,KAAK,EAAW,CAAC;AAE1E;;;;;;;;;;;;;GAaG;AACH,MAAM,OAAO,iBAAiB;IACpB,GAAG,CAAqC;IAC/B,SAAS,CAAS;IAC3B,WAAW,CAA4B;IAE/C,YAAY,SAAiB;QAC3B,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;IAC/C,CAAC;IAEO,iBAAiB;QACvB,0EAA0E;QAC1E,uEAAuE;QACvE,yEAAyE;QACzE,kEAAkE;QAClE,IAAI,CAAC,WAAW,KAAK,IAAI,CAAC,UAAU,EAAE,CAAC;QACvC,OAAO,IAAI,CAAC,WAAW,CAAC;IAC1B,CAAC;IAEO,KAAK,CAAC,UAAU;QACtB,MAAM,cAAc,GAAG,MAAM,MAAM,CAAC,2BAA2B,CAAC,CAAC;QACjE,kEAAkE;QAClE,MAAM,YAAY,GAAG,cAAc,CAAC,OAAO,CAAC;QAC5C,IAAI,CAAC,GAAG,GAAG,YAAY,CAAC;YACtB,IAAI,EAAE,kBAAkB;YACxB,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,OAAO,EAAE,CAAC,IAAI,EAAE,iBAAiB,CAAC;SACnC,CAAC,CAAC;QACH,MAAM,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC;IAC9B,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,IAAU;QAC3B,MAAM,IAAI,CAAC,iBAAiB,EAAE,CAAC;QAC/B,MAAM,OAAO,CAAC,GAAG,CAAC;YAChB,IAAI,CAAC,QAAQ,CAAC,eAAe,CAAC,2BAA2B,CAAC;YAC1D,IAAI,CAAC,QAAQ,CAAC,gBAAgB,CAAC,2BAA2B,CAAC;SAC5D,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,IAAU;QAC1B,IAAI,CAAC,IAAI,CAAC,GAAG;YAAE,OAAO;QACtB,IAAI,CAAC;YACH,MAAM,CAAC,EAAE,EAAE,GAAG,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;gBAClC,IAAI,CAAC,QAAQ,CAAC,cAAc,EAAE;gBAC9B,IAAI,CAAC,QAAQ,CAAC,eAAe,EAAE;aAChC,CAAC,CAAC;YACH,MAAM,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC;QACtC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,
|
|
1
|
+
{"version":3,"file":"coverage.js","sourceRoot":"","sources":["../../src/runner/coverage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAMjC,MAAM,2BAA2B,GAAG,EAAE,iBAAiB,EAAE,KAAK,EAAW,CAAC;AAE1E;;;;;;;;;;;;;GAaG;AACH,MAAM,OAAO,iBAAiB;IACpB,GAAG,CAAqC;IAC/B,SAAS,CAAS;IAC3B,WAAW,CAA4B;IAE/C,YAAY,SAAiB;QAC3B,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;IAC/C,CAAC;IAEO,iBAAiB;QACvB,0EAA0E;QAC1E,uEAAuE;QACvE,yEAAyE;QACzE,kEAAkE;QAClE,IAAI,CAAC,WAAW,KAAK,IAAI,CAAC,UAAU,EAAE,CAAC;QACvC,OAAO,IAAI,CAAC,WAAW,CAAC;IAC1B,CAAC;IAEO,KAAK,CAAC,UAAU;QACtB,MAAM,cAAc,GAAG,MAAM,MAAM,CAAC,2BAA2B,CAAC,CAAC;QACjE,kEAAkE;QAClE,MAAM,YAAY,GAAG,cAAc,CAAC,OAAO,CAAC;QAC5C,IAAI,CAAC,GAAG,GAAG,YAAY,CAAC;YACtB,IAAI,EAAE,kBAAkB;YACxB,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,OAAO,EAAE,CAAC,IAAI,EAAE,iBAAiB,CAAC;SACnC,CAAC,CAAC;QACH,MAAM,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC;IAC9B,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,IAAU;QAC3B,MAAM,IAAI,CAAC,iBAAiB,EAAE,CAAC;QAC/B,MAAM,OAAO,CAAC,GAAG,CAAC;YAChB,IAAI,CAAC,QAAQ,CAAC,eAAe,CAAC,2BAA2B,CAAC;YAC1D,IAAI,CAAC,QAAQ,CAAC,gBAAgB,CAAC,2BAA2B,CAAC;SAC5D,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,IAAU;QAC1B,IAAI,CAAC,IAAI,CAAC,GAAG;YAAE,OAAO;QACtB,IAAI,CAAC;YACH,MAAM,CAAC,EAAE,EAAE,GAAG,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;gBAClC,IAAI,CAAC,QAAQ,CAAC,cAAc,EAAE;gBAC9B,IAAI,CAAC,QAAQ,CAAC,eAAe,EAAE;aAChC,CAAC,CAAC;YACH,MAAM,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC;QACtC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,kEAAkE;YAClE,sDAAsD;YACtD,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,iCAAiC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAC5F,CAAC;QACJ,CAAC;IACH,CAAC;IAED,KAAK,CAAC,QAAQ;QACZ,IAAI,CAAC,IAAI,CAAC,GAAG;YAAE,OAAO,IAAI,CAAC,SAAS,CAAC;QACrC,MAAM,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;QAC1B,OAAO,IAAI,CAAC,SAAS,CAAC;IACxB,CAAC;CACF"}
|
|
@@ -6,23 +6,23 @@ import type { RunResult } from '../schema/result.ts';
|
|
|
6
6
|
* unit-testable in isolation.
|
|
7
7
|
*
|
|
8
8
|
* Precedence, highest wins:
|
|
9
|
-
* - `1
|
|
9
|
+
* - `1`: one or more stories failed (a step threw / the harness broke).
|
|
10
10
|
* Always outranks every other signal: a broken run's failure is the
|
|
11
11
|
* headline, not the visual diff it never got to compute cleanly.
|
|
12
|
-
* - `3
|
|
12
|
+
* - `3`: CI mode only: the committed environment manifest is present but its
|
|
13
13
|
* pixel-affecting keys diverge from this run's capture environment (a
|
|
14
|
-
* platform/browser/capture-mode/… drift). The comparison still ran
|
|
15
|
-
* is not an abort
|
|
14
|
+
* platform/browser/capture-mode/… drift). The comparison still ran (this
|
|
15
|
+
* is not an abort) but the diffs are computed against baselines rendered in
|
|
16
16
|
* a different environment, so the signal is "expect a full re-approve",
|
|
17
17
|
* distinct from ordinary pending changes. Outranks `2`: an environment
|
|
18
18
|
* mismatch subsumes and explains the `new`/`changed` churn it produces.
|
|
19
|
-
* - `2
|
|
19
|
+
* - `2`: CI mode only: pending baseline changes a human must approve,
|
|
20
20
|
* `new` or `changed` stories, or `deleted` (orphaned committed baselines an
|
|
21
|
-
* approve/prune should retire). This is the PR-gate signal
|
|
21
|
+
* approve/prune should retire). This is the PR-gate signal. The run itself
|
|
22
22
|
* succeeded, but committed baselines don't yet reflect the current UI. A
|
|
23
23
|
* deleted-only run still gates: the baseline set has drifted from the story
|
|
24
24
|
* set even though nothing rendered differently.
|
|
25
|
-
* - `0
|
|
25
|
+
* - `0`: clean: every story passed, the environment matched (or no manifest
|
|
26
26
|
* to check), and no baselines were orphaned.
|
|
27
27
|
*
|
|
28
28
|
* Local mode never emits `2` or `3`: local runs are advisory and never read
|
package/dist/runner/exitCode.js
CHANGED
|
@@ -4,23 +4,23 @@
|
|
|
4
4
|
* unit-testable in isolation.
|
|
5
5
|
*
|
|
6
6
|
* Precedence, highest wins:
|
|
7
|
-
* - `1
|
|
7
|
+
* - `1`: one or more stories failed (a step threw / the harness broke).
|
|
8
8
|
* Always outranks every other signal: a broken run's failure is the
|
|
9
9
|
* headline, not the visual diff it never got to compute cleanly.
|
|
10
|
-
* - `3
|
|
10
|
+
* - `3`: CI mode only: the committed environment manifest is present but its
|
|
11
11
|
* pixel-affecting keys diverge from this run's capture environment (a
|
|
12
|
-
* platform/browser/capture-mode/… drift). The comparison still ran
|
|
13
|
-
* is not an abort
|
|
12
|
+
* platform/browser/capture-mode/… drift). The comparison still ran (this
|
|
13
|
+
* is not an abort) but the diffs are computed against baselines rendered in
|
|
14
14
|
* a different environment, so the signal is "expect a full re-approve",
|
|
15
15
|
* distinct from ordinary pending changes. Outranks `2`: an environment
|
|
16
16
|
* mismatch subsumes and explains the `new`/`changed` churn it produces.
|
|
17
|
-
* - `2
|
|
17
|
+
* - `2`: CI mode only: pending baseline changes a human must approve,
|
|
18
18
|
* `new` or `changed` stories, or `deleted` (orphaned committed baselines an
|
|
19
|
-
* approve/prune should retire). This is the PR-gate signal
|
|
19
|
+
* approve/prune should retire). This is the PR-gate signal. The run itself
|
|
20
20
|
* succeeded, but committed baselines don't yet reflect the current UI. A
|
|
21
21
|
* deleted-only run still gates: the baseline set has drifted from the story
|
|
22
22
|
* set even though nothing rendered differently.
|
|
23
|
-
* - `0
|
|
23
|
+
* - `0`: clean: every story passed, the environment matched (or no manifest
|
|
24
24
|
* to check), and no baselines were orphaned.
|
|
25
25
|
*
|
|
26
26
|
* Local mode never emits `2` or `3`: local runs are advisory and never read
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
export function interpolate(template, parameters) {
|
|
7
7
|
// Story parameter keys are an open string record, so hyphen/dot keys are
|
|
8
|
-
// valid. Match them too
|
|
8
|
+
// valid. Match them too. Otherwise `${my-key}` wouldn't match at all and the
|
|
9
9
|
// missing-parameter guard below would never fire, leaking the literal token.
|
|
10
10
|
return template.replace(/\$\{([\w.-]+)\}/g, (_match, name) => {
|
|
11
11
|
const value = parameters[name];
|