Skip to main content

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.

playwright.config.ts
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

Every key is optional. Defaults are what an empty options object gives you.
OptionTypeDefaultWhat 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.
bestPracticebooleanfalseAdd axe’s advisory rules. Good advice, not WCAG failures, so a finding from one carries no WCAG block.
readingLevelbooleanon at AAAA 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
autoScanbooleantrueScan every settled navigation in every test.
quietMsnumber500How long the URL and DOM must stay still before a page can count as settled.
settleTimeoutMsnumber5000How long to wait for the page to settle before scanning anyway. A trigger, not a give-up.
settleByRouteRecord<string, { quietMs?, settleTimeoutMs? }>—Settle windows for particular route patterns. The most literal match wins.
loadingSelectorsstring[]—Selectors for your own loading placeholders, such as .animate-pulse. A page showing one is not settled.
scanTimeoutMsnumber10000The longest a single scan may hold your test.
captureStatesbooleanfalseAlso scan a dialog opening, a field going invalid, an alert or an expanded region, once the page goes quiet.
Checks that drive the page
listenersbooleanfalseRecord 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.
keyShortcutsbooleanfalseThe earlier name for listeners. Either turns it on.
onInputbooleanfalseCheck 3.2.2 by changing selects, checkboxes and radios, then putting them back. For suites on disposable data.
clickProbebooleanfalseCheck 2.5.5 by clicking the controls this run already failed, for a wrapper that takes the click.
paintedContrastbooleantrueMeasure contrast from painted pixels where CSS cannot resolve the background. The capture is never kept.
heuristicsHeuristicSwitchesall onTurn single heuristics off: { sensoryCharacteristics: false }.
Naming
surfacesRecord<string, string>—URL pattern to surface name: { '/jobs/:id/edit': 'job-editor' }.
personasRecord<string, string>—Playwright project name to the persona it is reported as.
themesRecord<string, string>—Playwright project name to a theme. Also read from data-theme on the live page.
personastring—The persona for a suite whose project names carry none.
themestring—The theme for a suite whose project names carry none.
Output
outputDirstring'.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.
verbosebooleanfalsePrint every section in the terminal, for a CI log with no report to open.
maskstring[]—Extra regions to mask, added to the built-in defaults.
maskDefaultsbooleantrueSet 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.

e2e/editor.spec.ts
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

OptionTypeWhat it holds
statestringThe named state being evidenced: validation-errors, menu-open.
themestringOverrides whatever the DOM says. Your statement outranks our sniffing.
personastringOverrides the project-name mapping for this scan.
settlebooleanWait 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.

FieldTypeWhat it holds
surfacestringThe surface the scan was filed under.
wcagTarget'AA' | 'AAA'The level this scan was assessed against.
violationsnumberFailing results.
violatedRulesstring[]The rule ids behind violations, sorted. Lets a test accept one known failure by name.
incompletenumberResults that need a person.
incompleteRulesstring[]The rule ids behind incomplete, so the undecided set can be watched, not just counted.
passesnumberRules that held.
scannedbooleanFalse 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.

e2e/reflow.spec.ts
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

An id that isn’t a WCAG 2.2 success criterion throws at once, in your test. Everywhere else a problem warns and carries on; dropping a typo silently would leave you believing you have coverage you don’t.

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.

e2e/checkout.spec.ts
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.

e2e/order.spec.ts
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

ExportWhat 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_BANDSThe 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.

VariableWhat it does
SETSQUARE_VERBOSESet to 1 to print the whole summary in the terminal.
SETSQUARE_AUTOSCANSet to 0 to turn auto-scan off for this invocation. Explicit scan() calls still run.
SETSQUARE_DISABLEDSet to 1 to turn the SDK off entirely, to measure what it costs your suite.
SETSQUARE_OUTPUT_DIRWrite runs here instead of outputDir.
SETSQUARE_SUMMARY_MDAlso write the summary as Markdown to this path, for a CI job summary.
SETSQUARE_CHANGED_ONLYScan only the surfaces in the file setsquare changed wrote.
SETSQUARE_RUN_IDOne id per suite execution, shared by every invocation that should merge into one run.
SETSQUARE_RUN_PARTSHow many invocations that execution makes. The only way a merged run can say it is complete.
SETSQUARE_LANEA 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

CommandWhat it does
auditReport what your Playwright suite covers. Reads only; writes nothing.
doctorReport 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.
initAdd Setsquare to every Playwright config in this project.
findingsWrite 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>.
sarifThe same findings as SARIF 2.1.0, for GitHub code scanning, the VS Code problems panel and JetBrains inspections. Add --out <file>.
verifyRe-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.
changedWork 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.
reportFind the newest run's HTML report. Add --open to view it.
screensFind the newest run's screenshot contact sheet — every test's captures on one page. Add --open to view it.
helpShow this help.
versionPrint the CLI version.

Options

OptionWhat 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-runFor init: report what would change, write nothing.
--openFor report or screens: open it in your browser.
--jsonFor 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-partialFor 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.

PathWhat it does
runs/<timestamp>/run.jsonThe evidence: findings, criteria, contrast ratios, the exact ruleset, timings.
runs/<timestamp>/report.htmlFailing rules by surface, with selectors, and the criteria-by-surfaces grid.
runs/<timestamp>/screens.htmlAn index of the screenshots Playwright wrote, linked where they lie.
runs/group-<id>/One merged run across invocations that shared SETSQUARE_RUN_ID.
changed.jsonThe route set setsquare changed worked out, for SETSQUARE_CHANGED_ONLY.