@variance-authority/storybook-collector 0.14.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 CHANGED
@@ -1,5 +1,521 @@
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
+
182
+ ## 0.15.0
183
+
184
+ ### Minor Changes
185
+
186
+ - 1a0b845: A subject is read with nothing hovered, nothing focused, motion reduced and `Date` fixed
187
+
188
+ Every layout and raster baseline made before this release is compared under a
189
+ moved recipe once; a semantic baseline, read in jsdom, does not move. The
190
+ default recipes gained tricks, so the stabilization digest every reading records
191
+ has changed, and each subject names that recipe as the cause of whatever it
192
+ reports. Review the changes and adopt them with `variance accept --all`, as for
193
+ any recipe change.
194
+
195
+ The standard collection recipe now also holds:
196
+
197
+ - `no-hover`: the pointer is moved to `(-1, -1)`, off the page, once per page
198
+ before it loads. On the `variance` fixture's page it is moved again before
199
+ every observation, a frame each, and not put back: a menu a script opened on
200
+ hover is closed for your test's next step.
201
+ - `no-focus`: whatever holds focus is blurred before the subject is read,
202
+ including an element inside a shadow root. On a page your test or agent goes
203
+ on using, focus goes back to that element once the reading and any screenshot
204
+ of it are taken, so a test types where it left off. The blur still ran the
205
+ page's blur handlers, and what they did, such as a validate-on-blur error,
206
+ stays.
207
+ - `reduced-motion`: the browser reports `prefers-reduced-motion: reduce`, which
208
+ stops the script animations of a page that honours it, and the reading
209
+ declares the same preference among the conditions its `@media` rules are
210
+ resolved against. A `prefers-reduced-motion` condition you declare through
211
+ `createHarness`'s `features` wins, and the browser is asked for that value;
212
+ a declared `no-preference` is not recorded as `reduced-motion`. Rules under
213
+ `@media (prefers-reduced-motion: no-preference)` are not read by default;
214
+ leave `reduced-motion` out to read them.
215
+ - `freeze-clock`: `Date` reads one instant. A script added before the page's
216
+ own replaces `new Date()`, `Date()` and `Date.now()`, and gives the same
217
+ instant to `Intl.DateTimeFormat`'s `format()` and `formatToParts()` called
218
+ without a date. Timers, animation frames and `performance.now()` are the
219
+ browser's own, so a page that settles on a timer still settles. No Playwright
220
+ clock is installed, so `page.clock` stays yours, and a clock your test
221
+ installs replaces the fixed `Date`; the reading still records `freeze-clock`,
222
+ so leave it out of the list when your test owns the clock. `Temporal.Now` and
223
+ `Date` inside a worker are not fixed. The default instant is in the past, and
224
+ the browser's cookie store keeps real time: a cookie your page's script sets
225
+ with an expiry counted from `Date.now()` is already expired and is not
226
+ stored, so a dismissed consent banner can come back after the next
227
+ navigation. Set `varianceNow` or `now` near today, or leave `freeze-clock`
228
+ out.
229
+
230
+ The render and layout recipes gain `no-focus` alone, because a painted document
231
+ still honours a collected `autofocus`. The other three have nothing to act on
232
+ there: the date the page printed is already text in the document, and its
233
+ `@media` rules were resolved when it was read. A `<script>` inside a subject
234
+ root is carried into the render document and runs there under the real clock.
235
+ Every document is painted under the render recipe, so a reading taken without
236
+ `no-focus` is still painted blurred.
237
+
238
+ The instant defaults to `DEFAULT_NOW`, `2024-06-15T12:00:00.000Z`, exported
239
+ from `@variance-authority/core/format`. `routeCollector` and
240
+ `storybookCollector` take a `now` option to choose another. It must be an ISO
241
+ 8601 instant with its zone; anything else is refused before a browser opens.
242
+ An instant other than the default is spelled in the clock's id,
243
+ `freeze-clock@<instant>`, so it is part of the environment key, and a baseline taken at one instant is compared
244
+ with a run at another with the moved instant named as the cause.
245
+
246
+ To read a subject hovered, focused, animated or at the real time, pass your own
247
+ `stabilize` list without that trick: `DEFAULT_STABILIZE`, the ids of the
248
+ default recipe, filtered, as in
249
+ `DEFAULT_STABILIZE.filter((id) => id !== 'freeze-clock')`. It is exported from
250
+ `@variance-authority/core/format`, `@variance-authority/route-collector`,
251
+ `@variance-authority/storybook-collector` and
252
+ `@variance-authority/playwright-test`. `storybookCollector` and `observe` in
253
+ `@variance-authority/playwright-test` now take `stabilize`, as `routeCollector`
254
+ already did.
255
+
256
+ A trick needs a browser driver to apply it, and is recorded only where one did.
257
+ The collectors apply all four. So does the `variance` fixture in
258
+ `@variance-authority/playwright-test`: it sets `reduced-motion` and
259
+ `freeze-clock` on the `page` it hands your test, before the test body runs, and
260
+ takes the pointer off the page and releases focus before every observation,
261
+ giving focus back after it. Two new fixture options, `varianceStabilize` and
262
+ `varianceNow`, choose what it sets and the instant, and are set with
263
+ `test.use`; `varianceDriven` holds the ids it set. A fixed `Date` stops code
264
+ that times itself with `Date.now()`: a debounce or a throttle, such as lodash's
265
+ `debounce`, sees no time pass and never fires, so a test that types into a
266
+ debounced search box can stop getting results after this upgrade. A loop that
267
+ waits for `Date.now()` to pass a mark hangs the page, an animation timed by
268
+ `Date`, such as jQuery's `animate`, never calls its `complete`, and a client
269
+ that checks a token's `nbf` or `iat` against `Date.now()` can refuse a token
270
+ issued today. None of these failures names the clock. Leave
271
+ `freeze-clock` out for such a test, and for one that sets `page.clock` itself:
272
+
273
+ ```ts
274
+ import { DEFAULT_STABILIZE } from '@variance-authority/playwright-test';
275
+
276
+ test.use({ varianceStabilize: DEFAULT_STABILIZE.filter((id) => id !== 'freeze-clock') });
277
+ ```
278
+
279
+ On a page the fixture never handed your test,
280
+ such as one opened from your own browser context, call the new
281
+ `driveBeforeTest(page)` before `page.goto()` to set the same two; `observe` and
282
+ `createVariance` there apply `no-hover` and `no-focus`.
283
+ `@variance-authority/vitest-browser` reads from inside your page and has no
284
+ driver; `@variance-authority/presentation` reads through the Playwright `Page`
285
+ you hand it, a test's or an agent's live browser, and does not drive it. Both
286
+ apply `no-focus` only, giving focus back once the reading is taken. A trick left out is absent from the
287
+ reading's ids and digest, as a trick a tier cannot reach already is.
288
+ `stabilizeForObservation` in `@variance-authority/dom` takes `driven`, the ids
289
+ your driver applied, and returns `refocus()`, which gives focus back to the
290
+ element the reading released. `stabilizeAsRequested` takes the recipe by id, as
291
+ a page agent receives it. `createHarness` in `@variance-authority/playwright`
292
+ takes a `stabilize` recipe to drive its page before the first navigation, and
293
+ reports the ids it applied as `driven`. `createObservedHarness` opens one with
294
+ `observeNetwork` started before its first navigation, as both collectors do.
295
+
296
+ `createPlaywrightRenderer` no longer couples `no-focus` to `waitForFonts`:
297
+ `waitForFonts: false` turns off the waits alone.
298
+
299
+ `@variance-authority/core/format` exports `DEFAULT_STABILIZE`, `DEFAULT_NOW`,
300
+ `driveBeforeLoad` and `driveBeforeRead`, which apply the driver tricks to a
301
+ Playwright `Page`, `forDriver`, which drops the ones a host did not apply,
302
+ `featuresOf`, which declares the motion preference a recipe drove, and
303
+ `recipeToDrive`, which resolves a `stabilize` list and checks `now` before a
304
+ browser opens.
305
+ - d432339: A page reads its clock in UTC and formats for en-US, not for the host
306
+
307
+ The harness the route and Storybook collectors open, and the pages the renderer
308
+ paints, took their timezone and locale from the machine. A date the page
309
+ formatted read one way on a laptop in Sydney and another on a runner in
310
+ Virginia, from one build, and the two compared against one baseline as
311
+ `changed`.
312
+
313
+ Both are pinned: `timezoneId` to `UTC` and `locale` to `en-US`. Declare either
314
+ in `variance.config.json` (`"timezoneId": "Europe/Berlin"`, `"locale":
315
+ "de-DE"`) and the collectors and the renderer pin that instead; an unknown
316
+ timezone or a malformed language tag is refused by its field.
317
+ `createHarness` and `createPlaywrightRenderer` take the same two options.
318
+ `@variance-authority/core/format` exports their type, `PageRegion`, and
319
+ `@variance-authority/playwright` exports `pinnedRegion`, which fills in `UTC`
320
+ and `en-US` for a field left out.
321
+
322
+ Both are part of the environment key, and the renderer's pair is part of
323
+ `RenderIdentity.rasterization`. A capture read in another timezone or language
324
+ is another environment, and an image painted in one is compared with a
325
+ baseline painted in another, with `rasterization` named as the cause of
326
+ whatever moved.
327
+
328
+ `@variance-authority/playwright-test` paints each test in the timezone and
329
+ locale its page runs in: whatever the Playwright project or `test.use` sets.
330
+ When neither sets a `timezoneId`, `varianceFixtures` opens the page in `UTC`
331
+ rather than the host's, so a laptop and a runner in UTC read it under one key;
332
+ Playwright Test already opens it in `en-US` when nothing sets a `locale`. That
333
+ reaches every test of a suite extended with `varianceFixtures`, including tests
334
+ that never call `variance`, so a test that asserts a date formatted in your
335
+ machine's timezone reads it in `UTC` after this upgrade; set `timezoneId` in
336
+ `use` to keep your own. A page
337
+ you hand to `createVariance` is read and painted in whatever its own context
338
+ opened it in, which is the host's timezone when that context set none: open the
339
+ context with `timezoneId: 'UTC'` to match. `varianceRenderer` is now a test fixture, chosen
340
+ by the page, and `varianceRenderers` is the worker's set of renderers, one per
341
+ timezone and locale; a project that overrode `varianceRenderer` at worker scope
342
+ overrides it at test scope instead.
343
+
344
+ **Every image painted by the Playwright renderer is compared under a moved
345
+ recipe once after this upgrade**, because its recipe now carries the timezone
346
+ and locale. Each subject names `rasterization` as the cause of what it reports,
347
+ and one whose pixels moved is `changed`:
348
+
349
+ - With `variance run`: the run exits `1` for each `changed` subject. Review
350
+ them in `variance report --format html` and adopt them with
351
+ `variance accept --all`. A rerun reports `unchanged`.
352
+ - With `@variance-authority/playwright-test`: the suite fails each `changed`
353
+ test, and `--update-snapshots=changed` adopts them.
354
+ - With `@variance-authority/vitest-browser`: `vitest --update` adopts them, as
355
+ `variance accept --all` does.
356
+
357
+ `@variance-authority/vitest-browser` reads no `variance.config.json` and takes no
358
+ timezone or locale, so it paints in `UTC` and `en-US` whatever its tab ran in,
359
+ and neither it nor `@variance-authority/unit-test` writes a timezone or locale
360
+ to the environment key.
361
+ - 3e6a370: A run's cases travel in its record
362
+
363
+ The case index, the cases a run replaced and the run that replaced them are
364
+ sections of `coverage.bin`, no longer a `coverage.bin.cases.bin` beside it. The
365
+ one file is landed, layered, seeded, repinned, sharded and shared by the same
366
+ rules and under the same lock as the coverage it was recorded with, so the two
367
+ always answer for the same runs. A share, a seed or a fetch carries the index
368
+ and drops the replaced cases and the run that names them, which belong to the
369
+ machine that ran.
370
+
371
+ A record that carries cases is format 10, and a reader that knows only coverage
372
+ refuses it rather than misreading it. A record without cases keeps format 9. A
373
+ `coverage.bin.cases.bin` left from an earlier run is not read; the next run
374
+ writes its cases into the record.
375
+
376
+ The `executionFile` option is removed from `withTestSelection`, the Jest and
377
+ rstest seams, `startRecording`, the Playwright reporter and the Storybook
378
+ collector, along with the JSON it could write. `decodeExecutionIndex`,
379
+ `readExecutionIndex`, `variance covering --against`, `variance review` and
380
+ `distill --execution` read the index out of a record; JSON stays readable as
381
+ the spelling a foreign tool supplies. `landCaseIndexes` is replaced by
382
+ `landCases`, which returns the sections for the record you write, and
383
+ `lastCaseRunOf` reads the run they name. `caseLayerFiles` and
384
+ `executionIndexBytes`, which named and read the file beside the record, are
385
+ removed. `CaseSections`, `caseSectionsAt`, `caseSectionsOf`, `caseIndexOf`,
386
+ `recordedCases`, `withCaseSections`, `keepsCases` and `sharedRecord` read and
387
+ write the sections.
388
+ - 754d04c: The port a build is served on is no part of a render
389
+
390
+ The route and Storybook collectors serve a build on a free port, and that port
391
+ reached three identities. An asset the page loaded was keyed by its absolute
392
+ URL, a `url()` in a computed style was the absolute URL the engine resolved,
393
+ and the document digest read both. One build served twice therefore read as two
394
+ environment keys and two documents: each run missed the render cache, painted
395
+ again, and read its document as changed against its own baseline.
396
+
397
+ An asset the page's own origin serves is keyed by its path, and the page's
398
+ origin is dropped from a `url()` before it is hashed. An asset another origin
399
+ serves keeps its absolute URL. A capture carries the page's `baseUrl` so core
400
+ knows which origin is the page's, and the renderer resolves a path-keyed asset
401
+ against the document's `baseUrl`. `documentDigest` reads the page's own base
402
+ and resources as paths, so one build served on two ports addresses one render
403
+ and the render cache hits; the document keeps them absolute for the renderer,
404
+ and a resource another origin serves stays absolute in the digest too.
405
+
406
+ A `@variance-authority/unit-test` capture keys its assets the same way, so a
407
+ `@variance-authority/vitest-browser` observation, which captures through it on
408
+ the port the runner had free, keeps the port out of its environment key.
409
+ `readCapture` reads back a capture whose asset is keyed by path, resolving the
410
+ key against the document's `baseUrl` as the renderer does; `assetUrl` in
411
+ `@variance-authority/core/format` is that one resolution.
412
+
413
+ **The document of every page served over `http` moves once after this
414
+ upgrade.** `documentDigest` now reads a document's base and resources without
415
+ the page's origin, so the digest of every document served over `http` or
416
+ `https` changes: every route, every story, every Vitest browser page, and every
417
+ Playwright page opened by URL. A moved document misses the render cache once,
418
+ and its image is still compared with the baseline: a page whose pixels did not
419
+ move reads `unchanged`, and one whose pixels did reads `changed`, which
420
+ `variance accept --all` and Playwright's `--update-snapshots=changed` adopt.
421
+ `RULESET_VERSION` moves from `r1` to `r2`. The ruleset is part of a snapshot's
422
+ environment key, not of the render recipe, so no image names it as a moved
423
+ identity; a snapshot diffed against one recorded under `r1` names the ruleset as its
424
+ environment root.
425
+
426
+ ### Patch Changes
427
+
428
+ - 8dbc834: The components a module declares are read from its code. A declaration written
429
+ in a block comment, a JSDoc example or a template literal no longer names a
430
+ component, so a commented-out `function Retired()` no longer makes its file
431
+ the one that declares `Retired`. A name is declared by a statement of the
432
+ module itself: a function, class or binding inside a function body belongs to
433
+ that function and no longer counts. An `export async function Page()`, an
434
+ abstract class, a generator, a second name in `const A = 1, B = 2`, and a name
435
+ that starts with a non-ASCII capital or carries a `$` are now declared too.
436
+
437
+ `variance run`, `variance collect`, the Storybook collector and the route
438
+ collector resolve a component to its `file:line` from the same reading, through
439
+ `indexDeclarations`, which `sense` now exports. What that changes in the index
440
+ they build from `source.dirs`:
441
+
442
+ - The line is the first line of the declaring statement. A decorated class
443
+ sits at its first decorator, or at its `export` when the decorator is written
444
+ above the `export`, and a second name in a multi-line `const` at the line of
445
+ the `const`.
446
+ - `.d.ts` files, and test, spec and story files your own `exclude` lets
447
+ through, declare nothing.
448
+ - A file the parser cannot read declares nothing, where the text scan found
449
+ the components in it. That covers a Flow-annotated `.js` file, and a `.vue`,
450
+ `.svelte` or `.mdx` file you add to a collector's `extensions`, which is
451
+ parsed as TSX and fails. The index built from `source.dirs` or a collector's
452
+ `source` does not say so: the file's components are missing, and nothing
453
+ names the file. Only `sense`'s source index, for a file it records, names the
454
+ parse error in that file's record.
455
+ - Building the index needs `sense`'s native addon, which ships for macOS on
456
+ arm64, Linux on x64 and arm64 with glibc, and Windows on x64. On any other
457
+ machine, including an Intel Mac, an Alpine image and Windows on arm64, a
458
+ configured `source.dirs` fails at its first file and names why the addon did
459
+ not load, where the text scan ran anywhere. The route collector depends on
460
+ `sense` for it.
461
+
462
+ `indexSource` is removed from `@variance-authority/core/attribute`. Build a
463
+ `SourceIndex` with `indexDeclarations` from `@variance-authority/sense`, or
464
+ write one as plain data: a map from component name to `{ file, line, via }`.
465
+ `SourceRef['via']` loses `'declared'`, which nothing produced, and
466
+ `readCapture` in `@variance-authority/unit-test` refuses a capture whose source
467
+ index carries it.
468
+
469
+ The source index format moves to version 18, so an index written before this
470
+ release is rebuilt once instead of keeping the names it read from comments.
471
+ - 1eed290: A form filled in after mount is painted and compared filled in
472
+
473
+ Text a play function or a test typed into an `<input>` or `<textarea>`, the
474
+ option it chose in a `<select>` and the box it ticked now reach the render
475
+ document and the snapshot. Before, the document painted the form as the server
476
+ sent it and the snapshot did not move for typed text or a chosen option. A
477
+ password field's value is carried as one `•` per character, and a file input's
478
+ value is not carried. A form nobody filled in reads exactly as before.
479
+
480
+ This is part of `RULESET_VERSION` `r2`. A subject whose form was filled in
481
+ after the server sent it has a new render document, so after this upgrade its
482
+ image shows the form filled in and reads `changed` against a baseline painted
483
+ empty; `variance accept --all` adopts it. A Playwright test painted its form
484
+ filled in before this change, so it does not move there.
485
+ - ef496ad: READMEs name what the program does
486
+
487
+ The package READMEs, and the `@variance-authority/vantage` and
488
+ `@variance-authority/playwright-test` descriptions, no longer write a test, a
489
+ record or a run as something that says, asks or knows. Each sentence names what
490
+ the program does: a command prints, a record holds a field, a test runs or
491
+ covers. Where a value is filled in from configuration or a default rather than
492
+ recorded, the README says so. Four renamed headings change their anchors:
493
+ `help`'s "Where the declaration is undocumented", `playwright`'s "Where a
494
+ component is declared, read from the engine", `storybook`'s "What a pass sends
495
+ the preview" and `sense`'s "Correct what a file's text declares it imports".
496
+ - 4799688: The checkout says what the probes meant: no build writes module records
497
+
498
+ A probe names the file it was placed on and the digest of that text,
499
+ `path@digest`. When a run is folded, each module the journals name is cut again
500
+ from the file in the checkout. A file whose text still matches is read on its
501
+ own regions; a file that has moved on since the build reads as one whose reach
502
+ is not known, which selects every test that entered it; a file that is gone
503
+ counts the same way. Nothing is written beside the build, and nothing under the
504
+ cache's `test-selection/<key>/<label>/` is read.
505
+
506
+ Breaking:
507
+
508
+ - `testSelectionProbes()` takes no `cacheRoot`. Its `label` names the journey
509
+ head and nothing else.
510
+ - `recordExecution()` takes no `label` and no `heads`.
511
+ - The Jest journeys options (`withJourneyCoverage`) take no `heads`.
512
+ - `jestStore` is removed from `@variance-authority/sense/jest`.
513
+ - `instrumentModule(code, file)` takes no options: call it first, on the file as
514
+ it is on disk.
515
+ - A journal names a module by `path@digest`. A driver that writes its own
516
+ journal builds the id with `moduleId(path, code)` from
517
+ `@variance-authority/sense/journal`.
518
+
3
519
  ## 0.14.0
4
520
 
5
521
  Lockstep release — nothing in this package changed. Every `@variance-authority/*` package shares one version.