@variance-authority/storybook-collector 0.15.0 → 0.19.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/CHANGELOG.md +179 -0
- package/README.md +78 -18
- package/dist/contract.d.ts +35 -3
- package/dist/contract.js.map +1 -1
- package/dist/execution.d.ts +16 -41
- package/dist/execution.js +37 -103
- package/dist/execution.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +52 -6
- package/dist/index.js.map +1 -1
- package/dist/options.d.ts +5 -3
- package/dist/options.js.map +1 -1
- package/dist/page-agent-entry.js +4 -0
- package/dist/page-agent-entry.js.map +1 -1
- package/dist/page-agent.bundle.js +1193 -639
- package/dist/parameters.d.ts +24 -8
- package/dist/parameters.js +49 -35
- package/dist/parameters.js.map +1 -1
- package/dist/preset.d.ts +62 -0
- package/dist/preset.js +331 -0
- package/dist/preset.js.map +1 -0
- package/dist/read.js +22 -9
- package/dist/read.js.map +1 -1
- package/dist/serve.js +9 -0
- package/dist/serve.js.map +1 -1
- package/dist/source.d.ts +1 -1
- package/dist/source.js +12 -8
- package/dist/source.js.map +1 -1
- package/dist/world.d.ts +10 -6
- package/dist/world.js +16 -8
- package/dist/world.js.map +1 -1
- package/package.json +17 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,184 @@
|
|
|
1
1
|
# @variance-authority/storybook-collector
|
|
2
2
|
|
|
3
|
+
## 0.19.0
|
|
4
|
+
|
|
5
|
+
Lockstep release — nothing in this package changed. Every `@variance-authority/*` package shares one version.
|
|
6
|
+
|
|
7
|
+
## 0.18.0
|
|
8
|
+
|
|
9
|
+
Lockstep release — nothing in this package changed. Every `@variance-authority/*` package shares one version.
|
|
10
|
+
|
|
11
|
+
## 0.17.1
|
|
12
|
+
|
|
13
|
+
Lockstep release — nothing in this package changed. Every `@variance-authority/*` package shares one version.
|
|
14
|
+
|
|
15
|
+
## 0.17.0
|
|
16
|
+
|
|
17
|
+
Lockstep release — nothing in this package changed. Every `@variance-authority/*` package shares one version.
|
|
18
|
+
|
|
19
|
+
## 0.16.0
|
|
20
|
+
|
|
21
|
+
### Minor Changes
|
|
22
|
+
|
|
23
|
+
- 402ce9f: A story's parameters are read when the story is reached, so no story file is imported before its story comes up
|
|
24
|
+
|
|
25
|
+
Your Storybook run used to read every story's `parameters.variance` before the
|
|
26
|
+
first story, through the preview's `extract()`. That imported every story file
|
|
27
|
+
up front: on a large Storybook you paid for the whole build before seeing one
|
|
28
|
+
story, and each file's first story then timed its import as 0 in `collect`.
|
|
29
|
+
|
|
30
|
+
The run now plans from `index.json` alone. When it reaches a story, it asks the
|
|
31
|
+
preview for that story's merged parameters, which imports only that story's
|
|
32
|
+
file, the import showing the story would have made anyway. That import is
|
|
33
|
+
charged to the story's `collect`, so the first story of each file carries what
|
|
34
|
+
its file costs. A story that excludes itself is still skipped and listed in the
|
|
35
|
+
report with its reason, and a story whose parameters cannot be read is read at
|
|
36
|
+
your run's `viewport` with a warning naming it. A preview too old to read one
|
|
37
|
+
story's parameters says so once per run, not once per story.
|
|
38
|
+
|
|
39
|
+
A story that declares `widths` is still read as `<story id>@<width>` at each
|
|
40
|
+
width, with its own baseline, and all its widths are read on the same page in
|
|
41
|
+
one visit: nothing is opened, booted or loaded again for a second width. A
|
|
42
|
+
run that does not read such a story, because `--subjects`, `--since` or a shard
|
|
43
|
+
left it out, because its visit failed, or because its parameters could not be read, still counts its width baselines as
|
|
44
|
+
planned rather than naming them as baselines your plan no longer holds. A
|
|
45
|
+
story that excludes itself when it is reached holds no subject of the run, so
|
|
46
|
+
every baseline it left, under its own id and at each width, is named. A
|
|
47
|
+
shard prices the story at the sum of the widths its last visit read.
|
|
48
|
+
|
|
49
|
+
If you write a collector, `collect` may now return a `Visit` instead of a
|
|
50
|
+
`Collected`: every subject the visit to the planned one produced, each with its own
|
|
51
|
+
result, each id the planned id or the planned id at a width (`<id>@<width>`),
|
|
52
|
+
and any warnings the visit raised. A visit that could not learn every subject
|
|
53
|
+
it realizes, such as a story read without its parameters, says `incomplete: true`.
|
|
54
|
+
A visit that produced no subject is
|
|
55
|
+
reported as a failed one, and so is a visit that produced any other id. The run and `variance collect` report each subject
|
|
56
|
+
at the position the plan gave the planned subject, and evidence parts record
|
|
57
|
+
the planned id as `of`; a merge refuses a part whose subject is neither. A
|
|
58
|
+
`--subjects` glob that names one width, such as `*@375`, now reaches the story
|
|
59
|
+
it comes from, and only a width suffix extends a story id: `button--primary`
|
|
60
|
+
no longer reaches `button--primary-large`.
|
|
61
|
+
|
|
62
|
+
`@variance-authority/core/format` exports `atWidth`, which writes a subject's
|
|
63
|
+
id and name at a width, and `widenedFrom`, which reads the planned id back
|
|
64
|
+
from a width id, and `realizes`, which says whether a visit to one id may
|
|
65
|
+
produce another.
|
|
66
|
+
|
|
67
|
+
`readParameters(page)` is now `readParameters(page, storyId)` and returns one
|
|
68
|
+
story's parameters; the up-front read of every story is gone.
|
|
69
|
+
- d7f8b72: A story's execution record now says where the browser spent it, timed by the page: `prepare` for the preview's load, paid by the first story read on a document and 0 for every later one; `collect` for importing the story's file and unmounting the story before it; `cases` for the render through `afterEach`. `collectStory` returns them as `timing`, and `watchStoryTiming` starts the page's watch; the collector's page agent runs it.
|
|
70
|
+
- bd4243a: An image, font or media request still unanswered when the network wait runs
|
|
71
|
+
out refuses the subject, naming the URL. The subject used to be read without
|
|
72
|
+
it, with a `network-not-quiet` warning. `NetworkObservation.settle()` now
|
|
73
|
+
resolves that refusal, or `undefined` once nothing is in flight; a caller that
|
|
74
|
+
ignores it reads a subject whose bytes nobody hashed.
|
|
75
|
+
Only the requests a subject started count against it: one still open from an
|
|
76
|
+
earlier subject on the same page was named in that subject's refusal.
|
|
77
|
+
One the read itself asks for and never gets makes `acquireFromAgent` throw
|
|
78
|
+
`UnansweredAssets`, which both collectors turn into that subject's refusal.
|
|
79
|
+
- 8b189b9: Place the probes ahead of your transforms with `placement: 'before-transforms'`
|
|
80
|
+
|
|
81
|
+
The probes go in after your transforms by default, so a compiler that reads
|
|
82
|
+
syntax never reads one. That costs a second parse and the map back to each
|
|
83
|
+
file. A unit-test run whose transforms only strip types or JSX can skip both:
|
|
84
|
+
`placement: 'before-transforms'` places the probes in the file as read, with
|
|
85
|
+
one parse and no map. It means the same on the Vitest, Jest and Rstest
|
|
86
|
+
`withTestSelection`, on `testSelectionProbes` and `testSelectionRule`, and as an
|
|
87
|
+
option of the Storybook addon. With Compiled, React Compiler or another compiler
|
|
88
|
+
that reads syntax in the run, keep the default: nothing detects them for you.
|
|
89
|
+
- 7ff6d4b: Record what each story executed under Rspack and Webpack too
|
|
90
|
+
|
|
91
|
+
Add `@variance-authority/storybook-collector` to your Storybook's `addons`, and
|
|
92
|
+
the preview build carries the probes `tests` reads, whichever builder runs it:
|
|
93
|
+
`testSelectionProbes()` under Vite, the `testSelectionRule()` loader under
|
|
94
|
+
Rspack and Webpack 5. The probes go in after every compiler the build runs, so a
|
|
95
|
+
Storybook built by Rspack with `@compiled/react` records its stories. The
|
|
96
|
+
addon's options are the probes' own: `root`, `mode`, `include` and `placement`.
|
|
97
|
+
|
|
98
|
+
The addon probes only the builds the collector records: `storybook build
|
|
99
|
+
--test` and a dev server. Any other `storybook build`, the one a team
|
|
100
|
+
publishes, gets nothing from it, so build the recorded Storybook with `--test`.
|
|
101
|
+
The collector's `tests` is read in a later process, after the build, so the
|
|
102
|
+
build cannot ask it; Storybook's own `--test` is how a build says it is for
|
|
103
|
+
testing.
|
|
104
|
+
|
|
105
|
+
Under Rspack and Webpack, where the build writes no source map the loaders can
|
|
106
|
+
read, as `storybook build --test` does, the addon hands the loaders their maps
|
|
107
|
+
and the build still writes no `.map` file. `devtool` stays as you set it.
|
|
108
|
+
|
|
109
|
+
Storybook runs an addon's builder hooks before the ones in your `main.js`, so
|
|
110
|
+
the addon places the rule from a plugin, once the config is final: a post
|
|
111
|
+
loader your own `webpackFinal` or `rsbuildFinal` adds still runs ahead of the
|
|
112
|
+
probes. If you added `testSelectionProbes()` or `testSelectionRule()` to the
|
|
113
|
+
Storybook's builder config yourself, remove it and add the addon instead: a
|
|
114
|
+
second one stops the build with "remove your testSelectionRule(); the addon
|
|
115
|
+
places it", or the same of `testSelectionProbes()`, wherever the rule sits,
|
|
116
|
+
in `oneOf` or nested `rules` too, and whether it names the loader by its path
|
|
117
|
+
or as `@variance-authority/sense/probes-loader`. One your `vite.config` lists is
|
|
118
|
+
kept, and the addon adds no second one; if the addon was also given a `mode`,
|
|
119
|
+
`include` or `placement` that differs from it, the build stops and names the
|
|
120
|
+
option. The Vite config `@storybook/addon-vitest` loads your presets for,
|
|
121
|
+
inside Vitest, gets nothing from the addon. Under Rsbuild, an `rsbuildFinal` of
|
|
122
|
+
yours that assigns `tools.rspack` outright, rather than adding to it, drops the
|
|
123
|
+
addon's plugin, and the build runs unprobed.
|
|
124
|
+
|
|
125
|
+
When `tests` is on and the preview has no probes, the run's stderr now says to
|
|
126
|
+
add the addon and build with `storybook build --test`, where it named
|
|
127
|
+
`testSelectionProbes()`. The `tests` option's documentation says the same.
|
|
128
|
+
|
|
129
|
+
### Patch Changes
|
|
130
|
+
|
|
131
|
+
- 8d1bcc1: A link in a doc comment opens from `node_modules`
|
|
132
|
+
|
|
133
|
+
Doc comments linked to documentation by repository paths such as
|
|
134
|
+
`../../../../docs/flakiness.md`, which resolve to nothing in an installed
|
|
135
|
+
package. They now link to the page on variance-authority.dev, or to the file on
|
|
136
|
+
GitHub when the site does not publish it, so the link works on hover in your
|
|
137
|
+
editor and in what `variance ask symbol` prints.
|
|
138
|
+
|
|
139
|
+
The MCP server's instructions and its observability answer linked to
|
|
140
|
+
`/start-cli` and `/presentation`, which the site does not serve. They now link
|
|
141
|
+
to `/start/cli` and `/docs/presentation`, and the `@variance-authority/cli`,
|
|
142
|
+
`@variance-authority/help`, `@variance-authority/mcp` and
|
|
143
|
+
`@variance-authority/vitest-browser` READMEs link to the guides where the site
|
|
144
|
+
publishes them.
|
|
145
|
+
|
|
146
|
+
`variancePrecondition`, `wiringOf`, `tapCommits` and `provenanceOf` carry an
|
|
147
|
+
`@see` link to the section of the guide that documents them.
|
|
148
|
+
- 0e77166: A Vite Storybook with a `.storybook/preview` file builds with the addon
|
|
149
|
+
|
|
150
|
+
From Storybook 9.1 on, Storybook rewrites each `sb.mock(import('../lib/api'))`
|
|
151
|
+
in the preview file to `sb.mock('../lib/api')` by printing the whole file
|
|
152
|
+
again, with no map back to your lines, so `storybook build --test` stopped at
|
|
153
|
+
the probes on any preview, whether it mocked a module or not. The addon now has
|
|
154
|
+
that rewrite edit the file in place: `import(` and its closing parenthesis
|
|
155
|
+
become spaces, every other character keeps its line and column, and the
|
|
156
|
+
preview's decorators are recorded where you wrote them. Storybook 10 builds the
|
|
157
|
+
same way. A Storybook that rewrites more calls than the edit in place makes
|
|
158
|
+
stops the build with an error that names `storybook:mock-loader-preview` and
|
|
159
|
+
the preview, rather than shipping a mock that no longer mocks.
|
|
160
|
+
- c3c8e61: An absolute `source.dirs` entry is walked
|
|
161
|
+
|
|
162
|
+
Both collectors joined every `source.dirs` entry onto the working directory, so
|
|
163
|
+
an absolute path such as `/repo/packages/ui/src` was looked for under that
|
|
164
|
+
directory, matched nothing, and the run was refused for having no source files.
|
|
165
|
+
An absolute entry is now walked as written, and a relative one is still resolved
|
|
166
|
+
against the working directory. File names in the index stay relative to that
|
|
167
|
+
directory either way. When no entry matches any file, the refusal lists each
|
|
168
|
+
directory by the absolute path it walked, in place of the entries as spelled
|
|
169
|
+
followed by `(from <root>)`.
|
|
170
|
+
- 52d87e4: A run starts one Chromium. Harnesses and the renderer lease one browser per launch recipe and the last to close it closes it, so a Storybook or route run with four workers launches one browser instead of five. A Storybook run's workers also share one browser context, and with it the HTTP cache: a worker's preview boots from what the first page fetched instead of downloading the bundle again (at four workers on the storybook case, 75 fetches and 29 MB became 17 fetches and 6 MB).
|
|
171
|
+
|
|
172
|
+
New options: `createHarness({ warm })` opens the page in a context shared with other warm harnesses, `createHarness({ isolated })` launches a browser of the harness's own, and `observeNetwork(page, { cache })` watches the wire through the DevTools protocol with the HTTP cache left on (Chromium only). The `alone` reading in both collectors stays in a browser of its own.
|
|
173
|
+
- e6afc58: One recorder for every visual subject
|
|
174
|
+
|
|
175
|
+
`@variance-authority/sense/journal` exports `createSubjectRecorder`, which keeps
|
|
176
|
+
one row per subject of a visual run with the page and every head joined, and
|
|
177
|
+
`driveJourneys`, the driver's listener, cookies and settling wait. The
|
|
178
|
+
Storybook collector records through the first, the Playwright fixture through
|
|
179
|
+
the second, so a story, a page and a test file record their journeys the same
|
|
180
|
+
way.
|
|
181
|
+
|
|
3
182
|
## 0.15.0
|
|
4
183
|
|
|
5
184
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
> Turn a built or already-served Storybook into Variance Authority subjects.
|
|
6
6
|
|
|
7
7
|
Part of [Variance Authority](https://variance-authority.dev).
|
|
8
|
+
Point your coding agent at [`llms.txt`](https://variance-authority.dev/llms.txt).
|
|
8
9
|
|
|
9
10
|
## What this is for
|
|
10
11
|
|
|
@@ -34,7 +35,7 @@ This is the Storybook adapter, not the `variance` binary. The binary lives in
|
|
|
34
35
|
| Module format | ESM only. Every `@variance-authority/*` package sets `"type": "module"`; `require()` will not load them. |
|
|
35
36
|
| Browser | Chromium, installed through Playwright. The binaries do not arrive with an `npm install`. |
|
|
36
37
|
| Storybook | Exercised against Storybook 10 with `@storybook/react-vite`. Index versions `3`, `4` and `5` are read, and the story root is looked for at `#storybook-root` (Storybook 7 and later) and then `#root` (before it). Storybook 8.3 and later emit `storyFinished`, which this package waits for; it falls back to `storyRendered` when the event is absent. |
|
|
37
|
-
| Builder | Collection reads `index.json` and drives the preview channel, so it works the same whether Vite
|
|
38
|
+
| Builder | Collection reads `index.json` and drives the preview channel, so it works the same whether Vite, Webpack 5 or Rspack built the Storybook. The `tests` option records under all three. `@variance-authority/jsx-source` is a Vite plugin with no Webpack or Rspack equivalent. |
|
|
38
39
|
| React | Required for component attribution, the `wiring` band and the Suspense wait. The reading is of the expando `react-dom` writes on host nodes — `__reactFiber$` on React 17 and later, `__reactInternalInstance$` on React 16 — so there is no React version to match and none is imported. The suite runs against React 19. |
|
|
39
40
|
|
|
40
41
|
A Storybook whose renderer is not React still collects: documents, pixels,
|
|
@@ -76,8 +77,8 @@ export default storybookCollector({
|
|
|
76
77
|
});
|
|
77
78
|
```
|
|
78
79
|
|
|
79
|
-
`source.dirs` is a list of directory paths — not globs —
|
|
80
|
-
directory you run `variance` from. The scan reads `.tsx`, `.jsx`, `.ts` and
|
|
80
|
+
`source.dirs` is a list of directory paths — not globs — each absolute or
|
|
81
|
+
resolved against the directory you run `variance` from. The scan reads `.tsx`, `.jsx`, `.ts` and
|
|
81
82
|
`.js`, skips `node_modules`, `dist`, `storybook-static` and any path containing
|
|
82
83
|
`.test.`, `.spec.` or `.stories.`, and indexes where each component is
|
|
83
84
|
*declared*. Without it the report still names components and resolves none of
|
|
@@ -173,7 +174,7 @@ rendered by playwright-chromium (chromium@131, darwin/arm64, 1x)
|
|
|
173
174
|
[changed] story:checkout--empty — Button: 1356 pixel(s) differ across 2 region(s) in Button
|
|
174
175
|
[changed] story:checkout--one-item — Button: 1356 pixel(s) differ across 2 region(s) in Button
|
|
175
176
|
|
|
176
|
-
not observed: 2 subject(s) — 0 the run could not see, 2 excluded
|
|
177
|
+
not observed: 2 subject(s) — 0 the run could not see, 2 excluded on purpose, 0 not reached by this change
|
|
177
178
|
[excluded] story:checkout--docs-only: excluded by tag `no-variance`
|
|
178
179
|
```
|
|
179
180
|
|
|
@@ -215,7 +216,7 @@ Everything below is passed to `storybookCollector(...)` in the module from step
|
|
|
215
216
|
| `wiring` | Your preview's renderer is not React. | `true`. Reads props, context, hook cells and keys into a band of its own; turning it off changes no stored digest. |
|
|
216
217
|
| `holdings` | Application values behind the nodes are evidence you want read. | `false`. Changes `structureHash` — an inert wrapper survives the collapse — so both sides of a comparison must be read the same way. |
|
|
217
218
|
| `roots` | Your preview mounts somewhere other than the standard roots. | `['#storybook-root', '#root']`, tightest match first. |
|
|
218
|
-
| `tests` | The next run should be able to skip stories whose code nothing touched. | `false`. Requires
|
|
219
|
+
| `tests` | The next run should be able to skip stories whose code nothing touched. | `false`. Requires this package in the Storybook's `addons` and `storybook build --test`; see below. |
|
|
219
220
|
|
|
220
221
|
A **band** is the severity category a change is filed under. Loudest first:
|
|
221
222
|
`a11y`, `geometry`, `token`, `content`, `texture`. A role or accessible name that
|
|
@@ -232,6 +233,16 @@ One navigation serves the whole suite rather than one navigation per story, and
|
|
|
232
233
|
addon chrome stays outside the selected story root, so it never covers the
|
|
233
234
|
subject document.
|
|
234
235
|
|
|
236
|
+
A parallel run starts one Chromium. Each worker is another page in it, in one
|
|
237
|
+
browser context with the first, so its preview boots from the HTTP cache rather
|
|
238
|
+
than fetching the bundle again; the pages share cookies and storage, as stories
|
|
239
|
+
in one preview already share a document. Across workers, what a story finds left
|
|
240
|
+
behind depends on scheduling: which worker read which story before it decides the
|
|
241
|
+
cookies, storage and service workers, msw's among them, that it meets. When you
|
|
242
|
+
let the collector serve the build, it answers with `cache-control: immutable` so
|
|
243
|
+
every asset stays cached for the run. A story read again to rule out its
|
|
244
|
+
neighbours gets a browser of its own.
|
|
245
|
+
|
|
235
246
|
## Readiness and loading
|
|
236
247
|
|
|
237
248
|
Most stories are complete when Storybook emits `storyRendered`. Add a `ready`
|
|
@@ -344,26 +355,58 @@ for builds that already use Emotion, theme-ui or another custom JSX runtime.
|
|
|
344
355
|
|
|
345
356
|
With `tests`, a run records which blocks of your code each story crossed, so the
|
|
346
357
|
next run can skip a story whose code your diff did not reach. The recording is
|
|
347
|
-
done by
|
|
348
|
-
|
|
349
|
-
```bash
|
|
350
|
-
npm install --save-dev @variance-authority/sense
|
|
351
|
-
```
|
|
358
|
+
done by probes in the preview build, which this package adds as a Storybook
|
|
359
|
+
addon to `storybook build --test` and a dev server:
|
|
352
360
|
|
|
353
361
|
```js
|
|
354
362
|
// .storybook/main.js
|
|
355
|
-
import { testSelectionProbes } from '@variance-authority/sense/journal';
|
|
356
|
-
|
|
357
363
|
export default {
|
|
358
364
|
stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'],
|
|
359
|
-
framework: { name: '
|
|
360
|
-
|
|
361
|
-
...config,
|
|
362
|
-
plugins: [...(config.plugins ?? []), testSelectionProbes()],
|
|
363
|
-
}),
|
|
365
|
+
framework: { name: 'storybook-react-rsbuild', options: {} },
|
|
366
|
+
addons: ['@variance-authority/storybook-collector'],
|
|
364
367
|
};
|
|
365
368
|
```
|
|
366
369
|
|
|
370
|
+
Storybook loads the addon through its preset,
|
|
371
|
+
`@variance-authority/storybook-collector/preset`, which you never import
|
|
372
|
+
yourself. The preset reads the builder Storybook runs. Under Vite it adds
|
|
373
|
+
`testSelectionProbes()` from `@variance-authority/sense/journal`; under Rspack,
|
|
374
|
+
through `rsbuildFinal`, and Webpack 5, through `webpackFinal`, it adds a plugin
|
|
375
|
+
that lists `testSelectionRule()`, a loader at `enforce: 'post'`, first among the
|
|
376
|
+
rules once the build's config is final, so it runs after every post loader of
|
|
377
|
+
yours, the ones your `main.js` hooks add included: Storybook runs an addon's
|
|
378
|
+
hooks before yours. Either way the probes go in after
|
|
379
|
+
every compiler your build runs, so an extractor such as `@compiled/react` reads
|
|
380
|
+
your file as you wrote it, and each probe is placed where the source map says
|
|
381
|
+
that code went. Where the build writes no map the loaders can read, as
|
|
382
|
+
`storybook build --test` does, the preset hands the loaders their maps and the
|
|
383
|
+
build still writes no `.map` file. The preset asks Storybook which build it
|
|
384
|
+
is: `test`, which `--test` sets, or `configType` of `DEVELOPMENT`, which a dev
|
|
385
|
+
server sets. Any other `storybook build`, the one you publish, gets nothing
|
|
386
|
+
from the addon: build it with `--test` for the run that records. If you added
|
|
387
|
+
`testSelectionRule()` to the Storybook's builder config by hand, or
|
|
388
|
+
`testSelectionProbes()` in a `viteFinal` of your own, remove it: two would
|
|
389
|
+
probe each other's probes, so the build stops and says "remove your
|
|
390
|
+
testSelectionRule(); the addon places it", or the same of
|
|
391
|
+
`testSelectionProbes()`. One your `vite.config` lists is already in the config
|
|
392
|
+
when the addon runs, and the addon keeps it rather than add a second; if you
|
|
393
|
+
also gave the addon a `mode`, `include` or `placement` that differs from it, the
|
|
394
|
+
build stops and names the option, since the addon's would be dropped. Under
|
|
395
|
+
Rsbuild the addon adds its plugin as a function at the end of `tools.rspack`:
|
|
396
|
+
an `rsbuildFinal` of yours that assigns `tools.rspack` outright, rather than
|
|
397
|
+
adding to the list, drops it, and the build runs without probes. The Vite
|
|
398
|
+
config `@storybook/addon-vitest` loads your presets for, inside Vitest, gets
|
|
399
|
+
nothing from the addon either: that run is a Vitest run, and the Vitest seam
|
|
400
|
+
records it where you configured one.
|
|
401
|
+
|
|
402
|
+
Pass the probes' options as the addon's: `{ name:
|
|
403
|
+
'@variance-authority/storybook-collector', options: { mode: 'entries' } }`.
|
|
404
|
+
`include` decides which modules are your source, every file outside
|
|
405
|
+
`node_modules` and `dist` that is not a test or a config by default; `root` is a
|
|
406
|
+
directory in the repository, the cwd by default. `placement:
|
|
407
|
+
'before-transforms'` places the probes in each file as read, ahead of every
|
|
408
|
+
compiler; a Storybook that runs an extractor keeps the default.
|
|
409
|
+
|
|
367
410
|
```js
|
|
368
411
|
// variance/storybook.mjs
|
|
369
412
|
import { storybookCollector } from '@variance-authority/storybook-collector';
|
|
@@ -412,6 +455,23 @@ the index names each row by where the story is declared — its file, its
|
|
|
412
455
|
`title/name` — which is the coordinate a person reads in the sidebar and the one
|
|
413
456
|
a diff touches.
|
|
414
457
|
|
|
458
|
+
Each story's row also says where the browser spent it, timed by the page on its
|
|
459
|
+
own clock rather than by the test driving it, under the phase names a test
|
|
460
|
+
file's row uses. `prepare` is the document's start until the preview is ready:
|
|
461
|
+
the navigation, the runtime, the project annotations and the index. A document
|
|
462
|
+
pays it once, so only the first story read on it carries it, and a story the
|
|
463
|
+
preview switched to reads 0, as the second test in one file pays no worker
|
|
464
|
+
start. `collect` is importing the story's file and everything it loads, and then
|
|
465
|
+
unmounting the story shown before it: Storybook does that in between and signals
|
|
466
|
+
nothing for it. No file is imported before its first story comes up — the
|
|
467
|
+
story's parameters are read from the file the preview loads to show it — so the
|
|
468
|
+
first story of each file carries that file's import, and the stories after it
|
|
469
|
+
read only the unmount. `cases` is the render, from loaders through the play function to
|
|
470
|
+
`afterEach`, or to the phase it ended on when it errored or was aborted. Each
|
|
471
|
+
width a story is read at is its own row, with its own figures; the widths share
|
|
472
|
+
one visit on one page, so the first carries the import and the others are the
|
|
473
|
+
same story shown again at another size.
|
|
474
|
+
|
|
415
475
|
## When integration fails
|
|
416
476
|
|
|
417
477
|
- **The index cannot be read:** build Storybook first and check
|
|
@@ -450,4 +510,4 @@ navigation, mounting and readiness.
|
|
|
450
510
|
|
|
451
511
|
---
|
|
452
512
|
|
|
453
|
-
**[@variance-authority/storybook-collector](https://variance-authority.dev/reference/packages/storybook-collector)** is part of [Variance Authority](https://variance-authority.dev) — [documentation](https://variance-authority.dev/docs) · MIT
|
|
513
|
+
**[@variance-authority/storybook-collector](https://variance-authority.dev/reference/packages/storybook-collector)** is part of [Variance Authority](https://variance-authority.dev) — [documentation](https://variance-authority.dev/docs) · [GitHub](https://github.com/Variance-Authority/variance-authority/tree/main/packages/storybook-collector) · MIT
|
package/dist/contract.d.ts
CHANGED
|
@@ -82,8 +82,8 @@ export interface PlannedSubject {
|
|
|
82
82
|
* from — and it is the right one anyway: what a subject *is* belongs in its
|
|
83
83
|
* own name, next to it, rather than in a central file repeating every id.
|
|
84
84
|
* How a story is *read* — excluded, resized, read at several widths — comes
|
|
85
|
-
* from its parameters, which
|
|
86
|
-
*
|
|
85
|
+
* from its parameters, which are read when the story is reached: see
|
|
86
|
+
* {@link Visit}.
|
|
87
87
|
*
|
|
88
88
|
* Selection lives here; definition lives in the config. A tag is a word a
|
|
89
89
|
* story wears, and what that word *means* is the operator's to write down
|
|
@@ -124,7 +124,39 @@ export type Collected = {
|
|
|
124
124
|
} | {
|
|
125
125
|
readonly ok: false;
|
|
126
126
|
readonly because: string;
|
|
127
|
+
/**
|
|
128
|
+
* The subject asked not to be read, and was not: an exclusion the run
|
|
129
|
+
* reports with its reason, not a failure. Absent for every other refusal.
|
|
130
|
+
*/
|
|
131
|
+
readonly excluded?: true;
|
|
127
132
|
};
|
|
133
|
+
/** One subject a visit read: the subject as it was realized, and its reading. */
|
|
134
|
+
export interface VisitedSubject {
|
|
135
|
+
readonly planned: PlannedSubject;
|
|
136
|
+
readonly collected: Collected;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* What reaching one planned subject produced, when it is not one reading.
|
|
140
|
+
*
|
|
141
|
+
* A plan is made before any subject is visited, and some of what decides how a
|
|
142
|
+
* subject is read is only known at the visit: a story's widths live in its
|
|
143
|
+
* parameters, which are read when its file is loaded. So a visit may realize
|
|
144
|
+
* several subjects — one per width, each the planned id at that width,
|
|
145
|
+
* `<id>@<digits>` — or the planned subject at a viewport it declared, and say
|
|
146
|
+
* what it could not read on the way. A visit that realizes any other id fails
|
|
147
|
+
* its story.
|
|
148
|
+
*/
|
|
149
|
+
export interface Visit {
|
|
150
|
+
readonly subjects: readonly VisitedSubject[];
|
|
151
|
+
readonly warnings?: readonly string[];
|
|
152
|
+
/**
|
|
153
|
+
* Present when the visit could not learn every subject the planned one
|
|
154
|
+
* realizes — a story whose parameters were not read, so its widths are
|
|
155
|
+
* unknown. The run then treats what the store holds of the planned subject
|
|
156
|
+
* as it does for a subject it did not visit: planned, not left behind.
|
|
157
|
+
*/
|
|
158
|
+
readonly incomplete?: true;
|
|
159
|
+
}
|
|
128
160
|
export interface CollectorContext {
|
|
129
161
|
readonly config: CollectorConfig;
|
|
130
162
|
/** Computed by the run from the story index. Returned unchanged. */
|
|
@@ -132,7 +164,7 @@ export interface CollectorContext {
|
|
|
132
164
|
}
|
|
133
165
|
export interface Collector {
|
|
134
166
|
plan(): Promise<Plan>;
|
|
135
|
-
collect(subject: PlannedSubject): Promise<Collected>;
|
|
167
|
+
collect(subject: PlannedSubject): Promise<Collected | Visit>;
|
|
136
168
|
/**
|
|
137
169
|
* The frames a snapshot carries, spent on demand.
|
|
138
170
|
*
|
package/dist/contract.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contract.js","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"","sourcesContent":["import type { CallSiteResolver, SourceIndex } from '@variance-authority/core/attribute';\nimport type {\n Diagnostic,\n PageRegion,\n RenderDocument,\n SemanticSnapshot,\n SubjectRef,\n Viewport,\n} from '@variance-authority/core/format';\n\n/**\n * The contract a collector satisfies, restated here rather than imported.\n *\n * The CLI declares the same shapes and this package does not depend on it — a\n * surface package pulling in the binary would put a config parser, a docket and\n * six commands into an adopter's dependency tree to describe four values\n * (ADR-0024). What keeps the two copies honest is that the CLI imports *this*\n * collector in its own tests, so a drift between them fails a build rather than\n * a run.\n */\n\n/**\n * The subset of a run's configuration this collector reads. A region field it\n * leaves out is pinned to `UTC` or `en-US`, never the host's.\n */\nexport interface CollectorConfig extends PageRegion {\n readonly viewport: Viewport;\n readonly fonts?: readonly string[];\n /**\n * Subtrees this project excludes, from `config.ignore` (spec 0024).\n *\n * Only the two fields a page needs: a rule id to record the mark under, and a\n * selector to find it with. Everything else about a rule — its reason, its\n * expiry, the bands it narrows to — is decided after collection, where a clock\n * and the whole run's diffs are available and a browser is not.\n */\n readonly ignore?: readonly {\n readonly id: string;\n readonly select?: string;\n /**\n * Subjects the rule names. Read here to decide what to send, and never sent.\n *\n * A page can resolve a selector and cannot know which subject it is one of,\n * so scoping has to happen on this side of the boundary. Without it a rule\n * written for one route marks its element in every subject that renders the\n * same shared layout, and a real regression inside that element is absorbed\n * everywhere — an ignore silencing more than it says, which is the one thing\n * the mechanism must not do.\n */\n readonly subjects?: readonly string[];\n\n /** Tags the subject must carry. Read here to decide what to send, never sent. */\n readonly tags?: readonly string[];\n }[];\n\n /**\n * Images to serve as nothing, from `config.blank`.\n *\n * Handed to the driver rather than to the page, because it is enforced on the\n * wire — before a byte is decoded, and therefore before the layout it would\n * have participated in exists. Not scoped by subject, and it cannot be: a\n * request carries no idea which subject will end up using it, which is the\n * same reason the asset map is per page rather than per subject.\n */\n readonly blank?: readonly {\n readonly id: string;\n readonly url?: string;\n readonly minPixels?: number;\n readonly maxPixels?: number;\n }[];\n\n /**\n * The subjects section of the config, as the operator wrote it.\n *\n * `index` is optional because it belongs to `subjects.kind: \"storybook\"`, and\n * a config naming any other kind still reaches this collector — the kind is\n * chosen in the config and the collector is chosen in the config, and nothing\n * makes the operator pick a matching pair. Typed as always present, the first\n * thing to read it hands `undefined` to `node:path` and the adopter gets a\n * TypeError about an argument instead of a sentence naming the wrong word.\n */\n readonly subjects: { readonly index?: string };\n}\n\nexport interface PlannedSubject {\n readonly subject: SubjectRef;\n readonly viewport?: Viewport;\n\n /**\n * What the subject declares itself to be, from the artifact that produced it.\n *\n * Storybook's built index carries `tags` and does not carry a story's\n * `parameters`, so a tag is the one per-story declaration the index can plan\n * from — and it is the right one anyway: what a subject *is* belongs in its\n * own name, next to it, rather than in a central file repeating every id.\n * How a story is *read* — excluded, resized, read at several widths — comes\n * from its parameters, which `withParameters` lays over this plan from the\n * running preview.\n *\n * Selection lives here; definition lives in the config. A tag is a word a\n * story wears, and what that word *means* is the operator's to write down\n * once, where a typo can be refused by name.\n */\n readonly tags?: readonly string[];\n}\n\nexport interface Plan {\n readonly subjects: readonly PlannedSubject[];\n readonly notObserved: readonly unknown[];\n readonly warnings: readonly string[];\n}\n\nexport type Collected =\n | {\n readonly ok: true;\n readonly document: RenderDocument;\n readonly snapshot?: SemanticSnapshot;\n readonly source?: SourceIndex;\n\n /**\n * Stabilization tricks applied to the page before this subject was read.\n *\n * Reported so a run can say what it did to somebody else's page. The\n * digest of the same list is in the environment key, which is what names a\n * differently-stabilized baseline as the cause of a change; this is the\n * half a person reads.\n */\n readonly stabilization?: readonly string[];\n\n /**\n * What the adapter noticed about the *way* this subject was produced.\n *\n * Not about the picture — the document and the snapshot carry that — but\n * about the reading: a story Storybook finished by reporting it failed, a\n * preview that had to be reloaded to show it, a render that never\n * finished. Each of those leaves a real image that a run can compare, and\n * each of them changes what a person should conclude from a green verdict,\n * so they travel with the subject rather than being dropped at the seam.\n */\n readonly diagnostics?: readonly Diagnostic[];\n }\n | { readonly ok: false; readonly because: string };\n\nexport interface CollectorContext {\n readonly config: CollectorConfig;\n /** Computed by the run from the story index. Returned unchanged. */\n readonly plan?: Plan;\n}\n\nexport interface Collector {\n plan(): Promise<Plan>;\n collect(subject: PlannedSubject): Promise<Collected>;\n\n /**\n * The frames a snapshot carries, spent on demand.\n *\n * Present when the collector drives a browser, because resolving a frame means\n * fetching the module it names and the page is the only place that request is\n * already correct. Absent otherwise, and absence is not a degradation: it means\n * either that nothing captured frames, or that the run has no live page to\n * fetch through — and both are a report without call sites rather than a\n * report that is wrong.\n *\n * Handed to `locateSites` with the few nodes a region or a finding names. The\n * resolver is per collector rather than per subject: the cache is what makes\n * this bounded, and a suite's subjects share their modules.\n */\n readonly callSites?: CallSiteResolver;\n\n /**\n * Collect this subject again, in a world nothing else has touched.\n *\n * The saving this whole tool is built on is that the world is *not* rebuilt\n * between subjects (ADR-0009): one browser, one page, one Storybook, for the\n * length of a run. What it buys is the possibility that story B renders\n * differently because story A ran first — and a comparison cannot tell that\n * apart from a regression, because both arrive as \"the pixels moved\".\n *\n * One clean collection settles it. If the difference is gone with nothing else\n * in the world, the baseline was right and the session moved this subject, and\n * the run reports `order-dependent` rather than asking anybody to accept it.\n *\n * Optional in the contract the CLI declares, because a collector holding a\n * single page open has no clean world to offer and the run says so rather than\n * reading silence as \"nothing leaked\". This collector implements it: a\n * Storybook preview can be opened twice, and the second one costs a browser\n * launch — which is why the run only spends it on subjects it already called\n * `changed`, up to `alone.limit`.\n */\n collectAlone?(subject: PlannedSubject): Promise<Collected>;\n\n /**\n * Another standing world from the same recipe and the same server, for a\n * second worker. Optional in the contract the CLI declares; absent, a run\n * configured with `workers` collects in one world and says so.\n */\n openWorker?(): Promise<Collector>;\n\n /**\n * `costs` is what the run timed for each story, first collection to\n * decision, by subject id; the execution record carries it as each story's\n * duration.\n */\n close(costs?: ReadonlyMap<string, number>): Promise<void>;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"contract.js","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"","sourcesContent":["import type { CallSiteResolver, SourceIndex } from '@variance-authority/core/attribute';\nimport type {\n Diagnostic,\n PageRegion,\n RenderDocument,\n SemanticSnapshot,\n SubjectRef,\n Viewport,\n} from '@variance-authority/core/format';\n\n/**\n * The contract a collector satisfies, restated here rather than imported.\n *\n * The CLI declares the same shapes and this package does not depend on it — a\n * surface package pulling in the binary would put a config parser, a docket and\n * six commands into an adopter's dependency tree to describe four values\n * (ADR-0024). What keeps the two copies honest is that the CLI imports *this*\n * collector in its own tests, so a drift between them fails a build rather than\n * a run.\n */\n\n/**\n * The subset of a run's configuration this collector reads. A region field it\n * leaves out is pinned to `UTC` or `en-US`, never the host's.\n */\nexport interface CollectorConfig extends PageRegion {\n readonly viewport: Viewport;\n readonly fonts?: readonly string[];\n /**\n * Subtrees this project excludes, from `config.ignore` (spec 0024).\n *\n * Only the two fields a page needs: a rule id to record the mark under, and a\n * selector to find it with. Everything else about a rule — its reason, its\n * expiry, the bands it narrows to — is decided after collection, where a clock\n * and the whole run's diffs are available and a browser is not.\n */\n readonly ignore?: readonly {\n readonly id: string;\n readonly select?: string;\n /**\n * Subjects the rule names. Read here to decide what to send, and never sent.\n *\n * A page can resolve a selector and cannot know which subject it is one of,\n * so scoping has to happen on this side of the boundary. Without it a rule\n * written for one route marks its element in every subject that renders the\n * same shared layout, and a real regression inside that element is absorbed\n * everywhere — an ignore silencing more than it says, which is the one thing\n * the mechanism must not do.\n */\n readonly subjects?: readonly string[];\n\n /** Tags the subject must carry. Read here to decide what to send, never sent. */\n readonly tags?: readonly string[];\n }[];\n\n /**\n * Images to serve as nothing, from `config.blank`.\n *\n * Handed to the driver rather than to the page, because it is enforced on the\n * wire — before a byte is decoded, and therefore before the layout it would\n * have participated in exists. Not scoped by subject, and it cannot be: a\n * request carries no idea which subject will end up using it, which is the\n * same reason the asset map is per page rather than per subject.\n */\n readonly blank?: readonly {\n readonly id: string;\n readonly url?: string;\n readonly minPixels?: number;\n readonly maxPixels?: number;\n }[];\n\n /**\n * The subjects section of the config, as the operator wrote it.\n *\n * `index` is optional because it belongs to `subjects.kind: \"storybook\"`, and\n * a config naming any other kind still reaches this collector — the kind is\n * chosen in the config and the collector is chosen in the config, and nothing\n * makes the operator pick a matching pair. Typed as always present, the first\n * thing to read it hands `undefined` to `node:path` and the adopter gets a\n * TypeError about an argument instead of a sentence naming the wrong word.\n */\n readonly subjects: { readonly index?: string };\n}\n\nexport interface PlannedSubject {\n readonly subject: SubjectRef;\n readonly viewport?: Viewport;\n\n /**\n * What the subject declares itself to be, from the artifact that produced it.\n *\n * Storybook's built index carries `tags` and does not carry a story's\n * `parameters`, so a tag is the one per-story declaration the index can plan\n * from — and it is the right one anyway: what a subject *is* belongs in its\n * own name, next to it, rather than in a central file repeating every id.\n * How a story is *read* — excluded, resized, read at several widths — comes\n * from its parameters, which are read when the story is reached: see\n * {@link Visit}.\n *\n * Selection lives here; definition lives in the config. A tag is a word a\n * story wears, and what that word *means* is the operator's to write down\n * once, where a typo can be refused by name.\n */\n readonly tags?: readonly string[];\n}\n\nexport interface Plan {\n readonly subjects: readonly PlannedSubject[];\n readonly notObserved: readonly unknown[];\n readonly warnings: readonly string[];\n}\n\nexport type Collected =\n | {\n readonly ok: true;\n readonly document: RenderDocument;\n readonly snapshot?: SemanticSnapshot;\n readonly source?: SourceIndex;\n\n /**\n * Stabilization tricks applied to the page before this subject was read.\n *\n * Reported so a run can say what it did to somebody else's page. The\n * digest of the same list is in the environment key, which is what names a\n * differently-stabilized baseline as the cause of a change; this is the\n * half a person reads.\n */\n readonly stabilization?: readonly string[];\n\n /**\n * What the adapter noticed about the *way* this subject was produced.\n *\n * Not about the picture — the document and the snapshot carry that — but\n * about the reading: a story Storybook finished by reporting it failed, a\n * preview that had to be reloaded to show it, a render that never\n * finished. Each of those leaves a real image that a run can compare, and\n * each of them changes what a person should conclude from a green verdict,\n * so they travel with the subject rather than being dropped at the seam.\n */\n readonly diagnostics?: readonly Diagnostic[];\n }\n | {\n readonly ok: false;\n readonly because: string;\n /**\n * The subject asked not to be read, and was not: an exclusion the run\n * reports with its reason, not a failure. Absent for every other refusal.\n */\n readonly excluded?: true;\n };\n\n/** One subject a visit read: the subject as it was realized, and its reading. */\nexport interface VisitedSubject {\n readonly planned: PlannedSubject;\n readonly collected: Collected;\n}\n\n/**\n * What reaching one planned subject produced, when it is not one reading.\n *\n * A plan is made before any subject is visited, and some of what decides how a\n * subject is read is only known at the visit: a story's widths live in its\n * parameters, which are read when its file is loaded. So a visit may realize\n * several subjects — one per width, each the planned id at that width,\n * `<id>@<digits>` — or the planned subject at a viewport it declared, and say\n * what it could not read on the way. A visit that realizes any other id fails\n * its story.\n */\nexport interface Visit {\n readonly subjects: readonly VisitedSubject[];\n readonly warnings?: readonly string[];\n /**\n * Present when the visit could not learn every subject the planned one\n * realizes — a story whose parameters were not read, so its widths are\n * unknown. The run then treats what the store holds of the planned subject\n * as it does for a subject it did not visit: planned, not left behind.\n */\n readonly incomplete?: true;\n}\n\nexport interface CollectorContext {\n readonly config: CollectorConfig;\n /** Computed by the run from the story index. Returned unchanged. */\n readonly plan?: Plan;\n}\n\nexport interface Collector {\n plan(): Promise<Plan>;\n collect(subject: PlannedSubject): Promise<Collected | Visit>;\n\n /**\n * The frames a snapshot carries, spent on demand.\n *\n * Present when the collector drives a browser, because resolving a frame means\n * fetching the module it names and the page is the only place that request is\n * already correct. Absent otherwise, and absence is not a degradation: it means\n * either that nothing captured frames, or that the run has no live page to\n * fetch through — and both are a report without call sites rather than a\n * report that is wrong.\n *\n * Handed to `locateSites` with the few nodes a region or a finding names. The\n * resolver is per collector rather than per subject: the cache is what makes\n * this bounded, and a suite's subjects share their modules.\n */\n readonly callSites?: CallSiteResolver;\n\n /**\n * Collect this subject again, in a world nothing else has touched.\n *\n * The saving this whole tool is built on is that the world is *not* rebuilt\n * between subjects (ADR-0009): one browser, one page, one Storybook, for the\n * length of a run. What it buys is the possibility that story B renders\n * differently because story A ran first — and a comparison cannot tell that\n * apart from a regression, because both arrive as \"the pixels moved\".\n *\n * One clean collection settles it. If the difference is gone with nothing else\n * in the world, the baseline was right and the session moved this subject, and\n * the run reports `order-dependent` rather than asking anybody to accept it.\n *\n * Optional in the contract the CLI declares, because a collector holding a\n * single page open has no clean world to offer and the run says so rather than\n * reading silence as \"nothing leaked\". This collector implements it: a\n * Storybook preview can be opened twice, and the second one costs a browser\n * launch — which is why the run only spends it on subjects it already called\n * `changed`, up to `alone.limit`.\n */\n collectAlone?(subject: PlannedSubject): Promise<Collected>;\n\n /**\n * Another standing world from the same recipe and the same server, for a\n * second worker. Optional in the contract the CLI declares; absent, a run\n * configured with `workers` collects in one world and says so.\n */\n openWorker?(): Promise<Collector>;\n\n /**\n * `costs` is what the run timed for each story, first collection to\n * decision, by subject id; the execution record carries it as each story's\n * duration.\n */\n close(costs?: ReadonlyMap<string, number>): Promise<void>;\n}\n"]}
|
package/dist/execution.d.ts
CHANGED
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
*
|
|
4
4
|
* The instrument is the one `@variance-authority/sense` already uses; only the
|
|
5
5
|
* transport differs, which is the rule
|
|
6
|
-
* [spec 0028](
|
|
7
|
-
* built with
|
|
6
|
+
* [spec 0028](https://github.com/Variance-Authority/variance-authority/blob/main/docs/specs/0028-the-instrument.md) states. The preview is
|
|
7
|
+
* built with the package's addon, which adds the probes whichever builder runs
|
|
8
|
+
* it ([`preset.ts`](./preset.ts)), the page counts block crossings, and this
|
|
8
9
|
* closes one window per story and joins them at the end of the run.
|
|
9
10
|
*
|
|
10
11
|
* A story is its own owner. Storybook is an execution surface this tool drives
|
|
@@ -12,44 +13,14 @@
|
|
|
12
13
|
* smallest thing a runner can be asked to execute — the crossings of one story
|
|
13
14
|
* belong to that story and to nothing else.
|
|
14
15
|
*/
|
|
15
|
-
import { type EvaluatingPage, type
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
readonly root?: string;
|
|
24
|
-
/** Where the coverage layers live. Defaults to the repository's cache. */
|
|
25
|
-
readonly cacheRoot?: string;
|
|
26
|
-
/** Coverage index. Defaults to the repository-keyed cache the runner seams share. */
|
|
27
|
-
readonly coverageFile?: string;
|
|
28
|
-
/** The suite this run is, as the root `variance.config.json` declares it under `suites`. */
|
|
29
|
-
readonly suite?: string;
|
|
30
|
-
/**
|
|
31
|
-
* The probe recipe the preview was built with, matching
|
|
32
|
-
* `testSelectionProbes()`'s `mode`. `presence` when absent, as it is there.
|
|
33
|
-
*
|
|
34
|
-
* Both sides answer the same or neither works: a journal cut by one recipe
|
|
35
|
-
* and folded as another is refused, and a snapshot a runner seam also writes
|
|
36
|
-
* under a different recipe has each run retire the other's evidence.
|
|
37
|
-
*/
|
|
38
|
-
readonly mode?: InstrumentMode;
|
|
39
|
-
/**
|
|
40
|
-
* Files whose contents are preconditions of every story this run recorded.
|
|
41
|
-
*
|
|
42
|
-
* A `.storybook/preview` file, a theme module every decorator reads — a
|
|
43
|
-
* story *file* is already a precondition of its own stories, and this is for
|
|
44
|
-
* the ones no story declares and nothing enters.
|
|
45
|
-
*/
|
|
46
|
-
readonly preconditions?: readonly string[];
|
|
47
|
-
/**
|
|
48
|
-
* Where this recording stands. Defaults to the checkout's `HEAD`, which is
|
|
49
|
-
* the answer in every case except a caller that already knows better.
|
|
50
|
-
*/
|
|
51
|
-
readonly commit?: string;
|
|
52
|
-
}
|
|
16
|
+
import { type EvaluatingPage, type SubjectRecording } from '@variance-authority/sense/journal';
|
|
17
|
+
import { type StoryTiming } from '@variance-authority/storybook';
|
|
18
|
+
/**
|
|
19
|
+
* Where a story run's execution evidence is joined, read and kept: the shared
|
|
20
|
+
* recording, with `root` also the directory a story's `importPath` is read
|
|
21
|
+
* from, because it is relative to the directory Storybook ran in.
|
|
22
|
+
*/
|
|
23
|
+
export type StoryExecutionOptions = Omit<SubjectRecording, 'heads'>;
|
|
53
24
|
/** One run's accumulation: a window per story, written once at the end. */
|
|
54
25
|
export interface StoryRecorder {
|
|
55
26
|
/**
|
|
@@ -58,8 +29,12 @@ export interface StoryRecorder {
|
|
|
58
29
|
* `complete` is false for a story this run refused. A refused story still
|
|
59
30
|
* executed code, so its crossings are kept — what it may never do is justify
|
|
60
31
|
* excluding itself from a later run.
|
|
32
|
+
*
|
|
33
|
+
* `timing` is where the page spent the story: the preview's load is the
|
|
34
|
+
* story's `prepare`, 0 for a story the preview switched to, its file's
|
|
35
|
+
* import its `collect`, its render its `cases`.
|
|
61
36
|
*/
|
|
62
|
-
readonly note: (page: EvaluatingPage, subjectId: string, complete: boolean) => Promise<void>;
|
|
37
|
+
readonly note: (page: EvaluatingPage, subjectId: string, complete: boolean, timing?: StoryTiming) => Promise<void>;
|
|
63
38
|
/**
|
|
64
39
|
* Merge the run into the index, or say on stderr why it could not.
|
|
65
40
|
*
|