playwright-a11y-runner
v1.3.0
Published
Unified accessibility testing for Playwright - plug-and-play Axe Core integration with zero test code changes
Maintainers
Readme
Playwright A11y Runner
A simple plug-and-play accessibility testing solution for Playwright that automatically scans your web pages for accessibility issues using axe-core.
Table of Contents
- What is this?
- Why This Package? (axe-core vs this)
- How it Works
- Installation
- Quick Start
- Configuration Options
- Usage Methods
- Environment Variables
- WCAG Standards
- Understanding Results
- Examples
- Troubleshooting
What is this?
This package adds automatic accessibility testing to your Playwright tests.
When you run your tests, it will:
- Scan each page for accessibility problems
- Report issues in the console
- Optionally fail tests if issues are found
Why use it?
| Without this package | With this package | |---------------------|-------------------| | Manual accessibility testing | Automatic scanning | | Issues found late in development | Issues caught during testing | | Requires accessibility expertise | Built-in WCAG standards | | Extra code needed | Zero code changes |
Why This Package?
You might ask: "Why do I need this package when axe-core and @axe-core/playwright already exist?"
Great question! Here's the answer:
The Problem with Using axe-core Directly
When you use @axe-core/playwright directly, every test needs boilerplate code:
// ❌ Using @axe-core/playwright directly - LOTS OF CODE!
const { test, expect } = require('@playwright/test');
const AxeBuilder = require('@axe-core/playwright').default;
test('homepage', async ({ page }) => {
await page.goto('https://example.com');
// You have to add ALL of this to EVERY test:
const accessibilityScanResults = await new AxeBuilder({ page })
.withTags(['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa'])
.analyze();
expect(accessibilityScanResults.violations).toEqual([]);
});
test('about page', async ({ page }) => {
await page.goto('https://example.com/about');
// Same boilerplate AGAIN:
const accessibilityScanResults = await new AxeBuilder({ page })
.withTags(['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa'])
.analyze();
expect(accessibilityScanResults.violations).toEqual([]);
});
// Repeat for EVERY test... 😫The Solution: This Package
// ✅ Using this package - ZERO EXTRA CODE!
const { test, expect } = require('@org/playwright-a11y');
test('homepage', async ({ page }) => {
await page.goto('https://example.com');
// Accessibility scan happens automatically! ✨
});
test('about page', async ({ page }) => {
await page.goto('https://example.com/about');
// Accessibility scan happens automatically! ✨
});Side-by-Side Comparison
| Aspect | axe-core directly | This package | |--------|-------------------|--------------| | Setup per test | 5-10 lines of code | 0 lines | | Configuration | Manual in each test | Central config file | | WCAG standards | Must specify tags manually | Pre-configured | | Existing tests | Rewrite every test | Change 1 import line | | Consistency | Varies by developer | Always consistent | | Forgot to add scan? | No accessibility check | Always scans | | Learning curve | Learn axe-core API | Just works |
Visual Comparison
┌─────────────────────────────────────────────────────────────────┐
│ USING AXE-CORE DIRECTLY │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Test 1 Test 2 Test 3 Test 4 │
│ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │
│ │ Your │ │ Your │ │ Your │ │ Your │ │
│ │ Code │ │ Code │ │ Code │ │ Code │ │
│ ├──────┤ ├──────┤ ├──────┤ ├──────┤ │
│ │ Axe │ │ Axe │ │ Axe │ │ Axe │ │
│ │Setup │ │Setup │ │Setup │ │Setup │ │
│ │ Code │ │ Code │ │ Code │ │ Code │ │
│ └──────┘ └──────┘ └──────┘ └──────┘ │
│ │
│ ⚠️ Boilerplate repeated in EVERY test │
│ ⚠️ Easy to forget │
│ ⚠️ Inconsistent configuration │
│ │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ USING THIS PACKAGE │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────┐ │
│ │ Central Config │ │
│ │ (a11y.config.js) │ │
│ └──────────────┬──────────────┘ │
│ │ │
│ ┌───────────────────┼───────────────────┐ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Test 1 │ │ Test 2 │ │ Test 3 │ │
│ │ (just │ │ (just │ │ (just │ │
│ │ your │ │ your │ │ your │ │
│ │ code) │ │ code) │ │ code) │ │
│ └──────────┘ └──────────┘ └──────────┘ │
│ │ │
│ ┌──────────────┴──────────────┐ │
│ │ Automatic A11y Scanning │ │
│ │ (handled by package) │ │
│ └─────────────────────────────┘ │
│ │
│ ✅ Zero boilerplate │
│ ✅ Never forgotten │
│ ✅ Always consistent │
│ │
└─────────────────────────────────────────────────────────────────┘Key Benefits Over Raw axe-core
| Benefit | Description | |---------|-------------| | 🚀 Zero Config | Works out of the box with sensible defaults | | 🔄 Automatic | Scans run without adding any code to tests | | 📁 Central Config | One config file controls all tests | | 🎯 Consistent | Same scanning rules across entire project | | ⚡ Instant Setup | Change one import, get full coverage | | 🛡️ Never Forget | Can't accidentally skip accessibility checks | | 📊 Better Output | Formatted, readable console output | | 🔧 Environment Control | Enable/disable via environment variables | | 🎛️ Flexible | Manual scanning when you need control |
When to Use What
| Scenario | Recommendation | |----------|----------------| | New project with many tests | ✅ Use this package | | Existing test suite | ✅ Use this package (just change import) | | Need automatic scanning | ✅ Use this package | | Want central configuration | ✅ Use this package | | Need custom axe-core plugins | ⚠️ Use axe-core directly | | One-off script | Either works | | Complex custom scanning logic | ⚠️ Use axe-core directly |
Summary
This package = axe-core + automation + configuration + convenience
We use axe-core under the hood. We just make it effortless to use in Playwright tests.
┌────────────────────────────────────────┐
│ THIS PACKAGE │
│ ┌──────────────────────────────────┐ │
│ │ Your Tests │ │
│ │ ┌────────────────────────────┐ │ │
│ │ │ Playwright Fixtures │ │ │
│ │ │ ┌──────────────────────┐ │ │ │
│ │ │ │ @axe-core/playwright│ │ │ │
│ │ │ │ ┌────────────────┐ │ │ │ │
│ │ │ │ │ axe-core │ │ │ │ │
│ │ │ │ └────────────────┘ │ │ │ │
│ │ │ └──────────────────────┘ │ │ │
│ │ └────────────────────────────┘ │ │
│ └──────────────────────────────────┘ │
└────────────────────────────────────────┘
We wrap axe-core to make YOUR life easier.How it Works
┌─────────────────────────────────────────────────────────────────┐
│ YOUR TEST RUNS │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ TEST NAVIGATES TO PAGE │
│ (e.g., page.goto('/home')) │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ YOUR TEST COMPLETES │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ AUTOMATIC ACCESSIBILITY SCAN │
│ │
│ ┌────────────────┐ ┌────────────────┐ ┌───────────────┐ │
│ │ axe-core │ => │ Analyze DOM │ => │ Report Issues │ │
│ │ injected │ │ for issues │ │ to console │ │
│ └────────────────┘ └────────────────┘ └───────────────┘ │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ RESULTS IN PLAYWRIGHT REPORT │
└─────────────────────────────────────────────────────────────────┘Simple Explanation
- You write tests - Just normal Playwright tests
- Import our test - Use our
testinstead of Playwright's - Tests run normally - Your tests work exactly the same
- We scan automatically - After each test, we check for accessibility issues
- See results - Issues appear in console and Playwright's report
Installation
Step 1: Install the package
npm install @org/playwright-a11yStep 2: Install peer dependencies (if not already installed)
npm install @playwright/testWhat gets installed?
| Package | Purpose |
|---------|---------|
| @org/playwright-a11y | This package |
| @axe-core/playwright | Accessibility scanning engine |
| axe-core | Accessibility rules database |
Quick Start
Use the CLI
Run your tests with the accessibility CLI wrapper:
npx playwright-a11y testThis runs Playwright with accessibility testing enabled.
WCAG Standards
WCAG (Web Content Accessibility Guidelines) are international standards for web accessibility.
Available Standards
| Standard | Description | Best For |
|----------|-------------|----------|
| wcag2a | WCAG 2.0 Level A | Minimum compliance |
| wcag2aa | WCAG 2.0 Level AA | Legal compliance (most common) |
| wcag21a | WCAG 2.1 Level A | Mobile accessibility basics |
| wcag21aa | WCAG 2.1 Level AA | Recommended - Modern standard |
| wcag22aa | WCAG 2.2 Level AA | Latest standard |
| best-practice | Best practices | Beyond WCAG requirements |
| all | All rules | Maximum coverage |
Choosing a Standard
┌─────────────────────────────────────────────────────────────────┐
│ WCAG COMPLIANCE LEVELS │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Level A ──────────> Level AA ──────────> Level AAA │
│ (Minimum) (Standard) (Highest) │
│ │
│ • Basic • Required by • Ideal but │
│ accessibility most laws not always │
│ • Must have • Industry possible │
│ standard │
│ │
└─────────────────────────────────────────────────────────────────┘
RECOMMENDATION: Use 'wcag21aa' for most projectsUnderstanding Results
Severity Levels
Issues are categorized by how much they impact users:
| Level | Icon | Impact | Example | |-------|------|--------|---------| | Critical | 🔴 | Blocks users completely | Missing form labels | | Serious | 🟠 | Major difficulty | Low color contrast | | Moderate | 🟡 | Some difficulty | Missing skip links | | Minor | 🔵 | Slight inconvenience | Redundant alt text |
Console Output Example
📋 Accessibility scan for: homepage loads correctly
URL: https://example.com/
✗ Found 3 accessibility violation(s):
1. 🔴 [CRITICAL] image-alt
Images must have alternate text
Help: https://dequeuniversity.com/rules/axe/4.8/image-alt
Affected elements (2):
- img.hero-image
- img.product-photo
2. 🟠 [SERIOUS] color-contrast
Elements must have sufficient color contrast
Help: https://dequeuniversity.com/rules/axe/4.8/color-contrast
Affected elements (1):
- p.disclaimer
3. 🟡 [MODERATE] region
All page content should be contained by landmarks
Help: https://dequeuniversity.com/rules/axe/4.8/region
Affected elements (1):
- div.floating-bannerWhen No Issues Found
📋 Accessibility scan for: contact page
URL: https://example.com/contact
✓ No accessibility violations foundTroubleshooting
Common Issues
| Problem | Cause | Solution |
|---------|-------|----------|
| "Cannot find module" | Package not installed | Run npm install @org/playwright-a11y |
| Scans not running | Disabled in config | Check enabled: true in config |
| Too many violations | Scanning third-party content | Add exclusions to scope.exclude |
| Tests too slow | Scanning every page | Use scanTiming: 'manual' |
| False positives | Rules too strict | Add to rules.exclude |
File Structure
your-project/
├── node_modules/
│ └── @org/playwright-a11y/
│ ├── bin/
│ │ └── playwright-a11y.js # CLI entry point
│ ├── src/
│ │ ├── index.js # Main exports
│ │ ├── axe-runner.js # Axe scanning logic
│ │ ├── cli.js # CLI implementation
│ │ ├── config.js # Configuration handling
│ │ └── fixtures.js # Playwright fixtures
│ ├── package.json
│ └── README.md
├── tests/
│ └── example.spec.js # Your tests
├── a11y.config.js # Optional config file
└── playwright.config.js # Playwright configQuick Reference Card
Imports
const { test, expect } = require('@org/playwright-a11y'); // Basic
const { withA11y } = require('@org/playwright-a11y'); // Wrapper
const { scanPage } = require('@org/playwright-a11y'); // StandaloneFixtures Available in Tests
| Fixture | Purpose |
|---------|---------|
| page | Standard Playwright page (with auto-scan) |
| a11yConfig | Current accessibility configuration |
| a11yResults | Array of scan results |
| runA11yScan | Function to trigger manual scan |
| checkA11y | Function to check specific elements |
CLI Commands
npx playwright-a11y test # Run all tests
npx playwright-a11y test tests/home.spec.js # Run specific file
npx playwright-a11y --help # Show help
npx playwright-a11y --version # Show versionNeed Help?
- Check the troubleshooting section
- Review axe-core rules documentation
- Read WCAG guidelines
