> ## Documentation Index
> Fetch the complete documentation index at: https://docs.qawolf.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Measure web accessibility with axe-core

> Inject axe-core into a Playwright page to catch WCAG violations and gate releases on accessibility quality.

Use axe-core or Lighthouse to assert that pages meet accessibility standards. Both tools are available in QA Wolf web flows — axe-core for precise violation gating, Lighthouse for scores and shareable reports.

<Info>
  This recipe covers accessibility spot-checking using axe-core and Lighthouse. For operationalized a11y monitoring — scheduled runs, trend tracking, aggregated reports, and stakeholder dashboards — talk to your QA Wolf team about full-service accessibility testing.
</Info>

## Examples

**Gate a release on axe-core violations**

```typescript theme={null}
await page.addScriptTag({
  url: "https://unpkg.com/axe-core@4.8.2/axe.min.js",
});

const violations = await page.evaluate(async () => {
  const { violations } = await window.axe.run();
  return violations;
});

const critical = violations.filter((x) => x.impact === "critical");
const serious  = violations.filter((x) => x.impact === "serious");

expect(critical.length).toBe(0);
expect(serious.length).toBe(0);
```

**Generate a Lighthouse accessibility report**

```typescript theme={null}
const { lhr } = await playAudit({
  page,
  thresholds: { accessibility: 90 },
  reports: {
    formats: { html: true, json: true },
    directory: `${process.env.TEAM_STORAGE_DIR}/lighthouse`,
    name: `a11y-${Date.now()}`,
  },
  config: {
    extends: "lighthouse:default",
    settings: { onlyCategories: ["accessibility"] },
  },
});

const a11yScore = Math.round(lhr.categories.accessibility.score * 100);
console.log(`Accessibility score: ${a11yScore}`);
```

<Warning>
  Lighthouse scores accessibility against its own model, which does not map 1:1 to WCAG conformance levels. Use it as a directional score and audit artifact — not as a hard compliance gate.
</Warning>

## When to use

* Your app has pages that must meet WCAG standards and you need to catch regressions before they reach production.
* Your team needs a release gate that fails on critical or serious WCAG violations.
* Your team needs a shareable accessibility report for stakeholders or compliance purposes.
* Your team wants to establish a baseline score for a page and track it over time.

## Choosing the right approach

|                     | Axe-core                                    | Lighthouse                                  |
| ------------------- | ------------------------------------------- | ------------------------------------------- |
| **Best for**        | CI checks, violation counts, release gating | Scores, formal reports, stakeholder sharing |
| **Output**          | Violation list by severity                  | Accessibility score + full report           |
| **Use as a gate**   | Yes — throw on critical / serious           | Not recommended                             |
| **Report artifact** | No (console / logs)                         | Yes — HTML, JSON, PDF                       |

<Note>
  These two approaches complement each other. Axe-core is precise and gateable; Lighthouse is broad and reportable. For the most complete picture, use both.
</Note>

## Full sample test

```typescript theme={null}
import { flow, expect } from "@qawolf/flows/web";

export default flow(
  "Accessibility",
  { target: "Web - Chrome", launch: true },
  async ({ page, test }) => {
    await test("assert no accessibility violations", async () => {
      // Arrange
      await page.goto("https://your-app.com");

      // Act
      await page.addScriptTag({
        url: "https://unpkg.com/axe-core@4.8.2/axe.min.js",
      });

      const violations = await page.evaluate(async () => {
        const { violations } = await window.axe.run();
        return violations;
      });

      // Assert
      const critical = violations.filter((x) => x.impact === "critical");
      const serious  = violations.filter((x) => x.impact === "serious");
      const moderate = violations.filter((x) => x.impact === "moderate");
      const minor    = violations.filter((x) => x.impact === "minor");

      expect(critical.length).toBe(0);
      expect(serious.length).toBe(0);
      expect(moderate.length).toBe(0);
      expect(minor.length).toBe(0);
    });
  },
);
```

<Note>
  The full sample gates on all violation levels. Adjust the threshold to match your policy — some teams only gate on `critical` and `serious`, particularly when first introducing accessibility testing.
</Note>
