UCDL Accessibility Use Case Definition Language
Contents

Accessibility Use Case Definition Language (UCDL) and Runner

This section is normative for the reference implementation.

usecase-runner <command> [options]

Commands:
  generate <path>    Generate Playwright .spec.ts files from use case YAML
  run <path>         Execute use cases directly and produce reports
  validate <path>    Validate use case YAML files without running them
  init               Create a sample use case file and config in cwd

Options:
  -c, --config <path>    Path to config file (default: ./usecase-runner.config.yaml)
  -o, --outdir <dir>     Output directory for generated tests (generate mode)
  -b, --browser <type>   Browser to use: chromium, firefox, webkit
      --headed           Run in headed mode
      --run              Generate and immediately run (generate mode)
      --set <pairs...>   Override test data variables (key=value)
  -r, --report <fmts>    Report formats (comma-separated)
      --profile <name>   Enforce an interaction profile (run, generate)
      --storage-state <path>  Playwright storageState.json to seed the context (run)
  -v, --verbose          Verbose output
      --no-color         Disable ANSI colour (§14.2)
      --plain            ASCII-only, uncoloured output (§14.2)
      --json             One JSON document on stdout (§14.2)
  -h, --help             Show help

<path> MAY be either a file or a directory. When a directory, all **/*.uc.yaml files within it are processed.

generate --run invokes npx playwright test <outdir> after generation.

run --set k=v accepts multiple pairs and merges them with values from data_files (CLI takes precedence).

validate parses and resolves all use cases (including extension chains and template variables) but does not run a browser.

The exit code is the contract a CI job gates on, so a scored failure MUST be distinguishable from success without parsing output or reports.

Code Meaning
0 Every use case processed scored pass or pass_with_conditions
1 At least one use case scored fail or error, or the command threw

run MUST exit non-zero when any use case scores fail or error. A step blocked by --profile is a scored failure rather than a thrown error, so a processor that exits non-zero only on thrown errors would let a profile violation pass CI silently — the run would gate on nothing but crashes.

Because a run may process many use cases, the exit code MUST reflect the whole batch: every use case is still executed and reported, and the non-zero status is set after the last one rather than short-circuiting on the first failure. This keeps continue_on_failure semantics (§11) intact while still failing the job.

A processor's own interface is subject to the same reasoning as the pages it tests: output that only some people can read is a defect in the tool.

A processor MUST make one colour decision before it writes anything, and MUST NOT emit ANSI escape sequences on either stream when any of these hold:

  • --no-color was passed, in any position the command line accepts options;
  • NO_COLOR is present in the environment and is not the empty string (https://no-color.org/);
  • TERM is dumb;
  • standard output is not a terminal.

FORCE_COLOR MAY force colour on, including when standard output is not a terminal, and FORCE_COLOR=0 MUST turn it off. Where FORCE_COLOR conflicts with an explicit request for no colour, the request for no colour wins: it is chosen per command or per user, whereas FORCE_COLOR is typically exported once by a continuous-integration image.

The decision has to precede the first byte written, which includes any diagnostic the argument parser itself emits. A processor that computes it inside a command's handler will already have printed an unknown-option error in colour.

Colour MUST NOT be the only carrier of meaning. Every line that a colour distinguishes MUST also be distinguishable by its text — a score is spelled out, a report path is labelled, a failure names what failed. Low-contrast styling (grey on a themed terminal, in particular) MUST NOT be the only thing marking a line as secondary.

A processor SHOULD offer a plain mode, and the reference implementation spells it --plain (equivalently USECASE_RUNNER_PLAIN in the environment). Plain mode implies no colour, restricts output to ASCII, and separates sections with a blank line rather than with styling. The restriction matters because a screen reader announces → as "right arrow" or omits it entirely depending on the user's punctuation level, and a field separator that disappears welds two values together. Text taken from a use case document SHOULD be transliterated rather than discarded. A processor that starts a child process in plain mode MUST also stop that child rewriting lines in place — for Playwright, PLAYWRIGHT_FORCE_TTY=0.

A processor SHOULD offer a structured mode, spelled --json in the reference implementation. In structured mode standard output MUST carry exactly one JSON document and nothing else, and every message addressed to a person — progress, warnings, errors, and any child process's own output — MUST go to standard error. The document is the console summary in machine-readable form; it does not replace the reports of §10.

A diagnostic about a document MUST name that document and the field at fault. When a directory is processed, the document at fault is not the argument the user typed, so naming it is what makes the diagnostic actionable. Serialising a schema validator's internal issue objects is not a diagnostic.

A processor MUST document these controls in its --help output and in its user documentation, including the environment variables, which are otherwise undiscoverable.