
Accessibility Testing
- 109 installs
- 433 repo stars
- Updated August 4, 2026
- proffesor-for-testing/agentic-qe
accessibility-testing is a Claude Code skill for testing & qa.
About
accessibility-testing is a Claude Code skill for testing & qa. It helps solo builders move faster with AI-assisted development.
- accessibility-testing
- Testing & QA
- AI-coding skill
Accessibility Testing by the numbers
- 109 all-time installs (skills.sh)
- +4 installs in the week ending Aug 4, 2026 (Skillselion tracking)
- Ranked #972 of 2,153 Testing & QA skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/proffesor-for-testing/agentic-qe --skill accessibility-testingAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 109 |
|---|---|
| repo stars | ★ 433 |
| Last updated | August 4, 2026 |
| Repository | proffesor-for-testing/agentic-qe ↗ |
How do I helps with testing & qa tasks.?
Helps with testing & qa tasks.
Who is it for?
Best when you're working on testing & qa and need structured help with accessibility testing.
Skip if: Teams with no testing & qa needs, or anyone wanting a generic chat assistant without this specific workflow.
When should I use this skill?
When you need to helps with testing & qa tasks., or when accessibility-testing is a claude code skill for testing & qa.
What you get
Structured output aligned to accessibility-testing: accessibility-testing, Testing & QA.
Files
Accessibility Testing
Consolidated: For comprehensive WCAG auditing with multi-tool testing (axe-core + pa11y + Lighthouse), video accessibility, and remediation, prefer `/a11y-ally`. This skill provides a quick reference card for basic accessibility testing patterns.
Browser engine
Browser-driven a11y checks should go through the qe-browser fleet skill. vibium a11y-tree --json returns the full accessibility tree without visual rendering — feed it into axe-core via vibium eval --stdin for ruleset enforcement. See .claude/skills/qe-browser/SKILL.md.
<default_to_action> When testing accessibility or ensuring compliance: 1. APPLY POUR principles: Perceivable, Operable, Understandable, Robust 2. TEST with keyboard-only navigation (Tab, Enter, Escape) 3. VALIDATE with screen readers (VoiceOver, NVDA, JAWS) 4. CHECK color contrast (4.5:1 for text, 3:1 for large text) 5. AUTOMATE with axe-core, integrate in CI/CD pipeline
Quick A11y Checklist:
- All images have alt text (or alt="" for decorative)
- All form fields have labels
- Color is never the only indicator
- Focus visible on all interactive elements
- Keyboard navigation works throughout
Critical Success Factors:
- Automated testing catches 30-50% of issues
- Manual testing with real assistive tech required
- Include users with disabilities in testing
</default_to_action>
Quick Reference Card
When to Use
- Legal compliance (ADA, Section 508, EU Directive)
- New feature development
- Before release validation
- Accessibility audits
WCAG 2.2 Levels
| Level | Requirement | Target |
|---|---|---|
| A | Basic accessibility | Minimum legal |
| AA | Standard (most orgs) | Industry standard |
| AAA | Enhanced | Specialized sites |
POUR Principles
| Principle | Meaning | Key Tests |
|---|---|---|
| Perceivable | Can perceive content | Alt text, contrast, captions |
| Operable | Can operate UI | Keyboard, no seizures, navigation |
| Understandable | Can understand | Clear labels, predictable, errors |
| Robust | Works with assistive tech | Valid HTML, ARIA |
Color Contrast Requirements
| Content | AA Ratio | AAA Ratio |
|---|---|---|
| Normal text | 4.5:1 | 7:1 |
| Large text (18pt+) | 3:1 | 4.5:1 |
| UI components | 3:1 | - |
---
Keyboard Navigation Testing
// Test all interactive elements reachable via keyboard
test('all interactive elements keyboard accessible', async ({ page }) => {
await page.goto('/');
const focusableElements = await page.$$('button, a, input, select, textarea, [tabindex]');
for (const element of focusableElements) {
await element.focus();
const isFocused = await element.evaluate(el => document.activeElement === el);
expect(isFocused).toBe(true);
}
});
// Verify visible focus indicator
test('focus indicator visible', async ({ page }) => {
await page.goto('/');
await page.keyboard.press('Tab');
const focusedElement = await page.locator(':focus');
const outline = await focusedElement.evaluate(el =>
getComputedStyle(el).outline
);
expect(outline).not.toBe('none');
});---
Automated Testing with axe-core
Preferred: via the a11y-ally AQE skill (qe-browser + Vibium)
For new work, use the a11y-ally skill — it composes qe-browser (Vibium WebDriver BiDi) with axe-core, pa11y, and Lighthouse and produces a WCAG-tagged JSON report with remediation guidance. It avoids the 300MB Playwright install and is already wired into the AQE fleet.
# Runs axe-core + pa11y + Lighthouse via qe-browser (Vibium) engine
aqe skill run a11y-ally -- --url https://example.com --wcag AAFallback: Playwright + @axe-core/playwright
Keep this path when you have an existing Playwright suite and don't want to introduce a second browser runner, or when you need Firefox/Safari coverage that Vibium's Chrome-only BiDi backend can't provide today.
import { test, expect } from '@playwright/test';
import AxeBuilder from '@axe-core/playwright';
test('page has no accessibility violations', async ({ page }) => {
await page.goto('/');
const results = await new AxeBuilder({ page })
.withTags(['wcag2a', 'wcag2aa', 'wcag22aa'])
.analyze();
expect(results.violations).toEqual([]);
});
// CI/CD integration
test('checkout flow accessible', async ({ page }) => {
await page.goto('/checkout');
const results = await new AxeBuilder({ page })
.include('#checkout-form')
.disableRules(['color-contrast']) // Fix in next sprint
.analyze();
expect(results.violations.filter(v =>
v.impact === 'critical' || v.impact === 'serious'
)).toHaveLength(0);
});---
Screen Reader Testing Checklist
## VoiceOver (macOS) Testing
- [ ] Page title announced on load
- [ ] Headings hierarchy correct (h1 → h2 → h3)
- [ ] Landmarks present (nav, main, footer)
- [ ] Images have descriptive alt text
- [ ] Form labels read correctly
- [ ] Error messages announced
- [ ] Dynamic content updates announced (aria-live)---
Agent-Driven Accessibility
// Comprehensive a11y validation
await Task("Accessibility Validation", {
url: 'https://example.com/checkout',
standard: 'WCAG2.2',
level: 'AA',
checks: ['keyboard', 'screen-reader', 'color-contrast'],
includeScreenReaderSimulation: true
}, "qe-visual-tester");
// Fleet coordination for comprehensive testing
const a11yFleet = await FleetManager.coordinate({
strategy: 'comprehensive-accessibility',
agents: [
'qe-visual-tester', // Visual & keyboard checks
'qe-test-generator', // Generate a11y tests
'qe-quality-gate' // Enforce compliance
],
topology: 'parallel'
});---
Agent Coordination Hints
Memory Namespace
aqe/accessibility/
├── wcag-results/* - WCAG audit results
├── screen-reader/* - Screen reader test logs
├── remediation/* - Fix recommendations
└── compliance/* - Compliance reportsFleet Coordination
const a11yFleet = await FleetManager.coordinate({
strategy: 'accessibility-testing',
agents: [
'qe-visual-tester', // axe-core, keyboard, focus
'qe-test-generator', // Generate a11y test cases
'qe-quality-gate' // Block non-compliant builds
],
topology: 'parallel'
});---
Related Skills
- visual-testing-advanced - Visual a11y checks
- mobile-testing - Mobile a11y (VoiceOver, TalkBack)
- compliance-testing - Legal compliance
---
Remember
1 billion people have disabilities. Inaccessible software excludes 15% of humanity. Legal requirements: ADA, Section 508, EU Directive 2016/2102. $13T purchasing power. 250%+ increase in lawsuits.
Automated testing catches only 30-50% of issues. Combine with manual keyboard testing, screen reader testing, and real user testing with people with disabilities.
With Agents: Agents automate WCAG 2.2 compliance checking, screen reader simulation, and focus management validation. Use agents to enforce accessibility standards in CI/CD and catch violations before production.
# =============================================================================
# AQE Accessibility Testing Skill Evaluation Suite v1.0.0
# WCAG 2.2 compliance testing evaluation with POUR principle coverage
# =============================================================================
#
# This evaluation suite validates accessibility testing skill behavior through:
# 1. POUR principle coverage (Perceivable, Operable, Understandable, Robust)
# 2. WCAG 2.2 Level A, AA, AAA conformance testing
# 3. Multi-model consistency across Claude and GPT models
# 4. Severity classification validation
# 5. Remediation quality assessment
#
# Schema: .validation/schemas/skill-eval.schema.json
# Runner: scripts/run-skill-eval.ts
# =============================================================================
skill: accessibility-testing
version: 1.0.0
description: >
Comprehensive evaluation suite for WCAG 2.2 accessibility testing skill.
Tests POUR principles (Perceivable, Operable, Understandable, Robust),
conformance levels, finding detection, and remediation quality across
multiple LLM models.
# =============================================================================
# Multi-Model Configuration
# =============================================================================
models_to_test:
- claude-sonnet-4-6 # Primary (high accuracy expected)
- claude-haiku-4-5 # Fast model (minimum quality floor)
# =============================================================================
# MCP Integration Configuration
# =============================================================================
mcp_integration:
enabled: true
namespace: skill-validation
# Query existing accessibility patterns before running evals
query_patterns: true
# Track each test outcome for learning feedback
track_outcomes: true
# Store successful patterns (WCAG violations, remediation approaches)
store_patterns: true
# Share learning with fleet coordinator agents
share_learning: true
# Update quality gate with accessibility metrics
update_quality_gate: true
# Agents to share learning with
target_agents:
- qe-learning-coordinator
- qe-queen-coordinator
- qe-accessibility-auditor
# =============================================================================
# ReasoningBank Learning Configuration
# =============================================================================
learning:
store_success_patterns: true
store_failure_patterns: true
pattern_ttl_days: 90
min_confidence_to_store: 0.7
cross_model_comparison: true
# =============================================================================
# Result Format Configuration
# =============================================================================
result_format:
json_output: true
markdown_report: true
include_raw_output: false
include_timing: true
include_token_usage: true
# =============================================================================
# Environment Setup
# =============================================================================
setup:
required_tools:
- jq
environment_variables:
WCAG_VERSION: "2.2"
TARGET_LEVEL: "AA"
fixtures:
- name: accessible_page
content: |
<!DOCTYPE html>
<html lang="en">
<head><title>Accessible Page</title></head>
<body>
<header><nav aria-label="Main"><a href="/">Home</a></nav></header>
<main>
<h1>Welcome</h1>
<img src="hero.jpg" alt="Person using laptop">
<form>
<label for="email">Email:</label>
<input type="email" id="email" name="email" required>
<button type="submit">Subscribe</button>
</form>
</main>
</body>
</html>
- name: inaccessible_page
content: |
<!DOCTYPE html>
<html>
<head><title></title></head>
<body>
<div onclick="navigate()">Menu</div>
<img src="logo.png">
<input type="text" placeholder="Enter email">
<span style="color: #999; background: #fff;">Light gray text</span>
</body>
</html>
# =============================================================================
# Test Cases - POUR Principles Coverage
# =============================================================================
test_cases:
# -------------------------------------------------------------------------
# PERCEIVABLE (WCAG 1.x) - Content can be perceived
# -------------------------------------------------------------------------
- id: tc001_perceivable_alt_text
description: "Detect missing alt text on images (WCAG 1.1.1)"
category: perceivable
priority: critical
input:
code: |
<img src="product.jpg">
<img src="banner.png" alt="">
<img src="hero.jpg" alt="Team collaboration in modern office">
context:
language: html
wcagLevel: AA
expected_output:
must_contain:
- "alt"
- "1.1.1"
- "perceivable"
must_not_contain:
- "no issues"
finding_count:
min: 1
max: 2
severity_classification: serious
validation:
schema_check: true
keyword_match_threshold: 0.9
reasoning_quality_min: 0.7
- id: tc002_perceivable_color_contrast
description: "Detect insufficient color contrast (WCAG 1.4.3)"
category: perceivable
priority: critical
input:
code: |
<p style="color: #777; background-color: #fff;">Gray text on white</p>
<p style="color: #333; background-color: #fff;">Dark text on white</p>
<h1 style="color: #aaa; background-color: #eee;">Low contrast heading</h1>
context:
language: html
wcagLevel: AA
expected_output:
must_contain:
- "contrast"
- "1.4.3"
- "4.5:1"
finding_count:
min: 1
max: 3
validation:
schema_check: true
keyword_match_threshold: 0.8
- id: tc003_perceivable_video_captions
description: "Detect videos without captions (WCAG 1.2.2)"
category: perceivable
priority: critical
input:
code: |
<video src="product-demo.mp4" controls>
<source src="product-demo.mp4" type="video/mp4">
</video>
<video controls>
<source src="interview.mp4" type="video/mp4">
<track kind="captions" src="captions.vtt" srclang="en">
</video>
context:
language: html
wcagLevel: AA
expected_output:
must_contain:
- "caption"
- "1.2.2"
- "track"
finding_count:
min: 1
max: 2
validation:
schema_check: true
keyword_match_threshold: 0.8
# -------------------------------------------------------------------------
# OPERABLE (WCAG 2.x) - Interface is operable
# -------------------------------------------------------------------------
- id: tc004_operable_keyboard_access
description: "Detect elements not keyboard accessible (WCAG 2.1.1)"
category: operable
priority: critical
input:
code: |
<div onclick="handleClick()">Click me</div>
<span class="button" onclick="submit()">Submit</span>
<button onclick="save()">Save</button>
<a href="/next">Next Page</a>
context:
language: html
wcagLevel: A
expected_output:
must_contain:
- "keyboard"
- "2.1.1"
- "operable"
- "button"
must_not_contain:
- "all elements accessible"
finding_count:
min: 2
max: 3
severity_classification: critical
validation:
schema_check: true
keyword_match_threshold: 0.9
reasoning_quality_min: 0.8
- id: tc005_operable_focus_visible
description: "Detect missing focus indicators (WCAG 2.4.7)"
category: operable
priority: high
input:
code: |
<style>
button:focus { outline: none; }
a:focus { outline: 0; }
input:focus { outline: none; border-color: blue; }
</style>
<button>Submit</button>
<a href="/">Home</a>
<input type="text" placeholder="Search">
context:
language: html
wcagLevel: AA
expected_output:
must_contain:
- "focus"
- "2.4.7"
- "outline"
finding_count:
min: 2
max: 3
validation:
schema_check: true
keyword_match_threshold: 0.8
- id: tc006_operable_keyboard_trap
description: "Detect keyboard traps (WCAG 2.1.2)"
category: operable
priority: critical
input:
code: |
<div id="modal" tabindex="0" onkeydown="if(event.key==='Tab'){event.preventDefault();}">
<h2>Modal Dialog</h2>
<input type="text" placeholder="Enter name">
<button>Close</button>
</div>
context:
language: html
wcagLevel: A
description: "Modal with keyboard trap"
expected_output:
must_contain:
- "keyboard trap"
- "2.1.2"
- "Tab"
severity_classification: critical
validation:
schema_check: true
# -------------------------------------------------------------------------
# UNDERSTANDABLE (WCAG 3.x) - Content is understandable
# -------------------------------------------------------------------------
- id: tc007_understandable_form_labels
description: "Detect form inputs without labels (WCAG 3.3.2)"
category: understandable
priority: high
input:
code: |
<form>
<input type="text" placeholder="Name">
<input type="email" placeholder="Email">
<label for="phone">Phone:</label>
<input type="tel" id="phone">
<button>Submit</button>
</form>
context:
language: html
wcagLevel: A
expected_output:
must_contain:
- "label"
- "3.3.2"
- "understandable"
finding_count:
min: 2
max: 3
validation:
schema_check: true
keyword_match_threshold: 0.8
- id: tc008_understandable_error_messages
description: "Detect missing error identification (WCAG 3.3.1)"
category: understandable
priority: high
input:
code: |
<form>
<input type="email" required aria-invalid="true">
<span style="color: red;">*</span>
<input type="password" required aria-describedby="pwd-error">
<span id="pwd-error" role="alert">Password must be 8+ characters</span>
</form>
context:
language: html
wcagLevel: A
expected_output:
must_contain:
- "error"
- "3.3.1"
finding_count:
min: 1
max: 2
validation:
schema_check: true
- id: tc009_understandable_language
description: "Detect missing page language (WCAG 3.1.1)"
category: understandable
priority: high
input:
code: |
<!DOCTYPE html>
<html>
<head><title>My Page</title></head>
<body><h1>Welcome</h1></body>
</html>
context:
language: html
wcagLevel: A
expected_output:
must_contain:
- "lang"
- "3.1.1"
- "language"
finding_count:
min: 1
max: 1
severity_classification: serious
validation:
schema_check: true
keyword_match_threshold: 0.9
# -------------------------------------------------------------------------
# ROBUST (WCAG 4.x) - Compatible with assistive technologies
# -------------------------------------------------------------------------
- id: tc010_robust_aria_valid
description: "Detect invalid ARIA attributes (WCAG 4.1.2)"
category: robust
priority: high
input:
code: |
<button aria-label="">Submit</button>
<div role="button" aria-pressed="maybe">Toggle</div>
<input type="checkbox" aria-checked="true">
<nav aria-labelledby="nonexistent">Navigation</nav>
context:
language: html
wcagLevel: A
expected_output:
must_contain:
- "ARIA"
- "4.1.2"
- "robust"
finding_count:
min: 2
max: 4
validation:
schema_check: true
keyword_match_threshold: 0.8
- id: tc011_robust_html_parsing
description: "Detect HTML parsing errors (WCAG 4.1.1)"
category: robust
priority: medium
input:
code: |
<html>
<head><title>Page</head>
<body>
<div id="main">
<p>Unclosed paragraph
<div id="main">Duplicate ID</div>
</div>
</body>
</html>
context:
language: html
wcagLevel: A
expected_output:
must_contain:
- "4.1.1"
- "parsing"
finding_count:
min: 1
max: 4
validation:
schema_check: true
# -------------------------------------------------------------------------
# Negative Tests (Should NOT find issues)
# -------------------------------------------------------------------------
- id: tc012_no_false_positives_accessible
description: "Fully accessible page should not flag critical issues"
category: negative
priority: critical
input:
code: |
<!DOCTYPE html>
<html lang="en">
<head>
<title>Accessible Website</title>
<meta charset="UTF-8">
</head>
<body>
<a href="#main" class="skip-link">Skip to main content</a>
<header>
<nav aria-label="Main navigation">
<ul>
<li><a href="/">Home</a></li>
<li><a href="/about">About</a></li>
</ul>
</nav>
</header>
<main id="main">
<h1>Welcome to Our Site</h1>
<img src="hero.jpg" alt="Happy customers using our product">
<form>
<label for="email">Email address:</label>
<input type="email" id="email" name="email" required aria-describedby="email-hint">
<span id="email-hint">We'll never share your email.</span>
<button type="submit">Subscribe</button>
</form>
</main>
<footer>
<p>© 2026 Accessible Company</p>
</footer>
</body>
</html>
context:
language: html
wcagLevel: AA
expected_output:
must_contain:
- "accessible"
must_not_contain:
- "critical"
- "serious"
finding_count:
max: 2 # Allow minor/informational findings only
validation:
schema_check: true
keyword_match_threshold: 0.7
# -------------------------------------------------------------------------
# Edge Cases
# -------------------------------------------------------------------------
- id: tc013_dynamic_content_aria_live
description: "Detect missing aria-live for dynamic content"
category: edge_cases
priority: medium
input:
code: |
<div id="notifications">
<!-- JavaScript updates this -->
</div>
<div id="status" aria-live="polite" role="status">
Loading...
</div>
<div id="alerts" role="alert">
Error occurred!
</div>
context:
language: html
wcagLevel: AA
description: "Dynamic content regions"
expected_output:
must_contain:
- "aria-live"
- "dynamic"
validation:
schema_check: true
- id: tc014_heading_hierarchy
description: "Detect broken heading hierarchy (WCAG 1.3.1)"
category: edge_cases
priority: medium
input:
code: |
<h1>Main Title</h1>
<h3>Skipped h2!</h3>
<h4>Another section</h4>
<h2>Back to h2</h2>
<h6>Way out of order</h6>
context:
language: html
wcagLevel: A
expected_output:
must_contain:
- "heading"
- "hierarchy"
- "1.3.1"
finding_count:
min: 1
max: 3
validation:
schema_check: true
# -------------------------------------------------------------------------
# Remediation Quality Tests
# -------------------------------------------------------------------------
- id: tc015_remediation_code_quality
description: "Verify remediation includes actionable code examples"
category: remediation
priority: high
input:
code: |
<img src="product.jpg">
<div onclick="buy()">Buy Now</div>
context:
language: html
wcagLevel: AA
options:
includeRemediation: true
expected_output:
must_contain:
- "alt="
- "button"
- "role"
must_match_regex:
- "<img.*alt=\".*\".*>"
- "<button.*>.*</button>"
validation:
schema_check: true
grading_rubric:
completeness: 0.3
accuracy: 0.4
actionability: 0.3
# -------------------------------------------------------------------------
# Multi-page / Complex Scenarios
# -------------------------------------------------------------------------
- id: tc016_complex_form_validation
description: "Complex form with multiple accessibility requirements"
category: integration
priority: high
input:
code: |
<form id="checkout">
<fieldset>
<legend>Shipping Address</legend>
<input type="text" name="street" placeholder="Street">
<input type="text" name="city" placeholder="City">
<select name="state">
<option value="">Select State</option>
</select>
</fieldset>
<fieldset>
<legend>Payment</legend>
<input type="text" name="card" maxlength="16">
<input type="text" name="cvv" maxlength="3">
</fieldset>
<div class="error" style="display:none;"></div>
<button type="submit">Place Order</button>
</form>
context:
language: html
wcagLevel: AA
environment: production
expected_output:
must_contain:
- "label"
- "form"
- "3.3"
finding_count:
min: 4
max: 10
validation:
schema_check: true
keyword_match_threshold: 0.8
# =============================================================================
# Success Criteria
# =============================================================================
success_criteria:
# Minimum percentage of tests that must pass
pass_rate: 0.90
# Critical tests (POUR principle detection) must have 100% pass rate
critical_pass_rate: 1.0
# Average reasoning quality across all tests
avg_reasoning_quality: 0.75
# Maximum time for entire suite (5 minutes)
max_execution_time_ms: 300000
# Maximum variance between different models (15%)
cross_model_variance: 0.15
# =============================================================================
# Metadata
# =============================================================================
metadata:
author: "@aqe-team"
created: "2026-02-02"
last_updated: "2026-02-02"
coverage_target: "POUR principles, WCAG 2.2 A/AA criteria, remediation quality"
wcag_criteria_covered:
- "1.1.1 Non-text Content"
- "1.2.2 Captions (Prerecorded)"
- "1.3.1 Info and Relationships"
- "1.4.3 Contrast (Minimum)"
- "2.1.1 Keyboard"
- "2.1.2 No Keyboard Trap"
- "2.4.7 Focus Visible"
- "3.1.1 Language of Page"
- "3.3.1 Error Identification"
- "3.3.2 Labels or Instructions"
- "4.1.1 Parsing"
- "4.1.2 Name, Role, Value"
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://agentic-qe.dev/schemas/accessibility-testing-output.json",
"title": "AQE Accessibility Testing Skill Output Schema",
"description": "Schema for WCAG 2.2 accessibility audit output. Extends base skill output template with accessibility-specific fields including POUR principles, conformance levels, and remediation guidance.",
"type": "object",
"required": ["skillName", "version", "timestamp", "status", "trustTier", "output"],
"properties": {
"skillName": {
"type": "string",
"const": "accessibility-testing",
"description": "Skill identifier"
},
"version": {
"type": "string",
"pattern": "^\\d+\\.\\d+\\.\\d+(-[a-zA-Z0-9]+)?$",
"description": "Semantic version of the skill"
},
"timestamp": {
"type": "string",
"pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}:\\d{2})?$",
"description": "ISO 8601 timestamp of audit execution"
},
"status": {
"type": "string",
"enum": ["success", "partial", "failed", "skipped"],
"description": "Overall execution status"
},
"trustTier": {
"type": "integer",
"const": 3,
"description": "Trust tier 3: has schema, validator, and eval suite"
},
"output": {
"type": "object",
"required": ["summary", "conformanceLevel", "pourBreakdown"],
"properties": {
"summary": {
"type": "string",
"minLength": 10,
"maxLength": 2000,
"description": "Human-readable summary of accessibility audit findings"
},
"score": {
"$ref": "#/$defs/accessibilityScore",
"description": "Overall accessibility compliance score"
},
"conformanceLevel": {
"$ref": "#/$defs/conformanceLevel",
"description": "WCAG conformance level achieved"
},
"targetLevel": {
"$ref": "#/$defs/conformanceLevel",
"description": "Target WCAG conformance level for the audit"
},
"wcagVersion": {
"type": "string",
"enum": ["2.0", "2.1", "2.2"],
"default": "2.2",
"description": "WCAG version tested against"
},
"pourBreakdown": {
"$ref": "#/$defs/pourBreakdown",
"description": "Breakdown by POUR principles (Perceivable, Operable, Understandable, Robust)"
},
"findings": {
"type": "array",
"items": {
"$ref": "#/$defs/accessibilityFinding"
},
"maxItems": 500,
"description": "List of accessibility violations found"
},
"recommendations": {
"type": "array",
"items": {
"$ref": "#/$defs/accessibilityRecommendation"
},
"maxItems": 100,
"description": "Remediation recommendations with code fixes"
},
"metrics": {
"$ref": "#/$defs/accessibilityMetrics",
"description": "Quantitative accessibility metrics"
},
"artifacts": {
"type": "array",
"items": {
"$ref": "#/$defs/artifact"
},
"maxItems": 50,
"description": "Generated artifacts (reports, captions, etc.)"
},
"categories": {
"type": "object",
"additionalProperties": {
"$ref": "#/$defs/categoryScore"
},
"description": "Scores by WCAG category"
},
"videoCaptions": {
"type": "array",
"items": {
"$ref": "#/$defs/videoCaptionOutput"
},
"description": "Generated video captions and audio descriptions"
},
"euCompliance": {
"$ref": "#/$defs/euComplianceResult",
"description": "EN 301 549 / EU Accessibility Act compliance (if tested)"
}
}
},
"metadata": {
"type": "object",
"properties": {
"executionTimeMs": {
"type": "integer",
"minimum": 0,
"description": "Execution time in milliseconds"
},
"toolsUsed": {
"type": "array",
"items": {
"type": "string",
"enum": ["axe-core", "pa11y", "lighthouse", "claude-vision", "ffmpeg", "nvda", "voiceover", "jaws"]
},
"description": "Accessibility tools used during audit"
},
"agentId": {
"type": "string",
"pattern": "^qe-[a-z][a-z0-9-]*$",
"description": "Agent that executed the audit"
},
"targetUrl": {
"type": "string",
"pattern": "^https?://",
"description": "URL audited"
},
"pagesAudited": {
"type": "integer",
"minimum": 1,
"description": "Number of pages audited"
},
"elementsAnalyzed": {
"type": "integer",
"minimum": 0,
"description": "Number of DOM elements analyzed"
}
}
},
"validation": {
"type": "object",
"properties": {
"schemaValid": {
"type": "boolean"
},
"contentValid": {
"type": "boolean"
},
"confidence": {
"type": "number",
"minimum": 0,
"maximum": 1
},
"warnings": {
"type": "array",
"items": { "type": "string" }
},
"errors": {
"type": "array",
"items": { "type": "string" }
}
}
},
"learning": {
"type": "object",
"properties": {
"patternsDetected": {
"type": "array",
"items": { "type": "string" },
"description": "Accessibility patterns detected"
},
"reward": {
"type": "number",
"minimum": 0,
"maximum": 1,
"description": "Learning reward signal"
}
}
}
},
"$defs": {
"conformanceLevel": {
"type": "string",
"enum": ["A", "AA", "AAA", "none"],
"description": "WCAG conformance level"
},
"pourPrinciple": {
"type": "string",
"enum": ["perceivable", "operable", "understandable", "robust"],
"description": "POUR accessibility principle"
},
"accessibilityScore": {
"type": "object",
"required": ["value", "max"],
"properties": {
"value": {
"type": "number",
"minimum": 0,
"maximum": 100,
"description": "Accessibility score (0-100)"
},
"max": {
"type": "number",
"const": 100
},
"grade": {
"type": "string",
"pattern": "^[A-F][+-]?$",
"description": "Letter grade"
},
"conformanceAchieved": {
"$ref": "#/$defs/conformanceLevel",
"description": "Highest conformance level achieved"
},
"trend": {
"type": "string",
"enum": ["improving", "stable", "declining", "unknown"]
}
}
},
"pourBreakdown": {
"type": "object",
"required": ["perceivable", "operable", "understandable", "robust"],
"properties": {
"perceivable": {
"$ref": "#/$defs/pourScore",
"description": "Perceivable (WCAG 1.x) - Text alternatives, time-based media, adaptable, distinguishable"
},
"operable": {
"$ref": "#/$defs/pourScore",
"description": "Operable (WCAG 2.x) - Keyboard, timing, seizures, navigation, input modalities"
},
"understandable": {
"$ref": "#/$defs/pourScore",
"description": "Understandable (WCAG 3.x) - Readable, predictable, input assistance"
},
"robust": {
"$ref": "#/$defs/pourScore",
"description": "Robust (WCAG 4.x) - Compatible with assistive technologies"
}
}
},
"pourScore": {
"type": "object",
"required": ["score", "violationCount"],
"properties": {
"score": {
"type": "number",
"minimum": 0,
"maximum": 100,
"description": "Principle score (0-100)"
},
"violationCount": {
"type": "integer",
"minimum": 0,
"description": "Number of violations in this principle"
},
"criticalCount": {
"type": "integer",
"minimum": 0,
"description": "Number of critical violations"
},
"seriousCount": {
"type": "integer",
"minimum": 0,
"description": "Number of serious violations"
},
"moderateCount": {
"type": "integer",
"minimum": 0,
"description": "Number of moderate violations"
},
"minorCount": {
"type": "integer",
"minimum": 0,
"description": "Number of minor violations"
},
"guidelines": {
"type": "array",
"items": {
"$ref": "#/$defs/guidelineResult"
},
"description": "Results by WCAG guideline"
}
}
},
"guidelineResult": {
"type": "object",
"required": ["guideline", "title", "passed"],
"properties": {
"guideline": {
"type": "string",
"pattern": "^\\d+\\.\\d+$",
"description": "WCAG guideline number (e.g., 1.1, 2.4)"
},
"title": {
"type": "string",
"description": "Guideline title"
},
"passed": {
"type": "boolean",
"description": "Whether all success criteria passed"
},
"successCriteria": {
"type": "array",
"items": {
"$ref": "#/$defs/successCriterionResult"
}
}
}
},
"successCriterionResult": {
"type": "object",
"required": ["criterion", "level", "status"],
"properties": {
"criterion": {
"type": "string",
"pattern": "^\\d+\\.\\d+\\.\\d+$",
"description": "WCAG success criterion (e.g., 1.1.1, 2.4.7)"
},
"level": {
"$ref": "#/$defs/conformanceLevel"
},
"status": {
"type": "string",
"enum": ["passed", "failed", "not-applicable", "not-tested"],
"description": "Criterion status"
},
"violationCount": {
"type": "integer",
"minimum": 0
}
}
},
"accessibilityFinding": {
"type": "object",
"required": ["id", "title", "severity", "wcagCriterion", "pourPrinciple"],
"properties": {
"id": {
"type": "string",
"pattern": "^A11Y-\\d{3,6}$",
"description": "Unique finding identifier (e.g., A11Y-001)"
},
"title": {
"type": "string",
"minLength": 5,
"maxLength": 200,
"description": "Finding title"
},
"description": {
"type": "string",
"maxLength": 2000,
"description": "Detailed description of the violation"
},
"severity": {
"type": "string",
"enum": ["critical", "serious", "moderate", "minor"],
"description": "Severity: critical=prevents access, serious=major barrier, moderate=some difficulty, minor=annoyance"
},
"impact": {
"type": "string",
"maxLength": 500,
"description": "Impact on users with disabilities"
},
"wcagCriterion": {
"type": "string",
"pattern": "^\\d+\\.\\d+\\.\\d+$",
"description": "WCAG success criterion violated (e.g., 1.1.1)"
},
"wcagLevel": {
"$ref": "#/$defs/conformanceLevel",
"description": "WCAG conformance level of the criterion"
},
"pourPrinciple": {
"$ref": "#/$defs/pourPrinciple",
"description": "POUR principle violated"
},
"location": {
"$ref": "#/$defs/elementLocation",
"description": "Location of the violation"
},
"element": {
"type": "object",
"properties": {
"tagName": {
"type": "string",
"description": "HTML tag name"
},
"selector": {
"type": "string",
"description": "CSS selector"
},
"xpath": {
"type": "string",
"description": "XPath expression"
},
"html": {
"type": "string",
"maxLength": 1000,
"description": "HTML snippet of the element"
},
"attributes": {
"type": "object",
"additionalProperties": { "type": "string" },
"description": "Relevant element attributes"
}
}
},
"remediation": {
"type": "string",
"maxLength": 2000,
"description": "How to fix this violation"
},
"codeExample": {
"type": "object",
"properties": {
"before": {
"type": "string",
"description": "Code before fix"
},
"after": {
"type": "string",
"description": "Code after fix"
}
},
"description": "Before/after code example for remediation"
},
"affectedUsers": {
"type": "array",
"items": {
"type": "string",
"enum": ["blind", "low-vision", "color-blind", "deaf", "hard-of-hearing", "motor-impaired", "cognitive", "photosensitive"]
},
"description": "User groups affected by this violation"
},
"confidence": {
"type": "number",
"minimum": 0,
"maximum": 1,
"description": "Confidence in this finding"
},
"tool": {
"type": "string",
"description": "Tool that detected this violation"
}
}
},
"accessibilityRecommendation": {
"type": "object",
"required": ["id", "title", "priority"],
"properties": {
"id": {
"type": "string",
"pattern": "^REC-\\d{3,6}$"
},
"title": {
"type": "string",
"minLength": 5,
"maxLength": 200
},
"description": {
"type": "string",
"maxLength": 2000
},
"priority": {
"type": "string",
"enum": ["critical", "high", "medium", "low"]
},
"effort": {
"type": "string",
"enum": ["trivial", "low", "medium", "high", "major"],
"description": "Estimated effort to implement"
},
"wcagCriteria": {
"type": "array",
"items": {
"type": "string",
"pattern": "^\\d+\\.\\d+\\.\\d+$"
},
"description": "WCAG criteria addressed"
},
"relatedFindings": {
"type": "array",
"items": {
"type": "string",
"pattern": "^A11Y-\\d{3,6}$"
},
"description": "Related finding IDs"
},
"codeExample": {
"type": "string",
"maxLength": 5000,
"description": "Code example for remediation"
},
"resources": {
"type": "array",
"items": {
"type": "object",
"required": ["title", "url"],
"properties": {
"title": { "type": "string" },
"url": { "type": "string", "pattern": "^https?://" }
}
},
"description": "External resources"
}
}
},
"accessibilityMetrics": {
"type": "object",
"properties": {
"totalElements": {
"type": "integer",
"minimum": 0,
"description": "Total DOM elements analyzed"
},
"imagesWithAlt": {
"type": "integer",
"minimum": 0,
"description": "Images with proper alt text"
},
"imagesWithoutAlt": {
"type": "integer",
"minimum": 0,
"description": "Images missing alt text"
},
"formsWithLabels": {
"type": "integer",
"minimum": 0,
"description": "Form fields with proper labels"
},
"formsWithoutLabels": {
"type": "integer",
"minimum": 0,
"description": "Form fields missing labels"
},
"colorContrastPasses": {
"type": "integer",
"minimum": 0,
"description": "Elements passing color contrast"
},
"colorContrastFails": {
"type": "integer",
"minimum": 0,
"description": "Elements failing color contrast"
},
"keyboardAccessible": {
"type": "integer",
"minimum": 0,
"description": "Interactive elements keyboard accessible"
},
"keyboardTraps": {
"type": "integer",
"minimum": 0,
"description": "Keyboard traps detected"
},
"ariaUsage": {
"type": "object",
"properties": {
"correct": { "type": "integer", "minimum": 0 },
"incorrect": { "type": "integer", "minimum": 0 },
"missing": { "type": "integer", "minimum": 0 }
}
},
"headingStructure": {
"type": "object",
"properties": {
"valid": { "type": "boolean" },
"skippedLevels": { "type": "array", "items": { "type": "integer" } }
}
},
"videosWithCaptions": {
"type": "integer",
"minimum": 0
},
"videosWithoutCaptions": {
"type": "integer",
"minimum": 0
}
}
},
"elementLocation": {
"type": "object",
"properties": {
"url": {
"type": "string",
"pattern": "^https?://",
"description": "Page URL"
},
"selector": {
"type": "string",
"description": "CSS selector"
},
"xpath": {
"type": "string",
"description": "XPath"
},
"line": {
"type": "integer",
"minimum": 1,
"description": "Source line number"
},
"column": {
"type": "integer",
"minimum": 1,
"description": "Source column number"
}
}
},
"artifact": {
"type": "object",
"required": ["type", "path"],
"properties": {
"type": {
"type": "string",
"enum": ["report", "captions", "audio-description", "screenshot", "data", "log"]
},
"path": {
"type": "string"
},
"format": {
"type": "string",
"enum": ["json", "html", "md", "vtt", "txt", "png", "csv"]
},
"description": {
"type": "string"
}
}
},
"categoryScore": {
"type": "object",
"required": ["score"],
"properties": {
"score": {
"type": "number",
"minimum": 0,
"maximum": 100
},
"grade": {
"type": "string",
"pattern": "^[A-F][+-]?$"
},
"findingCount": {
"type": "integer",
"minimum": 0
}
}
},
"videoCaptionOutput": {
"type": "object",
"required": ["videoId", "source"],
"properties": {
"videoId": {
"type": "string",
"description": "Video identifier"
},
"source": {
"type": "string",
"description": "Video source URL or element ID"
},
"duration": {
"type": "number",
"description": "Video duration in seconds"
},
"framesAnalyzed": {
"type": "integer",
"minimum": 1,
"description": "Number of frames analyzed"
},
"captionsPath": {
"type": "string",
"description": "Path to generated WebVTT captions file"
},
"audioDescriptionPath": {
"type": "string",
"description": "Path to generated audio description file"
},
"frameDescriptions": {
"type": "array",
"items": {
"$ref": "#/$defs/frameDescription"
},
"description": "Descriptions of analyzed frames"
}
}
},
"frameDescription": {
"type": "object",
"required": ["frameNumber", "timestamp", "description"],
"properties": {
"frameNumber": {
"type": "integer",
"minimum": 1
},
"timestamp": {
"type": "string",
"pattern": "^\\d{2}:\\d{2}:\\d{2}\\.\\d{3}$",
"description": "Timestamp in HH:MM:SS.mmm format"
},
"description": {
"type": "string",
"description": "Visual description of the frame"
},
"scene": {
"type": "string",
"description": "Scene setting"
},
"text": {
"type": "string",
"description": "Any visible text"
},
"action": {
"type": "string",
"description": "Action occurring"
}
}
},
"euComplianceResult": {
"type": "object",
"properties": {
"standard": {
"type": "string",
"enum": ["EN 301 549 V3.2.1"],
"description": "EU standard tested against"
},
"productCategory": {
"type": "string",
"description": "EAA product category"
},
"overallStatus": {
"type": "string",
"enum": ["compliant", "partially-compliant", "non-compliant"]
},
"clausesPassed": {
"type": "integer",
"minimum": 0
},
"clausesFailed": {
"type": "integer",
"minimum": 0
},
"clausesPartial": {
"type": "integer",
"minimum": 0
},
"failedClauses": {
"type": "array",
"items": {
"type": "object",
"properties": {
"clause": { "type": "string" },
"title": { "type": "string" },
"wcagMapping": { "type": "string" },
"testMethod": {
"type": "string",
"enum": ["automated", "manual", "hybrid"]
}
}
}
}
}
}
}
}
{
"skillName": "accessibility-testing",
"skillVersion": "1.0.0",
"requiredTools": [
"jq"
],
"optionalTools": [
"axe",
"pa11y",
"lighthouse",
"ffmpeg",
"python3",
"ajv",
"jsonschema"
],
"schemaPath": "schemas/output.json",
"requiredFields": [
"skillName",
"status",
"output",
"output.conformanceLevel",
"output.pourBreakdown"
],
"requiredNonEmptyFields": [
"output.summary",
"output.pourBreakdown"
],
"mustContainTerms": [
"WCAG",
"accessibility"
],
"mustNotContainTerms": [
"TODO",
"placeholder",
"FIXME"
],
"enumValidations": {
".status": [
"success",
"partial",
"failed",
"skipped"
],
".output.conformanceLevel": [
"A",
"AA",
"AAA",
"none"
],
".output.wcagVersion": [
"2.0",
"2.1",
"2.2"
]
}
}
{
"skillName": "accessibility-testing",
"version": "1.0.0",
"timestamp": "2026-02-02T08:45:00Z",
"status": "partial",
"trustTier": 3,
"output": {
"summary": "Accessibility audit of https://example.com found 5 WCAG 2.2 Level AA violations requiring remediation. Key issues include missing alt text on images, insufficient color contrast, and keyboard accessibility problems.",
"conformanceLevel": "none",
"targetLevel": "AA",
"wcagVersion": "2.2",
"score": {
"value": 72,
"max": 100,
"grade": "C",
"conformanceAchieved": "none",
"trend": "unknown"
},
"pourBreakdown": {
"perceivable": {
"score": 65,
"violationCount": 3,
"criticalCount": 0,
"seriousCount": 2,
"moderateCount": 1,
"minorCount": 0
},
"operable": {
"score": 80,
"violationCount": 2,
"criticalCount": 1,
"seriousCount": 0,
"moderateCount": 1,
"minorCount": 0
},
"understandable": {
"score": 100,
"violationCount": 0,
"criticalCount": 0,
"seriousCount": 0,
"moderateCount": 0,
"minorCount": 0
},
"robust": {
"score": 90,
"violationCount": 0,
"criticalCount": 0,
"seriousCount": 0,
"moderateCount": 0,
"minorCount": 0
}
},
"findings": [
{
"id": "A11Y-001",
"title": "Image missing alt text",
"description": "The product image does not have an alt attribute, making it inaccessible to screen reader users.",
"severity": "serious",
"impact": "Screen reader users cannot perceive the image content",
"wcagCriterion": "1.1.1",
"wcagLevel": "A",
"pourPrinciple": "perceivable",
"element": {
"tagName": "img",
"selector": "#product-image",
"html": "<img src=\"product.jpg\" class=\"hero-image\">"
},
"remediation": "Add a descriptive alt attribute to the image",
"codeExample": {
"before": "<img src=\"product.jpg\" class=\"hero-image\">",
"after": "<img src=\"product.jpg\" class=\"hero-image\" alt=\"Red wireless headphones on white background\">"
},
"affectedUsers": ["blind", "low-vision"],
"confidence": 0.98,
"tool": "axe-core"
},
{
"id": "A11Y-002",
"title": "Insufficient color contrast",
"description": "The gray text on white background has a contrast ratio of 3.2:1, which is below the WCAG AA minimum of 4.5:1.",
"severity": "serious",
"impact": "Users with low vision may have difficulty reading the text",
"wcagCriterion": "1.4.3",
"wcagLevel": "AA",
"pourPrinciple": "perceivable",
"element": {
"tagName": "p",
"selector": ".subtitle",
"html": "<p class=\"subtitle\" style=\"color: #888888;\">Product description</p>"
},
"remediation": "Increase text color darkness to achieve 4.5:1 contrast ratio",
"codeExample": {
"before": "color: #888888;",
"after": "color: #595959;"
},
"affectedUsers": ["low-vision", "color-blind"],
"confidence": 0.95,
"tool": "axe-core"
},
{
"id": "A11Y-003",
"title": "Interactive element not keyboard accessible",
"description": "The custom dropdown uses a div with onclick but is not focusable or operable via keyboard.",
"severity": "critical",
"impact": "Keyboard-only users cannot interact with the dropdown",
"wcagCriterion": "2.1.1",
"wcagLevel": "A",
"pourPrinciple": "operable",
"element": {
"tagName": "div",
"selector": ".custom-dropdown",
"html": "<div class=\"custom-dropdown\" onclick=\"toggleDropdown()\">"
},
"remediation": "Use a native button element or add tabindex, role, and keyboard event handlers",
"codeExample": {
"before": "<div class=\"custom-dropdown\" onclick=\"toggleDropdown()\">",
"after": "<button class=\"custom-dropdown\" onclick=\"toggleDropdown()\" aria-expanded=\"false\" aria-haspopup=\"listbox\">"
},
"affectedUsers": ["motor-impaired", "blind"],
"confidence": 0.99,
"tool": "axe-core"
}
],
"recommendations": [
{
"id": "REC-001",
"title": "Add alt text to all images",
"description": "Review all images and add descriptive alt text. Use empty alt=\"\" for decorative images.",
"priority": "high",
"effort": "low",
"wcagCriteria": ["1.1.1"],
"relatedFindings": ["A11Y-001"],
"resources": [
{
"title": "W3C Alt Text Decision Tree",
"url": "https://www.w3.org/WAI/tutorials/images/decision-tree/"
}
]
},
{
"id": "REC-002",
"title": "Fix color contrast issues",
"description": "Update text colors to meet 4.5:1 contrast ratio for normal text and 3:1 for large text.",
"priority": "high",
"effort": "trivial",
"wcagCriteria": ["1.4.3"],
"relatedFindings": ["A11Y-002"],
"codeExample": "/* Before */\n.subtitle { color: #888888; }\n\n/* After */\n.subtitle { color: #595959; }"
},
{
"id": "REC-003",
"title": "Make custom controls keyboard accessible",
"description": "Replace custom div-based controls with native HTML elements or add proper ARIA roles and keyboard handling.",
"priority": "critical",
"effort": "medium",
"wcagCriteria": ["2.1.1"],
"relatedFindings": ["A11Y-003"]
}
],
"metrics": {
"totalElements": 245,
"imagesWithAlt": 8,
"imagesWithoutAlt": 3,
"formsWithLabels": 4,
"formsWithoutLabels": 1,
"colorContrastPasses": 42,
"colorContrastFails": 5,
"keyboardAccessible": 18,
"keyboardTraps": 0,
"videosWithCaptions": 1,
"videosWithoutCaptions": 0
}
},
"metadata": {
"executionTimeMs": 4523,
"toolsUsed": ["axe-core", "pa11y"],
"agentId": "qe-accessibility-auditor",
"targetUrl": "https://example.com",
"pagesAudited": 1,
"elementsAnalyzed": 245
},
"validation": {
"schemaValid": true,
"contentValid": true,
"confidence": 0.92
},
"learning": {
"patternsDetected": ["missing-alt-pattern", "low-contrast-text", "keyboard-inaccessible-control"],
"reward": 0.85
}
}
Related skills
FAQ
What does accessibility-testing do?
accessibility-testing is a Claude Code skill for testing & qa.
When should I use accessibility-testing?
When you need to helps with testing & qa tasks., or when accessibility-testing is a claude code skill for testing & qa.
What are the main capabilities?
accessibility-testing; Testing & QA; AI-coding skill.