🧪 Test Hub
testing: Demo target v3.0.0 · built-in demo site

DEMO-022 Freight: accessibility scan (WCAG 2.1 AA)

Edit Load test Duplicate

Scans five pages with axe-core (shipped with the hub, runs offline) and fails on the critical and serious WCAG 2.1 AA problems, grouped by rule. The full report is saved as a11y-report.html with the run.

508accessibilitydemofreight version: 1.0 DEMO-022__freight_accessibility.py group: Freight extras

Runs
6
Pass rate
67%
4 passed / 2 failed
Avg duration
6s
p95 7s
Estimate
6s
avg of last 10 judged runs
Flakiness
0.40
0 stable · 1 alternates
Current streak
2
passed

Last 6 results newest on the right — click a square to open that run

Duration per run point color = outcome; dashed = 7-run average; click a point to open the run

Step timing trends the same step compared across the last 6 runs — slowest steps first, one line each

How long it takes distribution of 6 runs — two humps mean two different behaviours hiding behind one average

fastest 6s · slowest 7s

Why this test failed grouped by message, last 90 days

timesmessagelast
2 AssertionError: WCAG 2.1 AA: 4 rule(s) broken (details: a11y-report.h… Sep 24 open

Outcomes by target version

What this test does plain language, derived from the code

  1. site = Freight(page, ctx)
  2. audit = Audit(page, ctx)
  3. for label, path in PAGES:
  4. with ctx.timed(f"scan: {label}"):
  5. site.open(path)
  6. page.wait_for_load_state("networkidle")
  7. audit.scan(label)
  8. site.sign_in()
  9. ⏱ Timed phase: scan: staff dashboard
  10. site.open("ops/")
  11. page.wait_for_load_state("networkidle")
  12. audit.scan("staff dashboard")
  13. report = audit.save_report()
  14. ctx.log(f"report saved: {report.name}")
  15. audit.assert_clean()
Show the code
"""Accessibility (WCAG 2.1 AA -- what Section 508 points to), on every release.

Scans the pages most visitors use with axe-core, the engine behind most
commercial accessibility scanners, shipped in _lib/axe/ so it runs offline.
Fails on the problems a screen-reader or keyboard user actually runs into
(axe's "critical" and "serious"), grouped by rule with the pages they are on;
the full report -- every element, the HTML it quotes, how to fix it -- is
saved as a11y-report.html with the run's files.

Acme Freight 2.0.0's redesign breaks four rules at once (the page language,
a skip link hidden from screen readers, the map's text alternative, brand
colours with too little contrast). A visual check sees none of them: the
pages look fine. That is the point of running both.
"""
from _lib.a11y import Audit
from _lib.freight import Freight

PAGES = [("home page", ""), ("tracking", "track/?id=AF-100001"),
         ("quote, step 1", "quote/?restart=1"), ("staff sign-in", "login/")]


def run(page, ctx):
    site = Freight(page, ctx)
    audit = Audit(page, ctx)
    for label, path in PAGES:
        with ctx.timed(f"scan: {label}"):
            site.open(path)
            page.wait_for_load_state("networkidle")
            audit.scan(label)
    site.sign_in()
    with ctx.timed("scan: staff dashboard"):
        site.open("ops/")
        page.wait_for_load_state("networkidle")
        audit.scan("staff dashboard")
    report = audit.save_report()
    ctx.log(f"report saved: {report.name}")
    audit.assert_clean()

All runs

RunStatusQueuedDuration VersionTriggerBatch
#362 passed 2026-09-24 22:05:07 6s 3.0.0 group group: Freight extras
#347 passed 2026-09-24 20:41:19 6s 3.0.0 cli-adopted 3 tests (terminal)
#344 failed 2026-09-24 20:41:04 7s 2.1.0 cli-adopted 3 tests (terminal)
#341 failed 2026-09-24 20:40:49 6s 2.0.0 cli-adopted 3 tests (terminal)
#338 passed 2026-09-24 20:40:35 6s 1.1.0 cli-adopted 3 tests (terminal)
#335 passed 2026-09-24 20:40:21 7s 1.0.0 cli-adopted 3 tests (terminal)