How to Run axe-core Accessibility Tests in Browser Automation
Browserbase Skills provides a deterministic, script-driven way to run axe-core accessibility audits against any web page using the browse CLI.
Automated accessibility testing ensures your web applications meet WCAG standards before they reach production. The browserbase/skills repository offers a deterministic approach to run axe-core accessibility tests in browser automation through command-line driven Chromium instances, producing consistent, machine-readable results ideal for CI/CD pipelines.
The Core Workflow
The browse CLI implements a four-step workflow to execute axe-core audits. Because browse eval does not support top-level await, the process splits library injection and execution into discrete commands with explicit synchronization.
1. Open the Target Page
Navigate to your application and ensure the DOM is fully loaded before injecting testing libraries.
browse open "https://example.com"
browse wait load
2. Inject the axe-core Library
Dynamically append a script tag to load the axe-core bundle from CDN. This approach avoids bundling dependencies and always uses the specified version.
browse eval "const s=document.createElement('script'); \
s.src='https://cdnjs.cloudflare.com/ajax/libs/axe-core/4.10.2/axe.min.js'; \
document.head.appendChild(s); 'loading'"
3. Allow Initialization Time
Wait for the external script to download and initialize. A 3000ms timeout typically ensures axe is available in the global scope.
browse wait timeout 3000
4. Execute the Audit
Run axe.run() inside the page context and transform the results into a concise JSON structure containing only essential fields.
browse eval "axe.run().then(r=>JSON.stringify({\
violations:r.violations.map(v=>({id:v.id,impact:v.impact,description:v.description,nodes:v.nodes.length,help:v.helpUrl})),\
passes:r.passes.length,\
incomplete:r.incomplete.length}))"
Interpreting the Results
The CLI returns a JSON payload that separates actionable violations from passed rules. The structure includes:
violations– Array of objects containingid,impactlevel (critical,serious,moderate,minor),description, node count, and help URLpasses– Integer count of rules that passedincomplete– Count of rules requiring manual verification
Example output:
{
"violations": [
{"id":"color-contrast","impact":"critical","description":"Elements must have sufficient color contrast","nodes":3,"help":"https://dequeuniversity.com/rules/axe/4.10/color-contrast"},
{"id":"label","impact":"critical","description":"Form elements must have a label","nodes":1,"help":"https://dequeuniversity.com/rules/axe/4.10/label"}
],
"passes": 33,
"incomplete": 0
}
CI/CD Integration Patterns
Parse the JSON output to enforce quality gates in automated pipelines. The deterministic nature of this approach ensures identical results across runs.
RESULT=$(browse open "https://example.com" && \
browse wait load && \
browse eval "const s=document.createElement('script');s.src='https://cdnjs.cloudflare.com/ajax/libs/axe-core/4.10.2/axe.min.js';document.head.appendChild(s);'loading'" && \
browse wait timeout 3000 && \
browse eval "axe.run().then(r=>JSON.stringify({violations:r.violations.map(v=>({id:v.id,impact:v.impact})),passes:r.passes.length}))")
CRITICAL=$(echo "$RESULT" | jq '[.violations[] | select(.impact=="critical")] | length')
if [ "$CRITICAL" -gt 0 ]; then
echo "❌ Accessibility audit failed – $CRITICAL critical violations"
exit 1
fi
echo "✅ No critical accessibility issues"
Combining with Keyboard Navigation Tests
Integrate axe-core audits with焦点管理 tests to verify both automated rules and interactive navigation patterns. After running the audit, simulate keyboard interaction to validate focus indicators.
# Run axe audit (steps above)
browse press Tab
browse eval "JSON.stringify({\
tag:document.activeElement?.tagName,\
text:document.activeElement?.textContent?.trim().slice(0,40),\
role:document.activeElement?.getAttribute('role'),\
ariaLabel:document.activeElement?.getAttribute('aria-label'),\
hasFocus: (()=>{const s=window.getComputedStyle(document.activeElement);return s.outlineStyle!=='none'||s.boxShadow!=='none';})()})"
This technique, documented in skills/ui-test/references/browser-recipes.md (lines 94–108), combines automated axe-core validation with manual interaction verification.
Source Reference Files
According to the browserbase/skills source code, these files contain the canonical implementation details:
skills/ui-test/references/browser-recipes.md– Full two-step axe-core recipe with interpretation guidelinesskills/ui-test/EXAMPLES.md– Runnablebrowse evalstrings and practical automation examplesskills/ui-test/README.md– Overview of deterministic accessibility checks and why axe-core is the preferred testing engineskills/ui-test/references/parallel-testing.md– Integration patterns for running axe-core within larger test suites and failure reporting mechanisms
Summary
- The
browseCLI enables deterministic axe-core accessibility testing by driving Chromium instances with script-injection commands - Four-step process: Open page, inject CDN script (
https://cdnjs.cloudflare.com/ajax/libs/axe-core/4.10.2/axe.min.js), wait 3000ms, executeaxe.run() - Results return as JSON containing
violations,passes, andincompletecounts for downstream processing - Ideal for CI pipelines due to consistent, repeatable output that supports threshold enforcement (e.g., zero critical violations)
- Can combine with keyboard navigation tests for comprehensive accessibility coverage as shown in the repository's browser recipes
Frequently Asked Questions
Why does the script injection require an explicit timeout?
The 3000ms timeout specified in browse wait timeout 3000 ensures the axe-core library loads from the CDN and initializes in the global scope before axe.run() executes. Because browse eval cannot use top-level await, the workflow cannot wait for the script's onload event, making the fixed delay necessary for reliable execution.
Can I run axe-core tests against local development servers?
Yes. The browse CLI connects to both remote URLs and local development servers. Use browse open "http://localhost:3000" to audit applications running on your machine, making this approach suitable for pre-commit hooks and local development workflows.
What does the incomplete field indicate in the results?
The incomplete count represents accessibility rules that axe-core could not definitively evaluate due to missing context or ambiguous element usage. These require manual review, unlike violations which are automatically detectable failures. According to skills/ui-test/references/browser-recipes.md, you should inspect incomplete results when they appear, as they often indicate complex interactive components needing human verification.
Is this method compatible with headless CI environments?
Yes. The browserbase/skills implementation is specifically designed for automated pipelines. The deterministic JSON output and exit-code-friendly structure allow you to parse results with tools like jq and fail builds based on impact thresholds. The repository's skills/ui-test/references/parallel-testing.md demonstrates how to integrate these checks into parallel test execution environments.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →