WCAGpilot Worker Test Fixtures

Static good/bad pages for exercising every modular worker. Each worker has isolated single-check files plus an all-bad.html (and where useful all-good.html) that packs several issues onto one page.

Legend: PASS · FAIL · WARNING · N/A · AI outcome depends on the Gemini model and is not 100% deterministic.

How to test

HTML-parsing workers accept the page markup directly in the request body, e.g.:

POST https://api.wcagpilot.com/w/headings with { "html": "<the page source>" }

URL-fetching workers (axe, keyboard-focus, reflow) need a live public URL — deploy this folder, then pass the deployed page URL, e.g. { "pages": [{ "url": "https://YOUR-HOST/axe/all-bad.html" }] }.

Headings — /w/headings

FixtureExpectedCheck
good-structure.htmlPASSOne H1 first, clean hierarchy, no empty headings
no-headings-bad.htmlWARNINGpresence — no headings
no-h1-bad.htmlWARNINGh1_first — no H1
multiple-h1-bad.htmlWARNINGh1_first — multiple H1
skipped-level-bad.htmlWARNINGhierarchy — H1 jumps to H3
empty-heading-bad.htmlFAILempty_headings
aria-no-level-bad.htmlFAILaria_misuse — role=heading, no aria-level
heading-in-button-bad.htmlFAILaria_misuse — heading inside button (F43)
visual-heading-bad.htmlFAILAIvisual_headings (F2)
semantic-mismatch-bad.htmlFAILAIcontent_match
all-bad.htmlFAILSeveral issues combined
all-good.htmlPASSFull clean outline

Dynamic rendering — shadow DOM & client-rendered SPA

These pages have no headings in their static HTML — the outline lives in shadow roots (web components) or is painted by JS after load. A raw { "html": ... } parse sees an empty page (false WARNING); the extension's in-page extraction and headless-render workers (axe) see the real outline. Use these to verify the analyzer reaches rendered content.

FixtureExpected (rendered)Check
webcomponents-good.htmlPASSClean outline inside shadow DOM
webcomponents-bad.htmlFAILEmpty heading + skipped level in shadow DOM
spa-good.htmlPASSClean outline rendered client-side
spa-bad.htmlFAILNo h1 + empty heading, rendered client-side

Page titles — /w/titles AI (fully model-driven)

FixtureExpectedCheck
descriptive-good.htmlPASSTopic + site name
generic-inner-bad.htmlFAILBrand-only on an inner page
placeholder-bad.htmlFAIL"Untitled Document"
too-long-warn.htmlWARNING> 70 characters
too-short-warn.htmlWARNING< 5 characters
all-caps-warn.htmlWARNINGALL CAPS title

Skip links — /w/skip-links

FixtureExpectedCheck
good.htmlPASSFirst focusable, visible, target exists
sr-only-good.htmlPASSVisually hidden, recovers on focus
missing-bad.htmlFAILNo skip link
broken-target-bad.htmlFAILTarget id does not exist
hidden-bad.htmlFAILdisplay:none, no focus recovery
button-partial.htmlPARTIALbutton instead of anchor
not-first-partial.htmlPARTIALNot the first focusable element
all-bad.htmlFAILNo skip link and no main landmark

Forms — /w/forms (label quality is AI)

FixtureExpectedCheck
label-for-good.htmlPASSlabel[for]
label-wrap-good.htmlPASSWrapped label
aria-label-good.htmlPASSaria-label
aria-labelledby-good.htmlPASSaria-labelledby
required-both-good.htmlPASSrequired_match=both
group-fieldset-good.htmlPASSfieldset + legend group
no-label-bad.htmlFAILNO_LABEL
placeholder-only-bad.htmlFAILPLACEHOLDER_ONLY
title-only-warn.htmlWARNINGTITLE_ONLY
misleading-bad.htmlFAILAILABEL_MISLEADING
vague-warn.htmlWARNINGAILABEL_VAGUE
required-visual-only-warn.htmlWARNINGrequired_match=visual_only
group-no-fieldset-warn.htmlWARNINGGroup without fieldset/legend
all-bad.htmlFAILSeveral issues combined
all-good.htmlPASSEvery field correct

Media — /w/media

FixtureExpectedCheck
captions-good.htmlPASScaptions — track present
transcript-good.htmlPASStranscripts — link present
audio-description-good.htmlPASSaudio_description — track present
captions-missing-bad.htmlFAILcaptions — native video, no track
audio-no-transcript-bad.htmlFAILtranscripts — audio, no link
youtube-warn.htmlWARNINGcaptions — platform may provide
video-no-transcript-warn.htmlWARNINGtranscripts — recommended
all-bad.htmlFAILSeveral issues combined
all-good.htmlPASSCaptions + transcripts + descriptions

Keyboard focus — /w/keyboard-focus (needs public URL)

FixtureExpectedCheck
default-focus-good.htmlPASSFOCUS_DEFAULT
custom-outline-good.htmlPASSFOCUS_REPLACED — custom outline
box-shadow-good.htmlPASSFOCUS_REPLACED — box-shadow
focus-visible-good.htmlPASSFOCUS_REPLACED — :focus-visible
global-outline-none-bad.htmlFAILFOCUS_REMOVED_GLOBAL
scoped-outline-none-warn.htmlWARNINGFOCUS_REMOVED_SCOPED
no-focusable-na.htmlN/ANA_NO_FOCUSABLE
all-bad.htmlFAILGlobal removal with many focusables

Reflow & zoom — /w/reflow (needs public URL)

FixtureExpectedCheck
responsive-good.htmlPASSREFLOW_OK + ZOOM_OK
zoom-blocked-bad.htmlFAILZOOM_BLOCKED — user-scalable=no
maximum-scale-bad.htmlFAILZOOM_BLOCKED — maximum-scale=1
fixed-width-bad.htmlFAILREFLOW_LIKELY_FAIL — >3 fixed widths
single-wide-warn.htmlWARNINGREFLOW_POSSIBLE — one wide element
small-fonts-warn.htmlWARNINGZOOM_SMALL_FONTS
all-bad.htmlFAILZoom blocked + fixed widths + small fonts

Alt text — /w/alt-texts-v2 (quality is AI vision)

FixtureExpectedCheck
decorative-good.htmlPASSEMPTY_DECORATIVE — aria-hidden
spacer-good.htmlPASSEMPTY_DECORATIVE — 1x1 spacer
redundant-link-good.htmlPASSEMPTY_REDUNDANT_LINK
svg-decorative-good.htmlPASSDecorative inline SVG
informative-good.htmlPASSAIINFORMATIVE_SHORT — alt matches
missing-alt-bad.htmlFAILNo alt attribute
functional-no-alt-bad.htmlFAILFUNCTIONAL_ACTION — icon button, empty alt
filename-alt-bad.htmlFAILAlt is a filename
generic-alt-bad.htmlFAILGeneric placeholder alt
svg-link-no-name-bad.htmlFAILSVG-only link, no name
background-meaningful-bad.htmlFAILAIMeaningful CSS background
vague-alt-warn.htmlWARNINGAIAlt too vague (partial match)
complex-chart-warn.htmlWARNINGAICOMPLEX_PLUS_LONGDESC
all-bad.htmlFAILSeveral issues combined
all-good.htmlPASSDecorative + functional + informative done right

Axe-core — /w/axe (needs public URL, headless render)

FixtureExpectedRule
good.htmlPASSNo violations
missing-lang-bad.htmlFAILhtml-has-lang
image-alt-bad.htmlFAILimage-alt
button-name-bad.htmlFAILbutton-name
contrast-bad.htmlFAILcolor-contrast
duplicate-id-bad.htmlFAILduplicate-id
empty-heading-bad.htmlFAILempty-heading
input-label-bad.htmlFAILlabel
all-bad.htmlFAILMany rules at once

Accessibility statement — /w/statement/find + /w/statement/parse

The discovery worker crawls a homepage for a statement link; the link below gives it a fully parseable page (conformance status, dates, evaluation method, known issues, technologies, contact, enforcement).

Page discovery — /w/pages

This index links every fixture above, so the AI page-discovery worker can use it as a homepage to crawl and rank candidate pages.