Reference · @setsquare/review-sdk 0.9.0
API reference
One function goes in your config. Four calls go in a test when you want more than auto-scan. Everything else is optional: an empty options object produces a useful run.
withSetsquare()
withSetsquare(config: PlaywrightTestConfig, options?: SetsquareOptions): PlaywrightTestConfig
Wraps your Playwright config and appends one reporter. Projects, testDir, use, webServer and timeouts stay as you wrote them.
import { defineConfig } from '@playwright/test';
import { withSetsquare } from '@setsquare/review-sdk';
export default withSetsquare(defineConfig({ testDir: './e2e' }), {
wcag: 'AAA', // default 'AA'
personas: { 'a11y-admin': 'recruiter' },
themes: { 'dark-suite': 'dark' },
surfaces: { '/jobs/:id/edit': 'job-editor' },
mask: ['.candidate-name'],
settleByRoute: { '/pages/editor': { settleTimeoutMs: 15000 } },
});Options
| Option | Type | Default | What it does |
|---|---|---|---|
| What is assessed | |||
wcag | 'AA' | 'AAA' | 'AA' | The level to assess against. AAA adds axe’s AAA rules and Setsquare’s AAA checks. |
bestPractice | boolean | false | Add axe’s advisory rules. Good advice, not WCAG failures, so a finding from one carries no WCAG block. |
readingLevel | boolean | on at AAA | A Flesch–Kincaid grade per page, for 3.1.5. Always needs review, never a violation. |
scope | 'page' | 'component' | 'page' | component for Storybook stories: the page-only criteria read as not applying, with the reason. |
| When a page is scanned | |||
autoScan | boolean | true | Scan every settled navigation in every test. |
quietMs | number | 500 | How long the URL and DOM must stay still before a page can count as settled. |
settleTimeoutMs | number | 5000 | How long to wait for the page to settle before scanning anyway. A trigger, not a give-up. |
settleByRoute | Record<string, { quietMs?, settleTimeoutMs? }> | — | Settle windows for particular route patterns. The most literal match wins. |
loadingSelectors | string[] | — | Selectors for your own loading placeholders, such as .animate-pulse. A page showing one is not settled. |
scanTimeoutMs | number | 10000 | The longest a single scan may hold your test. |
captureStates | boolean | false | Also scan a dialog opening, a field going invalid, an alert or an expanded region, once the page goes quiet. |
| Checks that drive the page | |||
listeners | boolean | false | Record the listeners a page registers, before its scripts run. 2.1.4, 2.5.1, 2.5.2, 2.5.4 and 2.5.7 need it. |
keyShortcuts | boolean | false | The earlier name for listeners. Either turns it on. |
onInput | boolean | false | Check 3.2.2 by changing selects, checkboxes and radios, then putting them back. For suites on disposable data. |
clickProbe | boolean | false | Check 2.5.5 by clicking the controls this run already failed, for a wrapper that takes the click. |
paintedContrast | boolean | true | Measure contrast from painted pixels where CSS cannot resolve the background. The capture is never kept. |
heuristics | HeuristicSwitches | all on | Turn single heuristics off: { sensoryCharacteristics: false }. |
| Naming | |||
surfaces | Record<string, string> | — | URL pattern to surface name: { '/jobs/:id/edit': 'job-editor' }. |
personas | Record<string, string> | — | Playwright project name to the persona it is reported as. |
themes | Record<string, string> | — | Playwright project name to a theme. Also read from data-theme on the live page. |
persona | string | — | The persona for a suite whose project names carry none. |
theme | string | — | The theme for a suite whose project names carry none. |
| Output | |||
outputDir | string | '.setsquare' | Where runs are written, relative to the Playwright config rather than the working directory. |
format | 'text' | 'markdown' | 'json' | 'text' | How the summary prints. Markdown survives being pasted into an issue. |
grid | 'matrix' | 'rows' | 'matrix' | How the conformance grid renders in the terminal. |
verbose | boolean | false | Print every section in the terminal, for a CI log with no report to open. |
mask | string[] | — | Extra regions to mask, added to the built-in defaults. |
maskDefaults | boolean | true | Set to false to drop the built-in mask defaults. A deliberate act. |
setsquare.scan()
setsquare.scan(page: Page, surface: string, options?: ScanOptions): Promise<ScanSummary>
Waits for the page to settle, then scans it under a surface name you choose. Use it for a state your test reaches that the URL doesn’t show: a dialog that’s open, a form showing its errors. An explicit scan always outranks an inferred one for the same context.
import { test } from '@playwright/test';
import { setsquare } from '@setsquare/review-sdk';
test('the editor reports validation errors accessibly', async ({ page }) => {
await page.goto('/jobs/42/edit');
await page.getByRole('button', { name: 'Save' }).click();
await setsquare.scan(page, 'job-editor', { state: 'validation-errors' });
});ScanOptions
| Option | Type | What it holds |
|---|---|---|
state | string | The named state being evidenced: validation-errors, menu-open. |
theme | string | Overrides whatever the DOM says. Your statement outranks our sniffing. |
persona | string | Overrides the project-name mapping for this scan. |
settle | boolean | Wait for the page to settle first. Default true; false scans the page as it is, and the record says what was still loading. |
ScanSummary
What the scan found, returned so a test can assert on it. Facts only, and no comparison of any kind: locally there is nothing to compare against.
| Field | Type | What it holds |
|---|---|---|
surface | string | The surface the scan was filed under. |
wcagTarget | 'AA' | 'AAA' | The level this scan was assessed against. |
violations | number | Failing results. |
violatedRules | string[] | The rule ids behind violations, sorted. Lets a test accept one known failure by name. |
incomplete | number | Results that need a person. |
incompleteRules | string[] | The rule ids behind incomplete, so the undecided set can be watched, not just counted. |
passes | number | Rules that held. |
scanned | boolean | False when the scan could not run. The SDK never throws into your test. |
setsquare.covers()
setsquare.covers(...criteria: string[]): void
Says that this test checks a WCAG 2.2 success criterion. The report lists it as covered by your own test, with the test named beside it, and records it as your claim rather than our finding.
test('no horizontal scrolling at 320px', async ({ page }) => {
setsquare.covers('1.4.10');
await page.setViewportSize({ width: 320, height: 800 });
await page.goto('/pricing');
expect(await hasHorizontalOverflow(page)).toBe(false);
});This is the one call that throws
Pointing at a moment
Some criteria are out of reach only because we don’t know something your suite does: when a session expired, or which step comes before a submission completes. Point at that moment and the SDK takes the measurement.
setsquare.acrossReauthentication()
setsquare.acrossReauthentication(page: Page, run: () => Promise<void>): Promise<void>
For 2.2.5 Re-authenticating.
await page.goto('/checkout');
await page.fill('#address', '12 Example Street');
await setsquare.acrossReauthentication(page, async () => {
await page.context().clearCookies(); // however your app ends a session
await signBackIn(page);
});setsquare.acrossSubmission()
setsquare.acrossSubmission(page: Page, options: { consequential?: boolean }, run: () => Promise<void>): Promise<void>
For 3.3.6, and for 3.3.4 when consequential is true.
await setsquare.acrossSubmission(page, { consequential: true }, async () => {
await page.click('#review-order'); // the step before it completes
});What each one measures, in the SDK’s own words, is in What your tests cover.
Helpers
| Export | What it’s for |
|---|---|
storybookStories(indexPath, options?) | The stories in a Storybook index.json, for scope: 'component'. |
inferSurface(urlPattern, config?) | The surface name auto-scan would give a URL pattern, so your own scans agree with it. |
toUrlPattern(url) | A URL as the envelope carries it: identifier segments as :id, no query, no fragment. |
maskLocators(page, config?) | Locators for the masked regions, for your own screenshots. |
VIEWPORT_BANDS | The width bands the report groups by. |
Environment variables
For CI and for the script that calls Playwright, where editing the config isn’t the right lever.
| Variable | What it does |
|---|---|
SETSQUARE_VERBOSE | Set to 1 to print the whole summary in the terminal. |
SETSQUARE_AUTOSCAN | Set to 0 to turn auto-scan off for this invocation. Explicit scan() calls still run. |
SETSQUARE_DISABLED | Set to 1 to turn the SDK off entirely, to measure what it costs your suite. |
SETSQUARE_OUTPUT_DIR | Write runs here instead of outputDir. |
SETSQUARE_SUMMARY_MD | Also write the summary as Markdown to this path, for a CI job summary. |
SETSQUARE_CHANGED_ONLY | Scan only the surfaces in the file setsquare changed wrote. |
SETSQUARE_RUN_ID | One id per suite execution, shared by every invocation that should merge into one run. |
SETSQUARE_RUN_PARTS | How many invocations that execution makes. The only way a merged run can say it is complete. |
SETSQUARE_LANE | A label for this invocation in a merged run: functional, a11y, shard-1. |
The setsquare command
setsquare <command> [options]
Installed with the SDK. audit and doctor need nothing installed and send nothing anywhere, so you can run them first with npx @setsquare/review-cli audit. These tables are the command’s own help.
Commands
| Command | What it does |
|---|---|
audit | Report what your Playwright suite covers. Reads only; writes nothing. |
doctor | Report what your suite is CONFIGURED not to see — disabled rules, excluded regions, missing tags — plus settings that leave a Setsquare feature empty. Static, read-only, always exits 0. |
init | Add Setsquare to every Playwright config in this project. |
findings | Write the newest run's findings as machine-readable markdown — rule, criteria, context, selectors, candidate source files and a command that reproduces each one. Add --out <file>. |
sarif | The same findings as SARIF 2.1.0, for GitHub code scanning, the VS Code problems panel and JetBrains inspections. Add --out <file>. |
verify | Re-scan one surface and say what still fires. Needs --surface <name>. Three answers only: still failing, no longer detected, newly detected. Makes no better/worse claim. |
changed | Work out which routes a change can reach and write .setsquare/changed.json, for a run that scans only those surfaces. Refuses rather than guess: no set is written unless every import resolved. Add --base <ref>, or --allow-partial to accept a set it cannot vouch for. |
report | Find the newest run's HTML report. Add --open to view it. |
screens | Find the newest run's screenshot contact sheet — every test's captures on one page. Add --open to view it. |
help | Show this help. |
version | Print the CLI version. |
Options
| Option | What it does |
|---|---|
--cwd <dir> | Work in this directory instead of the current one. |
--config <name> | Wrap only this config, instead of every one found. |
--dry-run | For init: report what would change, write nothing. |
--open | For report or screens: open it in your browser. |
--json | For doctor: emit the report as JSON and nothing else. |
--out <file> | For findings or sarif: write to this file instead of stdout. |
--run <dir> | Read this .setsquare/runs directory instead of searching. |
--surface <name> | For verify: which surface to re-scan. |
--routes <file> | For audit: use this route list (one path per line) instead of detecting a framework. |
--sitemap <file> | For audit: read routes from this sitemap.xml. |
--include <dirs> | Read these directories even though they look generated. Comma-separated names, e.g. --include reports. Setsquare skips build and report output (dist, build, out, coverage, reports, playwright-report, test-results, storybook-static and dot-directories) so a build artefact is never offered as the source of a finding. Use this when yours is real source. |
--base <ref> | For changed: diff against this ref. Default origin/main. |
--allow-partial | For changed: write a route set even when the import graph has holes. Under-scanning is a clean run over a broken app, so this is off by default and says so in the file it writes. |
What a run writes
Everything lands under outputDir, .setsquare by default.
| Path | What it does |
|---|---|
runs/<timestamp>/run.json | The evidence: findings, criteria, contrast ratios, the exact ruleset, timings. |
runs/<timestamp>/report.html | Failing rules by surface, with selectors, and the criteria-by-surfaces grid. |
runs/<timestamp>/screens.html | An index of the screenshots Playwright wrote, linked where they lie. |
runs/group-<id>/ | One merged run across invocations that shared SETSQUARE_RUN_ID. |
changed.json | The route set setsquare changed worked out, for SETSQUARE_CHANGED_ONLY. |