# How to Run axe-core Accessibility Tests in Browser Automation

> Effortlessly run axe-core accessibility tests in browser automation with Browserbase Skills. Automate audits for any web page using the browse CLI for deterministic results.

- Repository: [browserbase/skills](https://github.com/browserbase/skills)
- Tags: how-to-guide
- Published: 2026-05-01

---

**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.

```bash
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.

```bash
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.

```bash
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.

```bash
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 containing `id`, `impact` level (`critical`, `serious`, `moderate`, `minor`), `description`, node count, and help URL
- **`passes`** – Integer count of rules that passed
- **`incomplete`** – Count of rules requiring manual verification

Example output:

```json
{
  "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.

```bash
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.

```bash

# 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`](https://github.com/browserbase/skills/blob/main/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`](https://github.com/browserbase/skills/blob/main/skills/ui-test/references/browser-recipes.md)** – Full two-step axe-core recipe with interpretation guidelines
- **[`skills/ui-test/EXAMPLES.md`](https://github.com/browserbase/skills/blob/main/skills/ui-test/EXAMPLES.md)** – Runnable `browse eval` strings and practical automation examples
- **[`skills/ui-test/README.md`](https://github.com/browserbase/skills/blob/main/skills/ui-test/README.md)** – Overview of deterministic accessibility checks and why axe-core is the preferred testing engine
- **[`skills/ui-test/references/parallel-testing.md`](https://github.com/browserbase/skills/blob/main/skills/ui-test/references/parallel-testing.md)** – Integration patterns for running axe-core within larger test suites and failure reporting mechanisms

## Summary

- The `browse` CLI 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, execute `axe.run()`
- Results return as JSON containing `violations`, `passes`, and `incomplete` counts 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`](https://github.com/browserbase/skills/blob/main/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`](https://github.com/browserbase/skills/blob/main/skills/ui-test/references/parallel-testing.md) demonstrates how to integrate these checks into parallel test execution environments.