tuffgal 0.2.0-alpha.3 → 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 +34 -20
- 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 +23 -23
- package/dist/reporter/template.js +48 -46
- 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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"interpolate.js","sourceRoot":"","sources":["../../src/runner/interpolate.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,MAAM,UAAU,WAAW,CACzB,QAAgB,EAChB,UAAkC;IAElC,yEAAyE;IACzE,
|
|
1
|
+
{"version":3,"file":"interpolate.js","sourceRoot":"","sources":["../../src/runner/interpolate.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,MAAM,UAAU,WAAW,CACzB,QAAgB,EAChB,UAAkC;IAElC,yEAAyE;IACzE,6EAA6E;IAC7E,6EAA6E;IAC7E,OAAO,QAAQ,CAAC,OAAO,CAAC,kBAAkB,EAAE,CAAC,MAAM,EAAE,IAAY,EAAE,EAAE;QACnE,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;QAC/B,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,MAAM,IAAI,KAAK,CAAC,sBAAsB,IAAI,mBAAmB,QAAQ,GAAG,CAAC,CAAC;QAC5E,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAC7B,IAAU,EACV,UAAkC;IAElC,OAAO;QACL,GAAG,IAAI;QACP,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI;QAChE,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACrB,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC;YACxC,CAAC,CAAC,IAAI,CAAC,QAAQ;KAClB,CAAC;AACJ,CAAC"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ResolvedConfig } from '../config.ts';
|
|
2
2
|
/**
|
|
3
3
|
* Bump when the capture pipeline changes behaviour in a way that shifts pixels
|
|
4
|
-
* for the same input UI
|
|
4
|
+
* for the same input UI: a new default screenshot option, a change to how the
|
|
5
5
|
* clock is frozen, a mask-application tweak, etc. A committed baseline set was
|
|
6
6
|
* rendered under one `CAPTURE_SCHEMA`; a run under a higher value is a pixel-
|
|
7
7
|
* affecting mismatch (see {@link PIXEL_AFFECTING_KEYS}) that prompts re-approve.
|
|
@@ -26,7 +26,7 @@ export interface ManifestBreakpoint {
|
|
|
26
26
|
* to detect when the current capture environment has drifted from the one the
|
|
27
27
|
* committed baselines were rendered under.
|
|
28
28
|
*
|
|
29
|
-
* `tuffgalVersion` and `playwrightVersion` are informational only
|
|
29
|
+
* `tuffgalVersion` and `playwrightVersion` are informational only. They are
|
|
30
30
|
* recorded for debugging but never contribute to a mismatch (a tuffgal patch
|
|
31
31
|
* release or a Playwright bump that does not move the bundled browser leaves
|
|
32
32
|
* pixels untouched). Every other field is pixel-affecting; see
|
|
@@ -54,7 +54,7 @@ export interface EnvironmentManifest {
|
|
|
54
54
|
* shape, not the pixels); `tuffgalVersion`/`playwrightVersion` are excluded as
|
|
55
55
|
* informational. `browser` is excluded because a browser-*name* change is
|
|
56
56
|
* already implied by `browserVersion` (which carries the vendor+version string)
|
|
57
|
-
* and the runner only launches chromium today
|
|
57
|
+
* and the runner only launches chromium today. Comparing the name would add a
|
|
58
58
|
* redundant key with no independent signal.
|
|
59
59
|
*/
|
|
60
60
|
export declare const PIXEL_AFFECTING_KEYS: readonly ["captureSchema", "browserVersion", "platform", "captureMode", "breakpoints", "deviceScaleFactor", "frozenTime"];
|
|
@@ -62,17 +62,17 @@ export type PixelAffectingKey = (typeof PIXEL_AFFECTING_KEYS)[number];
|
|
|
62
62
|
/**
|
|
63
63
|
* Result of reading `<baselines>/manifest.json`. Three outcomes the caller must
|
|
64
64
|
* distinguish, because they gate differently:
|
|
65
|
-
* - `ok
|
|
66
|
-
* - `missing
|
|
65
|
+
* - `ok`: a well-formed manifest was read; compare it against the run.
|
|
66
|
+
* - `missing`: no file on disk. The bootstrap case: the first `approve
|
|
67
67
|
* --from` has not written a manifest yet, so `run --ci` treats it as "no
|
|
68
|
-
* expectation to violate"
|
|
68
|
+
* expectation to violate": `environment.expected: null`, no mismatch, no
|
|
69
69
|
* exit 3. Never gate a project that has simply not been approved once.
|
|
70
|
-
* - `malformed
|
|
70
|
+
* - `malformed`: a file exists but is not valid JSON or fails shape checks.
|
|
71
71
|
* A committed manifest that cannot be parsed is a real problem the run
|
|
72
72
|
* should surface, but crashing the whole comparison is too blunt. Treated
|
|
73
73
|
* as a mismatch-with-note: `expected: null`, `mismatch: true`, and
|
|
74
74
|
* `mismatchKeys: ['manifest']` so the report/comment can say "the committed
|
|
75
|
-
* manifest is unreadable
|
|
75
|
+
* manifest is unreadable. Re-approve to rewrite it" without aborting.
|
|
76
76
|
*/
|
|
77
77
|
export type ManifestReadResult = {
|
|
78
78
|
status: 'ok';
|
|
@@ -91,7 +91,7 @@ export declare const MANIFEST_FILENAME = "manifest.json";
|
|
|
91
91
|
* Reads and shape-checks `<baselinesDir>/manifest.json`. Tolerant by design
|
|
92
92
|
* (see {@link ManifestReadResult}): a missing file is the bootstrap case, a
|
|
93
93
|
* malformed one is surfaced as a note rather than a crash. Shape validation is
|
|
94
|
-
* intentionally shallow
|
|
94
|
+
* intentionally shallow, enough to trust the field reads in {@link
|
|
95
95
|
* compareEnvironment}, not a full structural mirror.
|
|
96
96
|
*/
|
|
97
97
|
export declare function readManifest(baselinesDir: string): Promise<ManifestReadResult>;
|
|
@@ -103,7 +103,7 @@ export declare function readManifest(baselinesDir: string): Promise<ManifestRead
|
|
|
103
103
|
*
|
|
104
104
|
* Exported so `approve --from` can run the same shape check against a candidate
|
|
105
105
|
* artifact's `environment.actual` before promoting it into the committed
|
|
106
|
-
* manifest
|
|
106
|
+
* manifest. A well-formed-but-wrong-shaped environment block must fail closed,
|
|
107
107
|
* not slip into `manifest.json` and silently defeat the drift gate.
|
|
108
108
|
*/
|
|
109
109
|
export declare function validateManifestShape(value: unknown): string | undefined;
|
|
@@ -116,13 +116,13 @@ export interface EnvironmentComparison {
|
|
|
116
116
|
* Compares a committed manifest read result against the environment captured
|
|
117
117
|
* this run, returning which pixel-affecting keys diverged.
|
|
118
118
|
*
|
|
119
|
-
* - `missing
|
|
120
|
-
* - `malformed
|
|
119
|
+
* - `missing`: bootstrap: nothing to violate. `{ mismatch: false }`.
|
|
120
|
+
* - `malformed`: unreadable committed manifest: mismatch-with-note,
|
|
121
121
|
* `mismatchKeys: ['manifest']` (see {@link MALFORMED_MANIFEST_KEY}).
|
|
122
|
-
* - `ok
|
|
122
|
+
* - `ok`: diff each {@link PIXEL_AFFECTING_KEYS}. `breakpoints` compares deep
|
|
123
123
|
* and order-sensitively: the manifest records an ordered list, and a
|
|
124
124
|
* reorder (even at identical dimensions) is treated as a change worth a
|
|
125
|
-
* re-approve prompt rather than silently equal
|
|
125
|
+
* re-approve prompt rather than silently equal. Order-sensitivity is the
|
|
126
126
|
* conservative pixel-safety choice. Informational keys
|
|
127
127
|
* (`tuffgalVersion`/`playwrightVersion`) are never compared.
|
|
128
128
|
*/
|
|
@@ -133,7 +133,7 @@ export interface CapturedBrowser {
|
|
|
133
133
|
version: string;
|
|
134
134
|
}
|
|
135
135
|
/**
|
|
136
|
-
* Builds the environment manifest describing THIS run
|
|
136
|
+
* Builds the environment manifest describing THIS run, the "actual" side of
|
|
137
137
|
* the comparison and the block a later `approve --from` promotes into the
|
|
138
138
|
* committed manifest. Everything except the live browser version is derived
|
|
139
139
|
* from the resolved config and the host, so the caller only supplies the
|
|
@@ -142,7 +142,7 @@ export interface CapturedBrowser {
|
|
|
142
142
|
* `deviceScaleFactor` is hardcoded `1`: the runner never sets `deviceScaleFactor`
|
|
143
143
|
* on `browser.newContext` (see `runStory.ts`), so Playwright's default of `1`
|
|
144
144
|
* applies. If a future wave makes the scale factor configurable, thread it here
|
|
145
|
-
* and this constant must track it
|
|
145
|
+
* and this constant must track it. The manifest's whole job is to notice a DSF
|
|
146
146
|
* change, so a stale hardcode here would silently defeat that.
|
|
147
147
|
*/
|
|
148
148
|
export declare function captureEnvironment(config: ResolvedConfig, browser: CapturedBrowser): EnvironmentManifest;
|
package/dist/runner/manifest.js
CHANGED
|
@@ -3,7 +3,7 @@ import { createRequire } from 'node:module';
|
|
|
3
3
|
import { join } from 'node:path';
|
|
4
4
|
/**
|
|
5
5
|
* Bump when the capture pipeline changes behaviour in a way that shifts pixels
|
|
6
|
-
* for the same input UI
|
|
6
|
+
* for the same input UI: a new default screenshot option, a change to how the
|
|
7
7
|
* clock is frozen, a mask-application tweak, etc. A committed baseline set was
|
|
8
8
|
* rendered under one `CAPTURE_SCHEMA`; a run under a higher value is a pixel-
|
|
9
9
|
* affecting mismatch (see {@link PIXEL_AFFECTING_KEYS}) that prompts re-approve.
|
|
@@ -22,7 +22,7 @@ export const SCHEMA_VERSION = 1;
|
|
|
22
22
|
* shape, not the pixels); `tuffgalVersion`/`playwrightVersion` are excluded as
|
|
23
23
|
* informational. `browser` is excluded because a browser-*name* change is
|
|
24
24
|
* already implied by `browserVersion` (which carries the vendor+version string)
|
|
25
|
-
* and the runner only launches chromium today
|
|
25
|
+
* and the runner only launches chromium today. Comparing the name would add a
|
|
26
26
|
* redundant key with no independent signal.
|
|
27
27
|
*/
|
|
28
28
|
export const PIXEL_AFFECTING_KEYS = [
|
|
@@ -42,7 +42,7 @@ export const MANIFEST_FILENAME = 'manifest.json';
|
|
|
42
42
|
* Reads and shape-checks `<baselinesDir>/manifest.json`. Tolerant by design
|
|
43
43
|
* (see {@link ManifestReadResult}): a missing file is the bootstrap case, a
|
|
44
44
|
* malformed one is surfaced as a note rather than a crash. Shape validation is
|
|
45
|
-
* intentionally shallow
|
|
45
|
+
* intentionally shallow, enough to trust the field reads in {@link
|
|
46
46
|
* compareEnvironment}, not a full structural mirror.
|
|
47
47
|
*/
|
|
48
48
|
export async function readManifest(baselinesDir) {
|
|
@@ -75,7 +75,7 @@ export async function readManifest(baselinesDir) {
|
|
|
75
75
|
*
|
|
76
76
|
* Exported so `approve --from` can run the same shape check against a candidate
|
|
77
77
|
* artifact's `environment.actual` before promoting it into the committed
|
|
78
|
-
* manifest
|
|
78
|
+
* manifest. A well-formed-but-wrong-shaped environment block must fail closed,
|
|
79
79
|
* not slip into `manifest.json` and silently defeat the drift gate.
|
|
80
80
|
*/
|
|
81
81
|
export function validateManifestShape(value) {
|
|
@@ -127,13 +127,13 @@ export function validateManifestShape(value) {
|
|
|
127
127
|
* Compares a committed manifest read result against the environment captured
|
|
128
128
|
* this run, returning which pixel-affecting keys diverged.
|
|
129
129
|
*
|
|
130
|
-
* - `missing
|
|
131
|
-
* - `malformed
|
|
130
|
+
* - `missing`: bootstrap: nothing to violate. `{ mismatch: false }`.
|
|
131
|
+
* - `malformed`: unreadable committed manifest: mismatch-with-note,
|
|
132
132
|
* `mismatchKeys: ['manifest']` (see {@link MALFORMED_MANIFEST_KEY}).
|
|
133
|
-
* - `ok
|
|
133
|
+
* - `ok`: diff each {@link PIXEL_AFFECTING_KEYS}. `breakpoints` compares deep
|
|
134
134
|
* and order-sensitively: the manifest records an ordered list, and a
|
|
135
135
|
* reorder (even at identical dimensions) is treated as a change worth a
|
|
136
|
-
* re-approve prompt rather than silently equal
|
|
136
|
+
* re-approve prompt rather than silently equal. Order-sensitivity is the
|
|
137
137
|
* conservative pixel-safety choice. Informational keys
|
|
138
138
|
* (`tuffgalVersion`/`playwrightVersion`) are never compared.
|
|
139
139
|
*/
|
|
@@ -161,7 +161,7 @@ export function compareEnvironment(expected, actual) {
|
|
|
161
161
|
}
|
|
162
162
|
/**
|
|
163
163
|
* Deep, order-sensitive equality of two breakpoint lists: same length, and each
|
|
164
|
-
* position matches on `name`/`width`/`height`. Order-sensitive on purpose
|
|
164
|
+
* position matches on `name`/`width`/`height`. Order-sensitive on purpose. See
|
|
165
165
|
* {@link compareEnvironment}.
|
|
166
166
|
*/
|
|
167
167
|
function breakpointsEqual(a, b) {
|
|
@@ -178,7 +178,7 @@ function breakpointsEqual(a, b) {
|
|
|
178
178
|
const requirePackage = createRequire(import.meta.url);
|
|
179
179
|
/**
|
|
180
180
|
* Reads tuffgal's own version from its `package.json`. Resolved relative to this
|
|
181
|
-
* module so it works from both `src/` (dev/test) and the built `dist/` tree
|
|
181
|
+
* module so it works from both `src/` (dev/test) and the built `dist/` tree.
|
|
182
182
|
* `../../package.json` is the package root in both layouts. Informational only.
|
|
183
183
|
*/
|
|
184
184
|
function readTuffgalVersion() {
|
|
@@ -195,7 +195,7 @@ function readPlaywrightVersion() {
|
|
|
195
195
|
return pkg.version;
|
|
196
196
|
}
|
|
197
197
|
/**
|
|
198
|
-
* Builds the environment manifest describing THIS run
|
|
198
|
+
* Builds the environment manifest describing THIS run, the "actual" side of
|
|
199
199
|
* the comparison and the block a later `approve --from` promotes into the
|
|
200
200
|
* committed manifest. Everything except the live browser version is derived
|
|
201
201
|
* from the resolved config and the host, so the caller only supplies the
|
|
@@ -204,7 +204,7 @@ function readPlaywrightVersion() {
|
|
|
204
204
|
* `deviceScaleFactor` is hardcoded `1`: the runner never sets `deviceScaleFactor`
|
|
205
205
|
* on `browser.newContext` (see `runStory.ts`), so Playwright's default of `1`
|
|
206
206
|
* applies. If a future wave makes the scale factor configurable, thread it here
|
|
207
|
-
* and this constant must track it
|
|
207
|
+
* and this constant must track it. The manifest's whole job is to notice a DSF
|
|
208
208
|
* change, so a stale hardcode here would silently defeat that.
|
|
209
209
|
*/
|
|
210
210
|
export function captureEnvironment(config, browser) {
|
package/dist/runner/mode.d.ts
CHANGED
|
@@ -26,13 +26,13 @@ export interface RunModeInputs {
|
|
|
26
26
|
* - `--ci` and `--local` are mutually exclusive; passing both throws.
|
|
27
27
|
* - An explicit flag always wins over the environment.
|
|
28
28
|
* - With no flag, default to `ci` when `CI` is truthy (non-empty and not an
|
|
29
|
-
* explicit negation
|
|
29
|
+
* explicit negation, see {@link FALSY_CI}), else `local`.
|
|
30
30
|
*/
|
|
31
31
|
export declare function resolveRunMode(inputs: RunModeInputs): RunMode;
|
|
32
32
|
/**
|
|
33
33
|
* The baseline root a run compares against for the given mode: the committed
|
|
34
34
|
* `paths.baselines` set in CI mode, the per-machine gitignored `paths.localCache`
|
|
35
|
-
* in local mode. This is the single source of the mode→root mapping
|
|
35
|
+
* in local mode. This is the single source of the mode→root mapping, both the
|
|
36
36
|
* per-action comparison in `runAction` and the screen-coverage metric in `run`
|
|
37
37
|
* select their root through here, so the two can never drift. Encodes the PRD
|
|
38
38
|
* invariant that a local run never reads `paths.baselines`.
|
package/dist/runner/mode.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Strings a CI system might export to explicitly opt OUT of CI behaviour. Most
|
|
3
3
|
* CI providers (GitHub Actions, Travis, CircleCI, GitLab, …) set `CI=true`, but
|
|
4
|
-
* the de-facto convention
|
|
5
|
-
* packages
|
|
4
|
+
* the de-facto convention (as codified by the widely-used `ci-info`/`is-ci`
|
|
5
|
+
* packages) is that any non-empty `CI` value counts as "in CI" unless it is one
|
|
6
6
|
* of these explicit negations. We mirror that so a developer who exports
|
|
7
7
|
* `CI=false` locally still gets local mode.
|
|
8
8
|
*/
|
|
@@ -13,7 +13,7 @@ const FALSY_CI = new Set(['', '0', 'false']);
|
|
|
13
13
|
* - `--ci` and `--local` are mutually exclusive; passing both throws.
|
|
14
14
|
* - An explicit flag always wins over the environment.
|
|
15
15
|
* - With no flag, default to `ci` when `CI` is truthy (non-empty and not an
|
|
16
|
-
* explicit negation
|
|
16
|
+
* explicit negation, see {@link FALSY_CI}), else `local`.
|
|
17
17
|
*/
|
|
18
18
|
export function resolveRunMode(inputs) {
|
|
19
19
|
if (inputs.ci && inputs.local) {
|
|
@@ -32,7 +32,7 @@ export function resolveRunMode(inputs) {
|
|
|
32
32
|
/**
|
|
33
33
|
* The baseline root a run compares against for the given mode: the committed
|
|
34
34
|
* `paths.baselines` set in CI mode, the per-machine gitignored `paths.localCache`
|
|
35
|
-
* in local mode. This is the single source of the mode→root mapping
|
|
35
|
+
* in local mode. This is the single source of the mode→root mapping, both the
|
|
36
36
|
* per-action comparison in `runAction` and the screen-coverage metric in `run`
|
|
37
37
|
* select their root through here, so the two can never drift. Encodes the PRD
|
|
38
38
|
* invariant that a local run never reads `paths.baselines`.
|
|
@@ -34,16 +34,16 @@ export declare function shouldScanForOrphans(mode: RunMode, storyFilter: string
|
|
|
34
34
|
/**
|
|
35
35
|
* The distinct set of action names that ran at least one result this run. An
|
|
36
36
|
* action directory under `paths.baselines` whose name is absent from this set
|
|
37
|
-
* had no story compare against it
|
|
37
|
+
* had no story compare against it. It is a candidate orphan. Derived from the
|
|
38
38
|
* flat `stories[].actions[]` walk so `skipped` entries (an earlier step failed)
|
|
39
39
|
* still count the action as executed: the baseline was reachable this run, the
|
|
40
|
-
* story simply broke before reaching it, which is a failure to surface
|
|
40
|
+
* story simply broke before reaching it, which is a failure to surface, not a
|
|
41
41
|
* baseline to retire.
|
|
42
42
|
*/
|
|
43
43
|
export declare function executedActionNames(stories: RunResult['stories']): Set<string>;
|
|
44
44
|
/**
|
|
45
45
|
* Scans `baselinesDir` for orphaned committed baselines: action directories no
|
|
46
|
-
* story executed this run. Detection only
|
|
46
|
+
* story executed this run. Detection only. The returned entries carry the
|
|
47
47
|
* absolute paths a later `approve --prune` deletes; this function never touches
|
|
48
48
|
* the filesystem beyond reading directory listings.
|
|
49
49
|
*
|
|
@@ -22,7 +22,7 @@ export const LEGACY_BREAKPOINT = 'legacy';
|
|
|
22
22
|
* Non-action files that may sit at the baselines root and must never be treated
|
|
23
23
|
* as orphan candidates. `manifest.json` (the environment manifest, wave 6) is
|
|
24
24
|
* the known one; it is a file, not an action directory, so the readdir walk
|
|
25
|
-
* already skips it by virtue of only descending into directories
|
|
25
|
+
* already skips it by virtue of only descending into directories. This set is a
|
|
26
26
|
* belt-and-suspenders guard for any future flat file a sibling wave drops here.
|
|
27
27
|
*/
|
|
28
28
|
const NON_ACTION_ENTRIES = new Set(['manifest.json']);
|
|
@@ -44,10 +44,10 @@ export function shouldScanForOrphans(mode, storyFilter) {
|
|
|
44
44
|
/**
|
|
45
45
|
* The distinct set of action names that ran at least one result this run. An
|
|
46
46
|
* action directory under `paths.baselines` whose name is absent from this set
|
|
47
|
-
* had no story compare against it
|
|
47
|
+
* had no story compare against it. It is a candidate orphan. Derived from the
|
|
48
48
|
* flat `stories[].actions[]` walk so `skipped` entries (an earlier step failed)
|
|
49
49
|
* still count the action as executed: the baseline was reachable this run, the
|
|
50
|
-
* story simply broke before reaching it, which is a failure to surface
|
|
50
|
+
* story simply broke before reaching it, which is a failure to surface, not a
|
|
51
51
|
* baseline to retire.
|
|
52
52
|
*/
|
|
53
53
|
export function executedActionNames(stories) {
|
|
@@ -61,7 +61,7 @@ export function executedActionNames(stories) {
|
|
|
61
61
|
}
|
|
62
62
|
/**
|
|
63
63
|
* Scans `baselinesDir` for orphaned committed baselines: action directories no
|
|
64
|
-
* story executed this run. Detection only
|
|
64
|
+
* story executed this run. Detection only. The returned entries carry the
|
|
65
65
|
* absolute paths a later `approve --prune` deletes; this function never touches
|
|
66
66
|
* the filesystem beyond reading directory listings.
|
|
67
67
|
*
|
|
@@ -92,7 +92,7 @@ export async function scanOrphanedBaselines(baselinesDir, executed) {
|
|
|
92
92
|
}));
|
|
93
93
|
}
|
|
94
94
|
catch {
|
|
95
|
-
// No baselines directory yet (a never-approved project)
|
|
95
|
+
// No baselines directory yet (a never-approved project), nothing to orphan.
|
|
96
96
|
return [];
|
|
97
97
|
}
|
|
98
98
|
const orphans = [];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"orphanScan.js","sourceRoot":"","sources":["../../src/runner/orphanScan.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC3C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAIjC;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,YAAY,CAAC;AAExC;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,OAAO,CAAC;AAClC,MAAM,CAAC,MAAM,WAAW,GAAG,WAAW,CAAC;AACvC,MAAM,CAAC,MAAM,iBAAiB,GAAG,QAAQ,CAAC;AAE1C;;;;;;GAMG;AACH,MAAM,kBAAkB,GAAG,IAAI,GAAG,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC;AAEtD;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,oBAAoB,CAClC,IAAa,EACb,WAA+B;IAE/B,OAAO,IAAI,KAAK,IAAI,IAAI,WAAW,KAAK,SAAS,CAAC;AACpD,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,mBAAmB,CACjC,OAA6B;IAE7B,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;IAChC,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,KAAK,MAAM,MAAM,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;YACnC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAC3B,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,YAAoB,EACpB,QAAqB;IAErB,IAAI,OAAgD,CAAC;IACrD,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,YAAY,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;QACrE,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;YACjC,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,KAAK,EAAE,MAAM,CAAC,WAAW,EAAE;SAC5B,CAAC,CAAC,CAAC;IACN,CAAC;IAAC,MAAM,CAAC;QACP,
|
|
1
|
+
{"version":3,"file":"orphanScan.js","sourceRoot":"","sources":["../../src/runner/orphanScan.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,14 +2,14 @@ import type { Locator, Page } from 'playwright';
|
|
|
2
2
|
import type { Hint } from '../schema/action.ts';
|
|
3
3
|
/**
|
|
4
4
|
* Resolves a hint to a Playwright Locator using a precedence chain. The MVP
|
|
5
|
-
* intentionally stays literal
|
|
5
|
+
* intentionally stays literal, no LLM fallback. When this throws,
|
|
6
6
|
* `runAction` records `LocatorNotFound` and the parent story fails fast.
|
|
7
7
|
*
|
|
8
8
|
* Order:
|
|
9
|
-
* 1. `role + text
|
|
10
|
-
* 2. `role` alone
|
|
11
|
-
* 3. `selector
|
|
12
|
-
* 4. `text` alone
|
|
9
|
+
* 1. `role + text`: strongest ARIA contract.
|
|
10
|
+
* 2. `role` alone: when no name is supplied.
|
|
11
|
+
* 3. `selector`: explicit escape hatch / cached resolution.
|
|
12
|
+
* 4. `text` alone: last resort because text-only locators are noisy.
|
|
13
13
|
*/
|
|
14
14
|
export declare function resolveLocator(page: Page, hint: Hint): Locator;
|
|
15
15
|
export declare class LocatorHintError extends Error {
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Resolves a hint to a Playwright Locator using a precedence chain. The MVP
|
|
3
|
-
* intentionally stays literal
|
|
3
|
+
* intentionally stays literal, no LLM fallback. When this throws,
|
|
4
4
|
* `runAction` records `LocatorNotFound` and the parent story fails fast.
|
|
5
5
|
*
|
|
6
6
|
* Order:
|
|
7
|
-
* 1. `role + text
|
|
8
|
-
* 2. `role` alone
|
|
9
|
-
* 3. `selector
|
|
10
|
-
* 4. `text` alone
|
|
7
|
+
* 1. `role + text`: strongest ARIA contract.
|
|
8
|
+
* 2. `role` alone: when no name is supplied.
|
|
9
|
+
* 3. `selector`: explicit escape hatch / cached resolution.
|
|
10
|
+
* 4. `text` alone: last resort because text-only locators are noisy.
|
|
11
11
|
*/
|
|
12
12
|
export function resolveLocator(page, hint) {
|
|
13
13
|
if (hint.role && hint.text) {
|
|
@@ -22,7 +22,7 @@ export function resolveLocator(page, hint) {
|
|
|
22
22
|
if (hint.text) {
|
|
23
23
|
return page.getByText(hint.text, { exact: false });
|
|
24
24
|
}
|
|
25
|
-
throw new LocatorHintError('hint has no role, selector, or text
|
|
25
|
+
throw new LocatorHintError('hint has no role, selector, or text; cannot resolve');
|
|
26
26
|
}
|
|
27
27
|
export class LocatorHintError extends Error {
|
|
28
28
|
constructor(message) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolveLocator.js","sourceRoot":"","sources":["../../src/runner/resolveLocator.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;GAUG;AACH,MAAM,UAAU,cAAc,CAAC,IAAU,EAAE,IAAU;IACnD,IAAI,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;QAC3B,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;IACtE,CAAC;IACD,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;QACd,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACnC,CAAC;IACD,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;QAClB,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACrC,CAAC;IACD,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;QACd,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;IACrD,CAAC;IACD,MAAM,IAAI,gBAAgB,CACxB,
|
|
1
|
+
{"version":3,"file":"resolveLocator.js","sourceRoot":"","sources":["../../src/runner/resolveLocator.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;GAUG;AACH,MAAM,UAAU,cAAc,CAAC,IAAU,EAAE,IAAU;IACnD,IAAI,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;QAC3B,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;IACtE,CAAC;IACD,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;QACd,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACnC,CAAC;IACD,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;QAClB,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACrC,CAAC;IACD,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;QACd,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;IACrD,CAAC;IACD,MAAM,IAAI,gBAAgB,CACxB,qDAAqD,CACtD,CAAC;AACJ,CAAC;AAED,MAAM,OAAO,gBAAiB,SAAQ,KAAK;IACzC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,kBAAkB,CAAC;IACjC,CAAC;CACF;AAED,MAAM,OAAO,oBAAqB,SAAQ,KAAK;IAC3B,KAAK,CAAW;IAClC,YAAY,IAAU,EAAE,KAAe;QACrC,KAAK,CAAC,2BAA2B,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACzD,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAC;QACnC,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IACrB,CAAC;CACF"}
|
package/dist/runner/run.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { type Browser } from 'playwright';
|
|
1
2
|
import type { ResolvedConfig } from '../config.ts';
|
|
2
3
|
import type { EnvironmentReport, RunResult, StoryResult, StoryStatus } from '../schema/result.ts';
|
|
4
|
+
import { type ManagedDevServers } from './bridges/devServers.ts';
|
|
3
5
|
import { type RunMode } from './mode.ts';
|
|
4
6
|
import { type CapturedBrowser } from './manifest.ts';
|
|
5
7
|
export interface RunCliOptions {
|
|
@@ -21,16 +23,49 @@ export interface RunCliOptions {
|
|
|
21
23
|
* Loads every action and story from the configured paths, resets the
|
|
22
24
|
* consumer-supplied test database, schedules stories according to their
|
|
23
25
|
* needs/produces DAG, and drives execution across a fixed worker pool.
|
|
24
|
-
* Returns the aggregate `RunResult` so the CLI can set the process exit
|
|
25
|
-
*
|
|
26
|
+
* Returns the aggregate `RunResult` so the CLI can set the process exit code.
|
|
27
|
+
*
|
|
28
|
+
* Owns the run's shared lifecycle: it launches ONE browser (injectable via
|
|
29
|
+
* `launchBrowser` for tests) that every story reuses (each opening its own
|
|
30
|
+
* isolated context per breakpoint) and registers a SIGINT/SIGTERM handler that
|
|
31
|
+
* closes that browser and stops any `--manage-servers` dev-servers before
|
|
32
|
+
* exiting non-zero, so an interrupted run (Ctrl-C, CI cancel) orphans neither.
|
|
33
|
+
* Both the normal finally path and the signal handler tear down through the
|
|
34
|
+
* same idempotent {@link createRunTeardown}, so nothing double-closes.
|
|
35
|
+
*/
|
|
36
|
+
export declare function runAll(config: ResolvedConfig, options: RunCliOptions, launchBrowser?: () => Promise<Browser>): Promise<RunResult>;
|
|
37
|
+
/** The run's teardownable handles: the shared browser and any managed servers. */
|
|
38
|
+
interface RunHandles {
|
|
39
|
+
browser?: Pick<Browser, 'close'>;
|
|
40
|
+
managedServers?: ManagedDevServers;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Builds the run's single teardown: closes the shared browser and stops any
|
|
44
|
+
* managed dev-servers, exactly once. The `done` latch makes it idempotent so
|
|
45
|
+
* the normal finally path and a racing signal handler cannot double-close.
|
|
46
|
+
* Whichever calls first tears down, the other is a no-op. Reads the handles off
|
|
47
|
+
* the shared object at CALL time (not capture time), so a signal that arrives
|
|
48
|
+
* mid-setup still tears down whatever has been launched so far. `allSettled`
|
|
49
|
+
* closes both independently: a browser that throws on close must not prevent
|
|
50
|
+
* the dev-servers from being stopped.
|
|
51
|
+
*/
|
|
52
|
+
export declare function createRunTeardown(handles: RunHandles): () => Promise<void>;
|
|
53
|
+
/**
|
|
54
|
+
* Wraps a {@link createRunTeardown} teardown in a SIGINT/SIGTERM handler: tear
|
|
55
|
+
* the run's handles down, then exit non-zero (an interrupted run is a failure,
|
|
56
|
+
* not a clean pass). `exit` is injected (defaulting to `process.exit`) so a
|
|
57
|
+
* test can drive the handler directly, asserting it closes the browser, stops
|
|
58
|
+
* the servers, and requests a non-zero exit, without raising a real signal in
|
|
59
|
+
* the test runner. Idempotent by construction: it delegates to the shared
|
|
60
|
+
* teardown, so a second signal cannot double-close.
|
|
26
61
|
*/
|
|
27
|
-
export declare function
|
|
62
|
+
export declare function createSignalTeardownHandler(teardown: () => Promise<void>, exit?: (code: number) => void): () => void;
|
|
28
63
|
/**
|
|
29
64
|
* Copies the just-written `results.json` into `<report>/candidates/` so the
|
|
30
65
|
* candidate tree is a self-contained approval artifact. `writeReport` has
|
|
31
66
|
* already written `<report>/results.json`; this places a sibling copy under
|
|
32
67
|
* candidates. The candidates dir may not exist yet (a run where every action
|
|
33
|
-
* passed writes no candidate renders), so it is created first
|
|
68
|
+
* passed writes no candidate renders), so it is created first. An empty
|
|
34
69
|
* `candidates/` carrying only `results.json` still correctly describes "nothing
|
|
35
70
|
* to approve".
|
|
36
71
|
*/
|
|
@@ -40,21 +75,21 @@ export declare function copyResultsIntoCandidates(reportDir: string): Promise<vo
|
|
|
40
75
|
* `paths.baselines` in CI mode, per-machine `paths.localCache` in local mode.
|
|
41
76
|
* A thin, coverage-named alias over the shared {@link comparisonRootFor} so the
|
|
42
77
|
* metric counts screens against the SAME set the run (via `runAction`) diffed
|
|
43
|
-
* against
|
|
78
|
+
* against. The mode→root mapping now lives once, in `mode.ts`. Preserved as a
|
|
44
79
|
* named export because the coverage metric's PRD invariant (a local run never
|
|
45
80
|
* reads `paths.baselines`) reads most clearly against a coverage-specific name.
|
|
46
81
|
*/
|
|
47
82
|
export declare function coverageComparisonRoot(config: ResolvedConfig, mode: RunMode): string;
|
|
48
83
|
/**
|
|
49
84
|
* Builds the run's {@link EnvironmentReport}: the environment this run captured
|
|
50
|
-
* under (`actual`), and
|
|
85
|
+
* under (`actual`), and (in CI mode) the committed `<baselines>/manifest.json`
|
|
51
86
|
* (`expected`) plus whether their pixel-affecting keys diverge.
|
|
52
87
|
*
|
|
53
|
-
* The live browser-version probe
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
88
|
+
* The live browser-version probe runs in CI mode ONLY. Local mode never reads
|
|
89
|
+
* `paths.baselines`, so `expected` is always `null` and `browserVersion` is
|
|
90
|
+
* never compared against anything. Reading a browser version just to stamp a
|
|
91
|
+
* value nothing reads is pure cost, so local mode fills the browser identity
|
|
92
|
+
* with an empty sentinel and skips the probe entirely.
|
|
58
93
|
*
|
|
59
94
|
* In CI mode a missing manifest is the bootstrap case (no expectation yet, no
|
|
60
95
|
* mismatch); a malformed one surfaces as a mismatch note (see
|
|
@@ -62,16 +97,17 @@ export declare function coverageComparisonRoot(config: ResolvedConfig, mode: Run
|
|
|
62
97
|
* it read cleanly, so a malformed file reports `null` here while still driving a
|
|
63
98
|
* mismatch.
|
|
64
99
|
*
|
|
65
|
-
* `probe` is the live browser-identity reader
|
|
66
|
-
*
|
|
67
|
-
*
|
|
100
|
+
* `probe` is the live browser-identity reader. `runAll` passes one that reads
|
|
101
|
+
* the run's SHARED browser handle (`browser.version()`), so no throwaway
|
|
102
|
+
* Chromium is launched just to stamp the version; a test injects its own probe
|
|
103
|
+
* to assert it is invoked in CI mode and NEVER invoked in local mode.
|
|
68
104
|
*/
|
|
69
|
-
export declare function resolveEnvironmentReport(config: ResolvedConfig, mode: RunMode, probe
|
|
105
|
+
export declare function resolveEnvironmentReport(config: ResolvedConfig, mode: RunMode, probe: () => Promise<CapturedBrowser>): Promise<EnvironmentReport>;
|
|
70
106
|
/**
|
|
71
107
|
* Rolls a set of story results into the outcome counts. `deleted` counts
|
|
72
108
|
* orphaned baselines, which are a run-level detection (not a per-story outcome),
|
|
73
109
|
* so it always seeds `0` here; `runAll` overwrites the run-total `deleted` from
|
|
74
|
-
* the orphan scan. Per-breakpoint pass summaries keep `0`, which is correct
|
|
110
|
+
* the orphan scan. Per-breakpoint pass summaries keep `0`, which is correct.
|
|
75
111
|
* an orphan is not attributable to a single breakpoint pass.
|
|
76
112
|
*/
|
|
77
113
|
export declare function summarise(results: StoryResult[]): RunResult['totals'];
|
|
@@ -85,13 +121,13 @@ export declare function formatResultLine(status: StoryStatus, actionCount: numbe
|
|
|
85
121
|
/**
|
|
86
122
|
* One Summary bullet for a breakpoint pass: `• <parts> on "<name>" breakpoint`,
|
|
87
123
|
* where `<parts>` joins only the nonzero outcome categories in a fixed order
|
|
88
|
-
* (passed, new, changed, failed)
|
|
124
|
+
* (passed, new, changed, failed), e.g. `2 passed, 1 changed`. Falls back to
|
|
89
125
|
* `0 passed` for the degenerate all-zero pass the run loop never actually
|
|
90
126
|
* emits (it `continue`s past a pass with no participating stories).
|
|
91
127
|
*/
|
|
92
128
|
export declare function formatSummaryBullet(name: string, counts: RunResult['totals']): string;
|
|
93
129
|
/**
|
|
94
|
-
* The breakpoint names that drove a merged story to its status
|
|
130
|
+
* The breakpoint names that drove a merged story to its status, the modes the
|
|
95
131
|
* reader actually needs to inspect. A `changed` story that drifted only at
|
|
96
132
|
* `desktop` tags `[desktop]`, not the `mobile` pass that stayed clean. Returns
|
|
97
133
|
* empty (no tag) when the story spans a single breakpoint, since there is
|
|
@@ -99,4 +135,5 @@ export declare function formatSummaryBullet(name: string, counts: RunResult['tot
|
|
|
99
135
|
* tag, so this is derived, not separately tracked.
|
|
100
136
|
*/
|
|
101
137
|
export declare function drivingBreakpoints(result: StoryResult): string[];
|
|
138
|
+
export {};
|
|
102
139
|
//# sourceMappingURL=run.d.ts.map
|
package/dist/runner/run.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/runner/run.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/runner/run.ts"],"names":[],"mappings":"AAIA,OAAO,EAAY,KAAK,OAAO,EAAE,MAAM,YAAY,CAAC;AACpD,OAAO,KAAK,EAAsB,cAAc,EAAE,MAAM,cAAc,CAAC;AAEvE,OAAO,KAAK,EACV,iBAAiB,EACjB,SAAS,EACT,WAAW,EACX,WAAW,EACZ,MAAM,qBAAqB,CAAC;AAM7B,OAAO,EAEL,KAAK,iBAAiB,EACvB,MAAM,yBAAyB,CAAC;AAqBjC,OAAO,EAAqB,KAAK,OAAO,EAAE,MAAM,WAAW,CAAC;AAC5D,OAAO,EAIL,KAAK,eAAe,EAErB,MAAM,eAAe,CAAC;AAGvB,MAAM,WAAW,aAAa;IAC5B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;;;OAMG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAUD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,MAAM,CAC1B,MAAM,EAAE,cAAc,EACtB,OAAO,EAAE,aAAa,EACtB,aAAa,GAAE,MAAM,OAAO,CAAC,OAAO,CACY,GAC/C,OAAO,CAAC,SAAS,CAAC,CAkMpB;AAED,kFAAkF;AAClF,UAAU,UAAU;IAClB,OAAO,CAAC,EAAE,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IACjC,cAAc,CAAC,EAAE,iBAAiB,CAAC;CACpC;AAED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,UAAU,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,CAU1E;AAED;;;;;;;;GAQG;AACH,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,EAC7B,IAAI,GAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAmC,GAC1D,MAAM,IAAI,CAIZ;AAoED;;;;;;;;GAQG;AACH,wBAAsB,yBAAyB,CAC7C,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CAIf;AAED;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,cAAc,EACtB,IAAI,EAAE,OAAO,GACZ,MAAM,CAER;AAYD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAsB,wBAAwB,CAC5C,MAAM,EAAE,cAAc,EACtB,IAAI,EAAE,OAAO,EACb,KAAK,EAAE,MAAM,OAAO,CAAC,eAAe,CAAC,GACpC,OAAO,CAAC,iBAAiB,CAAC,CAe5B;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,WAAW,EAAE,GAAG,SAAS,CAAC,QAAQ,CAAC,CASrE;AAUD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,WAAW,EACnB,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,GACX,MAAM,CAIR;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,SAAS,CAAC,QAAQ,CAAC,GAC1B,MAAM,CAQR;AAoBD;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,EAAE,CAuBhE"}
|