Accessibility Testing with Selenium WebDriver & Axe Core
This skill enables automated accessibility analysis within the Selenium WebDriver framework using the axe-core engine to detect WCAG violations and best practice issues directly in the browser.
Activation: This skill is triggered when you need to validate WCAG compliance, scan for accessibility violations, test keyboard navigation, audit ARIA semantics, or generate a11y reports.
First Questions to Ask
- What app URL(s) or user flows are in scope (and what is explicitly out of scope)?
- Is there an existing Selenium setup and how is CI run?
- Which standard is the target (WCAG 2.2 AA by default), and are there org-specific policies?
- Which pages/components are highest risk (auth, checkout, forms, modals, navigation)?
- Are there known constraints (legacy markup, third-party widgets) that require exceptions?
Prerequisites
| Component |
Version |
Purpose |
| Java JDK |
21+ |
Runtime with modern features |
| Maven |
3.9+ |
Dependency management |
| Selenium WebDriver |
4.x |
Browser automation |
| axe-core-selenium |
4.10+ |
Deque axe-core integration |
| JUnit 5 |
5.10+ |
Test framework |
| AssertJ |
3.x |
Fluent assertions for readable failures |
| Allure |
2.x |
Reporting with a11y violation attachments |
Note: Use com.deque.html.axe-core:selenium Maven dependency for axe integration.
Target: WCAG 2.2 AA (wcag2a, wcag2aa, wcag21a, wcag21aa, wcag22a, wcag22aa). See WCAG 2.2 spec.
Do NOT Use For
- Playwright/TypeScript accessibility testing (use
a11y-playwright-testing).
- Authoring Selenium functional UI tests (use
webapp-selenium-testing).
- Full conformance sign-off — automated axe scans catch ~30-50% of issues; manual audit + assistive-tech testing is still required.
Axe-Core Tools Reference
AxeBuilder Configuration
| Method |
Purpose |
Example |
new AxeBuilder() |
Create scanner instance |
Entry point |
.withTags(List<String>) |
Filter by WCAG tags |
wcag2aa, wcag21aa, wcag22aa |
.include(String) |
Scan specific selector |
#main-content |
.exclude(String) |
Skip selector from scan |
.third-party-widget |
.disableRules(List<String>) |
Disable specific rules |
color-contrast |
.withRules(List<String>) |
Run only specific rules |
label, button-name |
.analyze(WebDriver) |
Execute the scan |
Returns Results |
Results Object
| Method |
Returns |
Purpose |
getViolations() |
List<Rule> |
Rules that failed |
getPasses() |
List<Rule> |
Rules that passed |
getIncomplete() |
List<Rule> |
Rules needing manual review |
getInapplicable() |
List<Rule> |
Rules not applicable to page |
violationFree() |
boolean |
True if no violations |
Violation Impact Levels
| Impact |
Severity |
CI Action |
| Critical |
Blocks users completely |
Always fail build |
| Serious |
Significant barrier |
Always fail build |
| Moderate |
Some difficulty |
Warn or fail |
| Minor |
Inconvenience |
Log for review |
Step-by-Step Workflows
Workflow 1: Add A11y Scan to Existing Test
Add dependency to pom.xml
<dependency>
<groupId>com.deque.html.axe-core</groupId>
<artifactId>selenium</artifactId>
<version>4.10.0</version>
</dependency>
Create AccessibilityHelper utility
- See Axe Patterns: Helper Scanning
Add scan after page loads
driver.get("https://example.com");
waitForPageReady();
AccessibilityHelper.verifyPageAccessibility(driver);
Run and review violations
mvn test -Dtest=A11yTest
Workflow 2: Test Specific Component
Navigate to page with component visible
Trigger component state (open modal, show dropdown)
Scan only the component
Results results = new AxeBuilder()
.withTags(List.of("wcag2a", "wcag2aa", "wcag22aa"))
.include("#login-modal")
.analyze(driver);
Assert and log
Workflow 3: Keyboard Navigation Audit
- Identify all interactive elements
- Tab through the page programmatically
element.sendKeys(Keys.TAB);
WebElement focused = driver.switchTo().activeElement();
- Verify focus order is logical
- Test Escape closes modals
- Verify no keyboard traps
Workflow 4: CI Integration
Configure headless browser
mvn test -Dheadless=true -Dgroups=a11y
Set zero-tolerance for Critical/Serious
long criticalCount = violations.stream()
.filter(v -> List.of("critical", "serious").contains(v.getImpact()))
.count();
assertThat(criticalCount).isZero();
Generate JSON report for tracking
Code Patterns
See references/code-patterns.md for full AxeBuilder scan patterns, violation logging, JUnit 5 integration, and CI/CD YAML.
Key snippet:
Results results = new AxeBuilder()
.withTags(List.of("wcag2a", "wcag2aa", "wcag21a", "wcag21aa", "wcag22a", "wcag22aa"))
.analyze(driver);
assertThat(results.violationFree()).as("A11y violations").isTrue();
Troubleshooting
| Problem |
Cause |
Solution |
| Axe returns empty results |
Page not fully loaded |
Add explicit wait for page ready state |
| False positives on contrast |
Dynamic themes |
Test both light and dark modes |
| Violations in third-party widgets |
Cannot modify vendor code |
Use .exclude() with documented ticket |
| Incomplete rules |
Requires manual review |
Log for manual audit, don't auto-fail |
| Different results between runs |
Async content loading |
Ensure deterministic page state before scan |
| CI fails but local passes |
Different viewport/browser |
Use same headless config as CI |
Triage by POUR Principles
| Principle |
Focus Areas |
Common Violations |
| Perceivable |
Text alternatives, captions, contrast, structure |
Missing alt text, low contrast, missing labels |
| Operable |
Keyboard access, focus order, bypass blocks |
Keyboard traps, no skip link, focus not visible |
| Understandable |
Labels, predictable behavior, error handling |
Unclear instructions, unexpected changes |
| Robust |
Valid HTML, ARIA, name/role/value |
Invalid ARIA, duplicate IDs, missing roles |
Running Tests
Maven Commands
| Command |
Purpose |
mvn test -Dgroups=a11y |
Run all accessibility tests |
mvn test -Dtest=A11yTest |
Run specific test class |
mvn test -Dheadless=true |
Run headless (CI mode) |
mvn allure:serve |
View Allure report with violations |
CI/CD Integration
- name: Run Accessibility Tests
run: mvn test -Dgroups=a11y -Dheadless=true
- name: Upload A11y Report
uses: actions/upload-artifact@v3
with:
name: a11y-report
path: target/a11y-results/
Red Flags
- Treating a clean axe scan as full WCAG conformance — automation covers only ~30-50% of criteria.
- Globally disabling rules instead of scoped
.exclude() with a documented remediation ticket.
- Scanning before the page is fully loaded — async content yields false "0 violations".
- Failing the build on
incomplete rules — those need manual review, not automatic failure.
References
- Axe Patterns: Helper Scanning - Maven setup and AccessibilityHelper scanning methods
- Axe Patterns: Helper Processing - AccessibilityHelper results, filtering, logging, and reporting
- Axe Patterns: Tags & Tests - Common axe tags reference and test patterns
- Axe Patterns: Keyboard & CI/CD - Keyboard navigation testing and CI/CD integration
- Axe-Core API Reference - Full AxeBuilder config, Results object, and impact levels
- WCAG 2.2 AA Checklist: Perceivable & Operable - Manual audit checklist, POUR principles 1-2
- WCAG 2.2 AA Checklist: Understandable & Robust - Manual audit checklist, POUR principles 3-4 and assistive tech
- WCAG 2.2 AA Checklist: Additions & Exceptions - WCAG 2.2 additions, exception template, W3C references
- Deque Axe Rules - Rule descriptions
- W3C WCAG 2.2 - Official specification
- WAI-ARIA Practices - Widget patterns
Verification
1---2name: accessibility-selenium-testing3description: Accessibility testing toolkit using Selenium WebDriver 4+ with Java 21+ and axe-core engine. Use when asked to validate WCAG 2.2 AA compliance, scan pages or components for a11y violations, test keyboard navigation, audit color contrast, check ARIA semantics, generate accessibility reports, filter axe rules, debug screen reader issues, or implement POUR principles (perceivable, operable, understandable, robust).4license: Complete terms in LICENSE.txt5---6
7# Accessibility Testing with Selenium WebDriver & Axe Core
8
9This skill enables automated accessibility analysis within the Selenium WebDriver framework using the **axe-core** engine to detect WCAG violations and best practice issues directly in the browser.
10
11> **Activation:** This skill is triggered when you need to validate WCAG compliance, scan for accessibility violations, test keyboard navigation, audit ARIA semantics, or generate a11y reports.
12
13## First Questions to Ask
14
15- What app URL(s) or user flows are in scope (and what is explicitly out of scope)?
16- Is there an existing Selenium setup and how is CI run?
17- Which standard is the target (WCAG 2.2 AA by default), and are there org-specific policies?
18- Which pages/components are highest risk (auth, checkout, forms, modals, navigation)?
19- Are there known constraints (legacy markup, third-party widgets) that require exceptions?
20
21## Prerequisites
22
23| Component | Version | Purpose |
24|-----------|---------|---------|
25| Java JDK | 21+ | Runtime with modern features |
26| Maven | 3.9+ | Dependency management |
27| Selenium WebDriver | 4.x | Browser automation |
28| axe-core-selenium | 4.10+ | Deque axe-core integration |
29| JUnit 5 | 5.10+ | Test framework |
30| AssertJ | 3.x | Fluent assertions for readable failures |
31| Allure | 2.x | Reporting with a11y violation attachments |
32
33> **Note:** Use `com.deque.html.axe-core:selenium` Maven dependency for axe integration.
34
35---
36
37> **Target:** WCAG 2.2 AA (`wcag2a`, `wcag2aa`, `wcag21a`, `wcag21aa`, `wcag22a`, `wcag22aa`). See [WCAG 2.2 spec](https://www.w3.org/TR/WCAG22/).
38
39### Do NOT Use For
40
41- Playwright/TypeScript accessibility testing (use `a11y-playwright-testing`).
42- Authoring Selenium functional UI tests (use `webapp-selenium-testing`).
43- Full conformance sign-off — automated axe scans catch ~30-50% of issues; manual audit + assistive-tech testing is still required.
44
45## Axe-Core Tools Reference
46
47### AxeBuilder Configuration
48
49| Method | Purpose | Example |
50|--------|---------|---------|
51| `new AxeBuilder()` | Create scanner instance | Entry point |
52| `.withTags(List<String>)` | Filter by WCAG tags | `wcag2aa`, `wcag21aa`, `wcag22aa` |
53| `.include(String)` | Scan specific selector | `#main-content` |
54| `.exclude(String)` | Skip selector from scan | `.third-party-widget` |
55| `.disableRules(List<String>)` | Disable specific rules | `color-contrast` |
56| `.withRules(List<String>)` | Run only specific rules | `label`, `button-name` |
57| `.analyze(WebDriver)` | Execute the scan | Returns `Results` |
58
59### Results Object
60
61| Method | Returns | Purpose |
62|--------|---------|---------|
63| `getViolations()` | `List<Rule>` | Rules that failed |
64| `getPasses()` | `List<Rule>` | Rules that passed |
65| `getIncomplete()` | `List<Rule>` | Rules needing manual review |
66| `getInapplicable()` | `List<Rule>` | Rules not applicable to page |
67| `violationFree()` | `boolean` | True if no violations |
68
69### Violation Impact Levels
70
71| Impact | Severity | CI Action |
72|--------|----------|-----------|
73| **Critical** | Blocks users completely | Always fail build |
74| **Serious** | Significant barrier | Always fail build |
75| **Moderate** | Some difficulty | Warn or fail |
76| **Minor** | Inconvenience | Log for review |
77
78---
79
80## Step-by-Step Workflows
81
82### Workflow 1: Add A11y Scan to Existing Test
83
841. **Add dependency to pom.xml**
85 ```xml
86 <dependency>
87 <groupId>com.deque.html.axe-core</groupId>
88 <artifactId>selenium</artifactId>
89 <version>4.10.0</version>
90 </dependency>
91 ```
92
932. **Create AccessibilityHelper utility**
94 - See [Axe Patterns: Helper Scanning](references/axe-patterns-helper-scanning.md)
95
963. **Add scan after page loads**
97 ```java
98 driver.get("https://example.com");
99 waitForPageReady();
100 AccessibilityHelper.verifyPageAccessibility(driver);
101 ```
102
1034. **Run and review violations**
104 ```bash
105 mvn test -Dtest=A11yTest
106 ```
107
108### Workflow 2: Test Specific Component
109
1101. **Navigate to page with component visible**
1112. **Trigger component state** (open modal, show dropdown)
1123. **Scan only the component**
113 ```java
114 Results results = new AxeBuilder()
115 .withTags(List.of("wcag2a", "wcag2aa", "wcag22aa"))
116 .include("#login-modal")
117 .analyze(driver);
118 ```
119
1204. **Assert and log**
121
122### Workflow 3: Keyboard Navigation Audit
123
1241. **Identify all interactive elements**
1252. **Tab through the page programmatically**
126 ```java
127 element.sendKeys(Keys.TAB);
128 WebElement focused = driver.switchTo().activeElement();
129 ```
1303. **Verify focus order is logical**
1314. **Test Escape closes modals**
1325. **Verify no keyboard traps**
133
134### Workflow 4: CI Integration
135
1361. **Configure headless browser**
137 ```bash
138 mvn test -Dheadless=true -Dgroups=a11y
139 ```
140
1412. **Set zero-tolerance for Critical/Serious**
142 ```java
143 long criticalCount = violations.stream()
144 .filter(v -> List.of("critical", "serious").contains(v.getImpact()))
145 .count();
146 assertThat(criticalCount).isZero();
147 ```
148
1493. **Generate JSON report for tracking**
150
151---
152
153## Code Patterns
154
155See [`references/code-patterns.md`](references/code-patterns.md) for full AxeBuilder scan patterns, violation logging, JUnit 5 integration, and CI/CD YAML.
156
157Key snippet:
158
159```java
160Results results = new AxeBuilder()
161 .withTags(List.of("wcag2a", "wcag2aa", "wcag21a", "wcag21aa", "wcag22a", "wcag22aa"))
162 .analyze(driver);
163assertThat(results.violationFree()).as("A11y violations").isTrue();
164```
165
166## Troubleshooting
167
168| Problem | Cause | Solution |
169|---------|-------|----------|
170| Axe returns empty results | Page not fully loaded | Add explicit wait for page ready state |
171| False positives on contrast | Dynamic themes | Test both light and dark modes |
172| Violations in third-party widgets | Cannot modify vendor code | Use `.exclude()` with documented ticket |
173| Incomplete rules | Requires manual review | Log for manual audit, don't auto-fail |
174| Different results between runs | Async content loading | Ensure deterministic page state before scan |
175| CI fails but local passes | Different viewport/browser | Use same headless config as CI |
176
177---
178
179## Triage by POUR Principles
180
181| Principle | Focus Areas | Common Violations |
182|-----------|-------------|-------------------|
183| **Perceivable** | Text alternatives, captions, contrast, structure | Missing alt text, low contrast, missing labels |
184| **Operable** | Keyboard access, focus order, bypass blocks | Keyboard traps, no skip link, focus not visible |
185| **Understandable** | Labels, predictable behavior, error handling | Unclear instructions, unexpected changes |
186| **Robust** | Valid HTML, ARIA, name/role/value | Invalid ARIA, duplicate IDs, missing roles |
187
188---
189
190## Running Tests
191
192### Maven Commands
193
194| Command | Purpose |
195|---------|---------|
196| `mvn test -Dgroups=a11y` | Run all accessibility tests |
197| `mvn test -Dtest=A11yTest` | Run specific test class |
198| `mvn test -Dheadless=true` | Run headless (CI mode) |
199| `mvn allure:serve` | View Allure report with violations |
200
201### CI/CD Integration
202
203```yaml
204- name: Run Accessibility Tests
205 run: mvn test -Dgroups=a11y -Dheadless=true
206
207- name: Upload A11y Report
208 uses: actions/upload-artifact@v3
209 with:
210 name: a11y-report
211 path: target/a11y-results/
212```
213
214---
215
216## Red Flags
217
218- Treating a clean axe scan as full WCAG conformance — automation covers only ~30-50% of criteria.
219- Globally disabling rules instead of scoped `.exclude()` with a documented remediation ticket.
220- Scanning before the page is fully loaded — async content yields false "0 violations".
221- Failing the build on `incomplete` rules — those need manual review, not automatic failure.
222
223---
224
225## References
226
227- [Axe Patterns: Helper Scanning](references/axe-patterns-helper-scanning.md) - Maven setup and AccessibilityHelper scanning methods
228- [Axe Patterns: Helper Processing](references/axe-patterns-helper-processing.md) - AccessibilityHelper results, filtering, logging, and reporting
229- [Axe Patterns: Tags & Tests](references/axe-patterns-tags-and-tests.md) - Common axe tags reference and test patterns
230- [Axe Patterns: Keyboard & CI/CD](references/axe-patterns-keyboard-and-cicd.md) - Keyboard navigation testing and CI/CD integration
231- [Axe-Core API Reference](references/axe-api-reference.md) - Full AxeBuilder config, Results object, and impact levels
232- [WCAG 2.2 AA Checklist: Perceivable & Operable](references/wcag21aa-checklist-perceivable-operable.md) - Manual audit checklist, POUR principles 1-2
233- [WCAG 2.2 AA Checklist: Understandable & Robust](references/wcag21aa-checklist-understandable-robust.md) - Manual audit checklist, POUR principles 3-4 and assistive tech
234- [WCAG 2.2 AA Checklist: Additions & Exceptions](references/wcag21aa-checklist-additions-exceptions.md) - WCAG 2.2 additions, exception template, W3C references
235- [Deque Axe Rules](https://dequeuniversity.com/rules/axe/4.10) - Rule descriptions
236- [W3C WCAG 2.2](https://www.w3.org/TR/WCAG22/) - Official specification
237- [WAI-ARIA Practices](https://www.w3.org/WAI/ARIA/apg/) - Widget patterns
238
239---
240
241## Verification
242
243- [ ] **Axe WebDriver audit passes** — `AxeBuilder.analyze(driver)` returns zero critical violations
244- [ ] **Keyboard accessibility verified** — Tab navigation reaches all interactive elements
245- [ ] **WCAG 2.2 AA compliance** — All rules for AA level pass (includes WCAG 2.2 additions: focus-not-obscured, dragging movements, target-size minimum)