@setsquare/review-sdk 0.0.1 → 0.1.1

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.
Files changed (116) hide show
  1. package/NOTICE +3 -2
  2. package/README.md +287 -3
  3. package/dist/autoscan.d.ts +23 -1
  4. package/dist/autoscan.d.ts.map +1 -1
  5. package/dist/autoscan.js +220 -15
  6. package/dist/autoscan.js.map +1 -1
  7. package/dist/brand.d.ts +51 -2
  8. package/dist/brand.d.ts.map +1 -1
  9. package/dist/brand.js +560 -5
  10. package/dist/brand.js.map +1 -1
  11. package/dist/checks/context-change.d.ts +96 -0
  12. package/dist/checks/context-change.d.ts.map +1 -0
  13. package/dist/checks/context-change.js +655 -0
  14. package/dist/checks/context-change.js.map +1 -0
  15. package/dist/checks/focus.d.ts +154 -0
  16. package/dist/checks/focus.d.ts.map +1 -0
  17. package/dist/checks/focus.js +1123 -0
  18. package/dist/checks/focus.js.map +1 -0
  19. package/dist/checks/heuristics.d.ts +117 -0
  20. package/dist/checks/heuristics.d.ts.map +1 -0
  21. package/dist/checks/heuristics.js +961 -0
  22. package/dist/checks/heuristics.js.map +1 -0
  23. package/dist/checks/keyboard.d.ts +106 -0
  24. package/dist/checks/keyboard.d.ts.map +1 -0
  25. package/dist/checks/keyboard.js +452 -0
  26. package/dist/checks/keyboard.js.map +1 -0
  27. package/dist/checks/reflow.d.ts +75 -0
  28. package/dist/checks/reflow.d.ts.map +1 -0
  29. package/dist/checks/reflow.js +285 -0
  30. package/dist/checks/reflow.js.map +1 -0
  31. package/dist/checks/rule-pack.d.ts +1 -1
  32. package/dist/checks/rule-pack.d.ts.map +1 -1
  33. package/dist/checks/rule-pack.js +350 -45
  34. package/dist/checks/rule-pack.js.map +1 -1
  35. package/dist/checks/shortcuts.d.ts +71 -0
  36. package/dist/checks/shortcuts.d.ts.map +1 -0
  37. package/dist/checks/shortcuts.js +196 -0
  38. package/dist/checks/shortcuts.js.map +1 -0
  39. package/dist/checks/versions.d.ts.map +1 -1
  40. package/dist/checks/versions.js +33 -1
  41. package/dist/checks/versions.js.map +1 -1
  42. package/dist/contract.d.ts +32 -0
  43. package/dist/contract.d.ts.map +1 -1
  44. package/dist/covers.d.ts +56 -0
  45. package/dist/covers.d.ts.map +1 -0
  46. package/dist/covers.js +135 -0
  47. package/dist/covers.js.map +1 -0
  48. package/dist/dedupe.d.ts +23 -0
  49. package/dist/dedupe.d.ts.map +1 -1
  50. package/dist/dedupe.js +96 -2
  51. package/dist/dedupe.js.map +1 -1
  52. package/dist/document.d.ts.map +1 -1
  53. package/dist/document.js +144 -0
  54. package/dist/document.js.map +1 -1
  55. package/dist/envelope.d.ts +8 -0
  56. package/dist/envelope.d.ts.map +1 -1
  57. package/dist/envelope.js +106 -16
  58. package/dist/envelope.js.map +1 -1
  59. package/dist/fixture.d.ts.map +1 -1
  60. package/dist/fixture.js +33 -4
  61. package/dist/fixture.js.map +1 -1
  62. package/dist/html-report.d.ts +24 -7
  63. package/dist/html-report.d.ts.map +1 -1
  64. package/dist/html-report.js +608 -136
  65. package/dist/html-report.js.map +1 -1
  66. package/dist/index.d.ts +13 -0
  67. package/dist/index.d.ts.map +1 -1
  68. package/dist/index.js +13 -0
  69. package/dist/index.js.map +1 -1
  70. package/dist/insights.d.ts.map +1 -1
  71. package/dist/insights.js +9 -12
  72. package/dist/insights.js.map +1 -1
  73. package/dist/links.d.ts +43 -0
  74. package/dist/links.d.ts.map +1 -1
  75. package/dist/links.js +43 -0
  76. package/dist/links.js.map +1 -1
  77. package/dist/observe.d.ts +8 -0
  78. package/dist/observe.d.ts.map +1 -1
  79. package/dist/observe.js +45 -1
  80. package/dist/observe.js.map +1 -1
  81. package/dist/options.d.ts +53 -0
  82. package/dist/options.d.ts.map +1 -1
  83. package/dist/options.js +3 -0
  84. package/dist/options.js.map +1 -1
  85. package/dist/reading-level.d.ts +22 -1
  86. package/dist/reading-level.d.ts.map +1 -1
  87. package/dist/reading-level.js +122 -19
  88. package/dist/reading-level.js.map +1 -1
  89. package/dist/reporter.d.ts.map +1 -1
  90. package/dist/reporter.js +31 -15
  91. package/dist/reporter.js.map +1 -1
  92. package/dist/scan.d.ts +36 -1
  93. package/dist/scan.d.ts.map +1 -1
  94. package/dist/scan.js +16 -2
  95. package/dist/scan.js.map +1 -1
  96. package/dist/screens.d.ts +55 -4
  97. package/dist/screens.d.ts.map +1 -1
  98. package/dist/screens.js +243 -43
  99. package/dist/screens.js.map +1 -1
  100. package/dist/settle.d.ts +35 -0
  101. package/dist/settle.d.ts.map +1 -1
  102. package/dist/settle.js +43 -2
  103. package/dist/settle.js.map +1 -1
  104. package/dist/summary.d.ts +35 -0
  105. package/dist/summary.d.ts.map +1 -1
  106. package/dist/summary.js +248 -28
  107. package/dist/summary.js.map +1 -1
  108. package/dist/unscannable-reasons.d.ts +30 -0
  109. package/dist/unscannable-reasons.d.ts.map +1 -0
  110. package/dist/unscannable-reasons.js +53 -0
  111. package/dist/unscannable-reasons.js.map +1 -0
  112. package/dist/viewports.d.ts +105 -0
  113. package/dist/viewports.d.ts.map +1 -0
  114. package/dist/viewports.js +134 -0
  115. package/dist/viewports.js.map +1 -0
  116. package/package.json +5 -4
package/NOTICE CHANGED
@@ -1,5 +1,5 @@
1
1
  Setsquare
2
- Copyright (c) 2026 Setsquare
2
+ Copyright (c) 2026 WORKTREE AMIGOS LTD (company no. 17430189)
3
3
 
4
4
  This product includes software developed by the Setsquare project
5
5
  (https://setsquare.dev).
@@ -39,7 +39,8 @@ the same thing. The accurate phrase is "Apache-2.0 licensed".
39
39
  Trademarks
40
40
  --------------------------------------------------------------------------------
41
41
 
42
- "Setsquare" and the Setsquare logo are trademarks of the Setsquare project. No
42
+ "Setsquare" and the Setsquare logo are unregistered trademarks of WORKTREE
43
+ AMIGOS LTD. No trademark registration is sought or held (decision D1). No
43
44
  trademark licence is granted by the Apache License — section 6 reserves this
44
45
  expressly — and none is granted by this notice. You may state accurately that
45
46
  your software uses or is compatible with Setsquare; you may not use the name or
package/README.md CHANGED
@@ -62,6 +62,14 @@ export default withSetsquare(defineConfig({/* your config, untouched */}));
62
62
 
63
63
  Then add `.setsquare/` to your `.gitignore`.
64
64
 
65
+ **One install brings the `setsquare` command with it**, which is why there is no
66
+ second install line above. `@setsquare/review-cli` arrives as a dependency and
67
+ owns every command's implementation; the SDK owns the *name*. If you look, you
68
+ will find both packages declaring a `setsquare` binary, and that is deliberate
69
+ rather than a collision — pnpm links binaries only for **direct** dependencies,
70
+ so an SDK-only install would otherwise leave you with no `setsquare` at all.
71
+ Both resolve to the same code.
72
+
65
73
  ## What you get
66
74
 
67
75
  Every settled page in your suite is scanned against **WCAG 2.2 AA**, and the run
@@ -85,6 +93,141 @@ and an evidence file at `.setsquare/runs/<timestamp>/run.json` — the full find
85
93
  their WCAG criteria, measured contrast ratios, the exact ruleset used, and
86
94
  performance timings.
87
95
 
96
+ ### Checks that need the page driven, not read
97
+
98
+ Some of what runs is not axe. A DOM-snapshot analyser can only answer questions
99
+ about the document as it stands; several WCAG criteria are about what the page
100
+ *does*. These run because we are already inside your test, with your page:
101
+
102
+ | Criterion | What it does |
103
+ |---|---|
104
+ | **1.4.8** Visual Presentation, AAA | Measures line spacing, the measure in characters, and justification, on blocks of text. |
105
+ | **1.4.12** Text Spacing | Applies the SC's four spacing metrics and measures what clips. |
106
+ | **2.1.2** No Keyboard Trap | Tabs both ways and looks for a cycle focus never leaves. |
107
+ | **2.1.4** Character Key Shortcuts, opt-in | Watches which key handlers a page registers, and on which characters. |
108
+ | **2.4.7** Focus Visible | Diffs the computed style before and after focus — including `::before`/`::after`. |
109
+ | **2.4.11** Focus Not Obscured (Minimum) | Focuses each element and checks nothing covers it entirely. |
110
+ | **2.4.12** Focus Not Obscured (Enhanced), AAA | The same walk, stricter: no part of it covered. |
111
+ | **2.4.13** Focus Appearance, AAA | Measures the indicator's thickness and its contrast, and states both. |
112
+ | **3.1.5** Reading Level, AAA | A Flesch–Kincaid grade per page. |
113
+ | **3.2.1** On Focus | Focuses each control and watches for a change of context nobody asked for. |
114
+ | **3.2.2** On Input, opt-in | Changes each `<select>`, checkbox and radio and watches the same. |
115
+ | **3.2.3** Consistent Navigation | Compares navigation order **across surfaces**, after the run. |
116
+ | **3.2.4** Consistent Identification | Compares the names given to the same target across surfaces. |
117
+ | **3.2.6** Consistent Help | Compares where help mechanisms appear across surfaces. |
118
+ | **2.4.5** Multiple Ways | Looks across surfaces for navigation, a search control and a sitemap. |
119
+ | **3.3.1 / 4.1.3** Error Identification, Status Messages | Reads a page your test put into an error state. |
120
+
121
+ **If you use Tailwind and 1.4.8 fires across most of your prose, it is one line
122
+ of theme configuration rather than anything you wrote.** Tailwind's type scale
123
+ ships line heights below the 1.5 the SC asks for — `text-sm` is `20px` on a
124
+ `14px` font, which is 1.43 — and line height **inherits**, so one utility on one
125
+ container hands it to every paragraph inside, whatever size those paragraphs
126
+ are. One utility, dozens of findings. The fix is in `@theme`, once:
127
+
128
+ ```css
129
+ @theme inline {
130
+ --text-xs--line-height: 1.55;
131
+ --text-sm--line-height: 1.55;
132
+ --text-base--line-height: 1.55;
133
+ --text-lg--line-height: 1.55;
134
+ --text-xl--line-height: 1.55;
135
+ }
136
+ ```
137
+
138
+ That raises the **default** and leaves `leading-tight` and friends working, so
139
+ headings and single-line labels keep the leading they are meant to have — which
140
+ matters, because 1.4.8 is about *blocks* of text and WCAG defines a block as
141
+ more than one sentence. 1.55 rather than 1.5 so a clamped font size cannot land
142
+ a block a hair under the bar. Worth checking before editing anything, because a
143
+ run of these usually has one cause rather than one per block.
144
+
145
+ The three walks that drive the page — focus, keyboard and reflow — run at
146
+ **teardown only**, and that is a real limitation rather than an implementation
147
+ detail. Focusing an element fires your page's own focus, focusin and blur
148
+ handlers; the keyboard walk presses Tab and Escape, which fires your key
149
+ handlers too; the reflow check resizes the viewport, which re-runs your media
150
+ queries. A handler that opened a menu or started a request has already run by
151
+ the time anything is restored.
152
+
153
+ Scroll position, the previously focused element and the viewport are all put
154
+ back; side effects cannot be. So a scan of a named state
155
+ (`{ state: 'menu-open' }`) carries no evidence from these checks, while
156
+ whatever your test left on screen does.
157
+
158
+ And twenty criteria are reported as **no automated rule can decide this** —
159
+ separately from the criteria nobody has built a rule for yet, because those are
160
+ different facts and an auditor's first question about an untested criterion is
161
+ which of the two it is. Each one carries the reason and what would have to
162
+ change for it to move, so the list is a position rather than a wall. Where
163
+ **presence** is checkable and **adequacy** is not — a caption track exists, but
164
+ whether it matches the audio is a judgement — the entry says so at that
165
+ granularity rather than writing the criterion off whole.
166
+
167
+ That list is the concrete floor under "automated evidence is not conformance".
168
+ A run that tells you twenty criteria no tool will ever check for you has told
169
+ you something more useful than a green tick.
170
+
171
+ Alongside those, eight **heuristics** point at criteria no rule can decide —
172
+ meaningful sequence (1.3.2), sensory instructions (1.3.3), weak headings
173
+ (2.4.6), unheaded runs (2.4.10), abbreviations (3.1.4), location cues (2.4.8),
174
+ missing caption tracks (1.2.1/1.2.2), and more than one route to a page
175
+ (2.4.5). They follow one discipline: **never a violation, always needs a
176
+ person, fire only above a margin, and say what would resolve it.** A heuristic
177
+ that reports a failure is worse than no heuristic, because someone who
178
+ disproves one stops trusting all of them.
179
+
180
+ They are on by default, being read-only and unable to fail a build, and each is
181
+ switchable on its own — `heuristics: { sensoryCharacteristics: false }` — so
182
+ disagreeing with one costs you one rather than all eight. The three that read
183
+ English words stay silent on a page in another language rather than guessing.
184
+
185
+ The last three below are the ones no per-page tool can have. They are statements
186
+ about a **set** of pages, computed after the whole run from what each scan
187
+ already carried — so they cost no extra page work, and they exist because the
188
+ run holds every surface at once.
189
+
190
+ They are also the ones with the most dangerous failure mode, so: **a run with
191
+ fewer than two surfaces reports them as untested, never as passing.** A
192
+ one-page run cannot evidence consistency, and a clean pass on a run that had
193
+ nothing to compare would be the most flattering possible lie. The summary says
194
+ "these criteria compare pages against each other — this run had one surface"
195
+ rather than folding them in with the criteria nothing can check.
196
+
197
+ Only links in navigation, header and footer landmarks are compared, because
198
+ 3.2.4 is about repeated components: naming an inline prose link differently in
199
+ two sentences is ordinary writing, not an inconsistency.
200
+
201
+ **2.1.4 is off unless you turn it on** (`keyShortcuts: true`), and for a
202
+ different reason again. There is no way to enumerate a page's event listeners
203
+ after the fact, so the only route is to wrap `addEventListener` before your own
204
+ scripts run, for the whole life of the page. Everything else here happens after
205
+ a page has loaded and can be undone. Even proven inert — the wrapper records
206
+ and delegates with your original arguments, so `removeEventListener` still
207
+ matches, and the fixture suite asserts exactly that — it is a larger presence in
208
+ your application than a scanner has any business having by default.
209
+
210
+ It only ever reports **needs a person**: 2.1.4 is satisfied if the shortcut can
211
+ be turned off, remapped, or is only active when a component has focus, and all
212
+ three are affordances no check can see.
213
+
214
+ **3.2.2 is off unless you turn it on** (`onInput: true`), and the default is the
215
+ decision rather than caution: a change event is where an application saves, and
216
+ writing to your data is a worse failure than any finding the rule could produce
217
+ — worse than being a flake, because a flake is visible and a silent write is
218
+ not. Turn it on where the suite runs against disposable data, which is most
219
+ suites. Even then, only `<select>`, checkboxes and radios are touched and their
220
+ values are put back; nothing is ever typed into a text field, no form is ever
221
+ submitted, and no navigation is ever allowed to commit.
222
+
223
+ Where geometry or stacking makes the answer a judgement — a translucent overlay
224
+ over the focused element, an indicator drawn with a box-shadow, a focus ring
225
+ against a gradient — these report **needs a person**, never a pass and never a
226
+ fail. So does an element whose focus indicator we could not observe: many sites
227
+ style `:focus-visible` only, and a programmatic focus does not always match it,
228
+ so "nothing changed" is reported as something to check rather than as a
229
+ failure.
230
+
88
231
  ## Every screenshot on one page
89
232
 
90
233
  Playwright takes the screenshots; reading them means opening its report and
@@ -151,6 +294,106 @@ test('the editor reports validation errors accessibly', async ({ page }) => {
151
294
 
152
295
  An explicit scan always outranks an inferred one for the same context.
153
296
 
297
+ ## Scanning at more than one viewport
298
+
299
+ A rule only ever sees the viewport it ran in. A navigation that collapses into a
300
+ menu below a breakpoint is a *different document*, not a narrower one, so a scan
301
+ at 1280 has no opinion about the same page at 390.
302
+
303
+ Setsquare cannot widen that for you — it scans the pages your suite drives, at
304
+ the sizes your suite drives them, and it takes no screenshots at all. A project
305
+ per width does, and it needs no changes to your tests:
306
+
307
+ ```ts
308
+ export default withSetsquare(
309
+ defineConfig({
310
+ projects: [
311
+ { name: 'chromium', use: { ...devices['Desktop Chrome'] } },
312
+ {
313
+ name: 'tablet',
314
+ testMatch: /a11y\.spec\.ts/,
315
+ use: { ...devices['Desktop Chrome'], viewport: { width: 768, height: 1024 } },
316
+ },
317
+ {
318
+ name: 'mobile',
319
+ testMatch: /a11y\.spec\.ts/,
320
+ use: { ...devices['Desktop Chrome'], viewport: { width: 390, height: 844 } },
321
+ },
322
+ ],
323
+ }),
324
+ );
325
+ ```
326
+
327
+ Spreading `Desktop Chrome` and overriding only `viewport` holds the engine
328
+ constant, so the width is the only variable — `devices['iPhone 15']` is WebKit
329
+ and changes both at once. `testMatch` keeps the extra projects to the specs whose
330
+ layout is the subject; a spec that sets its own viewport, or that checks request
331
+ origins or resolves links, returns the same answer at every width. And 320 needs
332
+ no project of its own: `setsquare-reflow` measures WCAG 1.4.10 there on every
333
+ surface already, by resizing at teardown and putting the viewport back.
334
+
335
+ The viewport is part of a scan's identity, so evidence from several widths
336
+ survives instead of collapsing into one row, and the report, the contact sheet
337
+ and the per-surface tables group by band — laptop 1024px and wider, tablet 768px
338
+ to 1023px, mobile narrower than 768px — with the exact size beside every name.
339
+ Those names describe a width and never a device: a 640px viewport is in the
340
+ mobile band whether it is a phone or a desktop browser with text at 200%, and
341
+ every artifact that prints a band name prints that caveat with it.
342
+
343
+ With one viewport in the run, Setsquare says nothing about narrow widths. Not
344
+ "no narrow-viewport failures found" — that would be a claim about your phone
345
+ layout from a run that never looked at it.
346
+
347
+ ## Telling the report what your own tests already cover
348
+
349
+ Some success criteria no automated engine evaluates. Reflow at 320px, focus not
350
+ being obscured by a sticky header, a keyboard trap, whether the navigation is
351
+ consistent between pages — these are checked by driving the page, and a suite
352
+ that has grown up around a real product is usually checking several of them
353
+ already. Until you say so, the conformance report has no way to know: your spec
354
+ arrives as a pass or a fail with no criterion attached to it.
355
+
356
+ So say so:
357
+
358
+ ```ts
359
+ import { setsquare } from '@setsquare/review-sdk';
360
+
361
+ test('no horizontal scrolling at 320px', async ({ page }) => {
362
+ setsquare.covers('1.4.10');
363
+
364
+ await page.setViewportSize({ width: 320, height: 800 });
365
+ await page.goto('/pricing');
366
+ expect(await hasHorizontalOverflow(page)).toBe(false);
367
+ });
368
+ ```
369
+
370
+ That criterion now appears in the report as **covered by your own test**, with
371
+ your test named next to it.
372
+
373
+ **It is recorded as your claim, not as our finding, and the report says so
374
+ everywhere it appears.** We do not check that a test declaring `1.4.10` tests
375
+ reflow — there is no way to — so a declaration is never merged into the state
376
+ that means every automated rule passed. It is its own state, worded
377
+ differently, with its own glyph in the grid. That is the point: the declaration
378
+ is exactly as strong as the test behind it, and the report never pretends
379
+ otherwise.
380
+
381
+ Three details worth knowing:
382
+
383
+ - **A declaring test that fails** is reported as *your own test for this
384
+ criterion did not pass*, and it stops the level reading as clean. It does not
385
+ become a detected failure: we did not observe it, and a red test can be red
386
+ for a reason that has nothing to do with the criterion.
387
+ - **A declaring test that is skipped** is reported as such, rather than folded
388
+ into "no automated check exists" — a check that exists and did not run is a
389
+ different problem.
390
+ - **An id that is not a WCAG 2.2 success criterion throws**, immediately, in
391
+ your test. This is the one thing in this package that does: everywhere else a
392
+ problem warns and carries on, because our evidence-gathering has no standing
393
+ to fail your build. A typo here is different — the alternative is dropping
394
+ your declaration silently, which would leave you believing you have coverage
395
+ you do not have.
396
+
154
397
  ## Configuration
155
398
 
156
399
  Everything is optional. An empty options object produces a useful run.
@@ -164,17 +407,58 @@ export default withSetsquare(defineConfig({/* … */}), {
164
407
  surfaces: { '/jobs/:id/edit': 'job-editor' },
165
408
  mask: ['.candidate-name'],
166
409
  outputDir: '.setsquare',
410
+ quietMs: 500, // how still counts as settled
411
+ settleTimeoutMs: 5000, // how long we wait for it
167
412
  promo: false,
168
413
  });
169
414
  ```
170
415
 
416
+ ### When a page gets scanned, and the two knobs that decide it
417
+
418
+ Scans fire automatically when a page **settles**: `document.readyState` is
419
+ `complete`, and neither the URL nor the DOM has changed for `quietMs`. Any
420
+ mutation restarts that window, which is what makes the scanner wait for late
421
+ content instead of auditing a skeleton.
422
+
423
+ - **`quietMs`** (default `500`) — how long a page must be still. Shorter is not
424
+ better: measured against a route that renders a conformant shell and injects
425
+ its real content a second later, 250ms lands *inside* that gap and reports a
426
+ clean page. 500ms does not.
427
+ - **`settleTimeoutMs`** (default `5000`) — how long we wait for quiet before
428
+ scanning anyway. **It is a trigger, not a give-up.** A page that never goes
429
+ still — a poller, a carousel, a progress animation — is extremely common, and
430
+ declining to scan it would produce exactly the "no findings" that reads as "no
431
+ problems".
432
+
433
+ **What happens to a page that settles late.** If it is still on screen when the
434
+ test ends, it is scanned — at the ceiling, and again at teardown if it changed
435
+ in between, so the evidence describes the finished page. What cannot be
436
+ recovered is a surface the test **navigated away from** while it was still
437
+ rendering: it is gone before anything can look at it, and the run reports it as
438
+ visited-but-never-scanned rather than quietly dropping it. Raising
439
+ `settleTimeoutMs` does not help there — the limit is the test's pace, not ours.
440
+
441
+ **The report tells you which problem you have.** A run with scans cut short
442
+ names the longest wait and the number of DOM mutations still arriving. A page a
443
+ few mutations from quiet will settle if you give it longer; a page with
444
+ thousands never will, and no value of `settleTimeoutMs` changes that.
445
+
171
446
  **Why AA by default.** It is what conformance means in practice, and what
172
447
  EN 301 549 and procurement ask for. AAA is a deliberate commitment — WCAG itself
173
448
  does not recommend it as a general policy — so opting in is the honest default.
174
449
 
175
- **Themes** are read from `data-theme` on the live page when your suite toggles
176
- them in-test, so a suite whose project names carry no theme still gets one context
177
- per theme without configuration.
450
+ **`personas`, `themes` and `surfaces` map your names to ours, and the direction
451
+ is the same in all three: the key is what is in your repository, the value is
452
+ the label you want in the report.** So `personas: { 'a11y-admin': 'recruiter' }`
453
+ means the Playwright **project** named `a11y-admin` is reported as the persona
454
+ `recruiter`; `themes: { 'dark-suite': 'dark' }` reads a project name and reports
455
+ a theme; and `surfaces` maps a URL pattern to a surface name. Keys are Playwright
456
+ project names in the first two and URL patterns in the third — nothing here maps
457
+ the other way round.
458
+
459
+ **Themes** are also read from `data-theme` on the live page when your suite
460
+ toggles them in-test, so a suite whose project names carry no theme still gets
461
+ one context per theme without configuring anything.
178
462
 
179
463
  ## One logical run across several Playwright invocations
180
464
 
@@ -1,6 +1,28 @@
1
- import type { BrowserContext, TestInfo } from '@playwright/test';
1
+ import type { BrowserContext, Page, TestInfo } from '@playwright/test';
2
+ import type { AxeFinding, RuleInapplicable, RulePass } from '@setsquare/schema';
2
3
  import { type ResolvedSetsquareOptions } from './options.js';
3
4
  export declare function installAutoScan(context: BrowserContext, options: ResolvedSetsquareOptions, testInfo: TestInfo, warn: (message: string) => void): Promise<void>;
5
+ /**
6
+ * Setsquare's own driven checks: the ones that need the page acted on rather
7
+ * than read.
8
+ *
9
+ * Extracted so the teardown scan and the checks-only teardown record run
10
+ * exactly the same set. Two call sites with two hand-maintained lists is how a
11
+ * check ends up silently missing from half the runs.
12
+ */
13
+ export declare function runDrivenChecks(page: Page, options: ResolvedSetsquareOptions,
14
+ /**
15
+ * Had this page met the quiet definition when the checks ran?
16
+ *
17
+ * Defaults to true, so an explicit `setsquare.scan()` suppresses nothing: the
18
+ * customer chose the moment, and second-guessing their choice would be us
19
+ * deciding their page was not ready when they said it was.
20
+ */
21
+ pageWentQuiet?: boolean): Promise<{
22
+ findings: AxeFinding[];
23
+ passes: RulePass[];
24
+ inapplicable: RuleInapplicable[];
25
+ }>;
4
26
  /**
5
27
  * Scan whatever the test left on screen, at teardown.
6
28
  *
@@ -1 +1 @@
1
- {"version":3,"file":"autoscan.d.ts","sourceRoot":"","sources":["../src/autoscan.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAQ,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAavE,OAAO,EAAqB,KAAK,wBAAwB,EAAE,MAAM,cAAc,CAAC;AA+DhF,wBAAgB,eAAe,CAC7B,OAAO,EAAE,cAAc,EACvB,OAAO,EAAE,wBAAwB,EACjC,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,GAC9B,OAAO,CAAC,IAAI,CAAC,CAqEf;AA6LD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE,cAAc,EACvB,OAAO,EAAE,wBAAwB,EACjC,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,GAC9B,OAAO,CAAC,IAAI,CAAC,CA0Df"}
1
+ {"version":3,"file":"autoscan.d.ts","sourceRoot":"","sources":["../src/autoscan.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACvE,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAoBhF,OAAO,EAAqB,KAAK,wBAAwB,EAAE,MAAM,cAAc,CAAC;AAmGhF,wBAAgB,eAAe,CAC7B,OAAO,EAAE,cAAc,EACvB,OAAO,EAAE,wBAAwB,EACjC,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,GAC9B,OAAO,CAAC,IAAI,CAAC,CAqFf;AAsMD;;;;;;;GAOG;AACH,wBAAsB,eAAe,CACnC,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,wBAAwB;AACjC;;;;;;GAMG;AACH,aAAa,UAAO,GACnB,OAAO,CAAC;IAAE,QAAQ,EAAE,UAAU,EAAE,CAAC;IAAC,MAAM,EAAE,QAAQ,EAAE,CAAC;IAAC,YAAY,EAAE,gBAAgB,EAAE,CAAA;CAAE,CAAC,CAuC3F;AAuGD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE,cAAc,EACvB,OAAO,EAAE,wBAAwB,EACjC,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,GAC9B,OAAO,CAAC,IAAI,CAAC,CAiGf"}