本文へ移動
cccskills
無料GitHub で公開

accessibility-selenium-testing

Accessibility testing toolkit using Selenium WebDriver 4+ with Java 21+ and axe-core engine. Use when asked to validate WCAG 2.1/2.2 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).

インストール方法を見る

含まれるファイル(2)

  • SKILL.md16.5 KB
  • source.json993 B

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

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

ComponentVersionPurpose
Java JDK21+Runtime with modern features
Maven3.9+Dependency management
Selenium WebDriver4.xBrowser automation
axe-core-selenium4.10+Deque axe-core integration
JUnit 55.10+Test framework
AssertJ3.xFluent assertions for readable failures
Allure2.xReporting with a11y violation attachments

Note: Use com.deque.html.axe-core:selenium Maven dependency for axe integration.


WCAG Compliance Levels

LevelRequirementLegal StatusAxe Tags
Level ABasic accessibility (must have)Minimum legal requirementwcag2a, wcag21a
Level AAIntermediate (should have)Legal requirement in most jurisdictionswcag2aa, wcag21aa
Level AAAAdvanced (nice to have)Not typically requiredwcag2aaa, wcag21aaa
Best PracticeIndustry recommendationsNot WCAG but improves UXbest-practice

Axe-Core Tools Reference

AxeBuilder Configuration

MethodPurposeExample
new AxeBuilder()Create scanner instanceEntry point
.withTags(List<String>)Filter by WCAG tagswcag2aa, wcag21aa
.include(String)Scan specific selector#main-content
.exclude(String)Skip selector from scan.third-party-widget
.disableRules(List<String>)Disable specific rulescolor-contrast
.withRules(List<String>)Run only specific ruleslabel, button-name
.analyze(WebDriver)Execute the scanReturns Results

Results Object

MethodReturnsPurpose
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()booleanTrue if no violations

Violation Impact Levels

ImpactSeverityCI Action
CriticalBlocks users completelyAlways fail build
SeriousSignificant barrierAlways fail build
ModerateSome difficultyWarn or fail
MinorInconvenienceLog for review

Core Capabilities

1. Axe Builder Analysis

  • Full Page Scan: new AxeBuilder().analyze(driver)
  • Component Scan: new AxeBuilder().include("#my-component").analyze(driver)
  • Rule Configuration: .withTags(List.of("wcag2a", "wcag2aa"))
  • Exclusions: .exclude(".legacy-footer") (use carefully, document reason)

2. Validation & Assertion

  • Analyze Results.getViolations() - should be empty
  • Filter by impact level (Critical, Serious, Moderate, Minor)
  • Use AssertJ Soft Assertions to report all violations before failing

3. Reporting

  • Log: Rule ID + Help URL + Selector for each violation
  • Serialize Results to JSON for dashboards
  • Attach to Allure reports

Your Role

As an Accessibility Automation Specialist:

  1. Integration: Configure axe-core with Selenium WebDriver
  2. Configuration: Set up AxeBuilder with appropriate WCAG tags
  3. Analysis: Parse results to identify violations by impact
  4. Assertion: Fail on Critical/Serious, warn on Moderate/Minor
  5. Reporting: Log Help URLs and selectors for remediation

Step-by-Step Workflows

Workflow 1: Add A11y Scan to Existing Test

  1. Add dependency to pom.xml

    <dependency>
        <groupId>com.deque.html.axe-core</groupId>
        <artifactId>selenium</artifactId>
        <version>4.10.0</version>
    </dependency>
    
  2. Create AccessibilityHelper utility

  3. Add scan after page loads

    driver.get("https://example.com");
    waitForPageReady();
    AccessibilityHelper.verifyPageAccessibility(driver);
    
  4. Run and review violations

    mvn test -Dtest=A11yTest
    

Workflow 2: Test Specific Component

  1. Navigate to page with component visible

  2. Trigger component state (open modal, show dropdown)

  3. Scan only the component

    Results results = new AxeBuilder()
        .withTags(List.of("wcag2a", "wcag2aa"))
        .include("#login-modal")
        .analyze(driver);
    
  4. Assert and log

Workflow 3: Keyboard Navigation Audit

  1. Identify all interactive elements
  2. Tab through the page programmatically
    element.sendKeys(Keys.TAB);
    WebElement focused = driver.switchTo().activeElement();
    
  3. Verify focus order is logical
  4. Test Escape closes modals
  5. Verify no keyboard traps

Workflow 4: CI Integration

  1. Configure headless browser

    mvn test -Dheadless=true -Dgroups=a11y
    
  2. Set zero-tolerance for Critical/Serious

    long criticalCount = violations.stream()
        .filter(v -> List.of("critical", "serious").contains(v.getImpact()))
        .count();
    assertThat(criticalCount).isZero();
    
  3. Generate JSON report for tracking


Code Patterns

Basic Full-Page Scan

@Step("Verify page accessibility - WCAG 2.1 AA")
public void verifyPageAccessibility(WebDriver driver) {
    Results results = new AxeBuilder()
        .withTags(List.of("wcag2a", "wcag2aa", "wcag21a", "wcag21aa"))
        .analyze(driver);

    logViolations(results.getViolations());

    assertThat(results.violationFree())
        .as("Accessibility violations found on: %s", driver.getCurrentUrl())
        .isTrue();
}

Component-Specific Scan

@Step("Verify component accessibility: {selectors}")
public void verifyComponentAccessibility(WebDriver driver, String... selectors) {
    AxeBuilder builder = new AxeBuilder()
        .withTags(List.of("wcag2a", "wcag2aa"));

    for (String selector : selectors) {
        builder.include(selector);
    }

    Results results = builder.analyze(driver);
    logViolations(results.getViolations());

    assertThat(results.violationFree())
        .as("Component accessibility check failed")
        .isTrue();
}

Filter by Impact Level

@Step("Verify no critical accessibility violations")
public void verifyCriticalViolations(WebDriver driver) {
    Results results = new AxeBuilder()
        .withTags(List.of("wcag2a", "wcag2aa"))
        .analyze(driver);

    List<Rule> criticalViolations = results.getViolations().stream()
        .filter(v -> List.of("critical", "serious").contains(v.getImpact()))
        .toList();

    if (!criticalViolations.isEmpty()) {
        logViolations(criticalViolations);
    }

    assertThat(criticalViolations)
        .as("Critical/Serious accessibility violations found")
        .isEmpty();
}

With Documented Exclusions

/**
 * Scan with exclusions for known issues.
 * Exclusions must be documented with ticket reference.
 */
@Step("Verify accessibility with documented exclusions")
public void verifyWithExclusions(WebDriver driver) {
    Results results = new AxeBuilder()
        .withTags(List.of("wcag2a", "wcag2aa"))
        .exclude(".third-party-chat-widget")  // JIRA-1234: Vendor limitation
        .exclude("#legacy-footer")            // JIRA-5678: Scheduled for Q2 fix
        .analyze(driver);

    assertThat(results.violationFree()).isTrue();
}

Violation Logger

private void logViolations(List<Rule> violations) {
    if (violations.isEmpty()) {
        log.info("✓ No accessibility violations found");
        return;
    }

    log.error("✗ Found {} accessibility violations:", violations.size());
    for (Rule violation : violations) {
        log.error("  [{}/{}] {}",
            violation.getImpact().toUpperCase(),
            violation.getId(),
            violation.getDescription());
        log.error("    Help: {}", violation.getHelpUrl());

        for (CheckedNode node : violation.getNodes()) {
            log.error("    Target: {}", String.join(", ", node.getTarget()));
            log.error("    HTML: {}", truncate(node.getHtml(), 100));
        }
    }
}

JUnit 5 Test Class

@Epic("Accessibility")
@Feature("WCAG 2.1 AA Compliance")
class AccessibilityTest extends BaseTest {

    @Test
    @Tag("a11y")
    @Severity(SeverityLevel.CRITICAL)
    @DisplayName("Homepage should meet WCAG 2.1 AA standards")
    void homePage_shouldBeAccessible() {
        driver.get(ConfigReader.get("base.url"));
        waitForPageReady();

        Results results = new AxeBuilder()
            .withTags(List.of("wcag2a", "wcag2aa", "wcag21a", "wcag21aa"))
            .analyze(driver);

        attachResultsToAllure(results);

        SoftAssertions.assertSoftly(softly -> {
            softly.assertThat(results.violationFree())
                .as("Page should have no accessibility violations")
                .isTrue();
        });
    }

    @Test
    @Tag("a11y")
    @DisplayName("Login modal should be keyboard accessible")
    void loginModal_shouldBeKeyboardAccessible() {
        driver.get(ConfigReader.get("base.url"));

        // Open modal
        driver.findElement(By.id("login-btn")).click();
        waitForVisible(By.id("login-modal"));

        // Scan modal only
        Results results = new AxeBuilder()
            .withTags(List.of("wcag2a", "wcag2aa"))
            .include("#login-modal")
            .analyze(driver);

        assertThat(results.violationFree()).isTrue();

        // Test keyboard navigation
        WebElement modal = driver.findElement(By.id("login-modal"));
        WebElement firstInput = modal.findElement(By.cssSelector("input:first-of-type"));

        assertThat(driver.switchTo().activeElement())
            .as("Focus should be inside modal")
            .isEqualTo(firstInput);

        // Test Escape closes modal
        modal.sendKeys(Keys.ESCAPE);
        assertThat(isDisplayed(By.id("login-modal"))).isFalse();
    }
}

Troubleshooting

ProblemCauseSolution
Axe returns empty resultsPage not fully loadedAdd explicit wait for page ready state
False positives on contrastDynamic themesTest both light and dark modes
Violations in third-party widgetsCannot modify vendor codeUse .exclude() with documented ticket
Incomplete rulesRequires manual reviewLog for manual audit, don't auto-fail
Different results between runsAsync content loadingEnsure deterministic page state before scan
CI fails but local passesDifferent viewport/browserUse same headless config as CI

Best Practices Checklist

✅ Wait for page ready - Ensure DOM is stable before axe analysis ✅ Scan unique states - Test modal open, form error, empty state separately ✅ Zero tolerance for Critical/Serious - Always fail CI on these ✅ Use specific tags - Define wcag2aa vs best-practice to reduce noise ✅ Log Help URLs - Developers need the link to fix issues ✅ Document exclusions - Every .exclude() needs a JIRA ticket ✅ Test keyboard navigation - Tab order, focus traps, Escape key ✅ Attach JSON reports - Enable tracking violations over time ✅ Combine with manual audit - Axe catches ~30-50% of issues


Guardrails (Important Limitations)

⚠️ Automated tooling cannot prove full WCAG conformance - only the presence of certain issues ⚠️ Use automation to prevent regressions - use manual audits for complete coverage ⚠️ Prefer native HTML semantics - use ARIA only when required ⚠️ Never disable rules globally - scope exceptions narrowly with documentation


Triage by POUR Principles

PrincipleFocus AreasCommon Violations
PerceivableText alternatives, captions, contrast, structureMissing alt text, low contrast, missing labels
OperableKeyboard access, focus order, bypass blocksKeyboard traps, no skip link, focus not visible
UnderstandableLabels, predictable behavior, error handlingUnclear instructions, unexpected changes
RobustValid HTML, ARIA, name/role/valueInvalid ARIA, duplicate IDs, missing roles

Running Tests

Maven Commands

CommandPurpose
mvn test -Dgroups=a11yRun all accessibility tests
mvn test -Dtest=A11yTestRun specific test class
mvn test -Dheadless=trueRun headless (CI mode)
mvn allure:serveView 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/

Common Rationalizations

Common shortcuts and "good enough" excuses that erode test quality — and the reality behind each.

RationalizationReality
"Selenium isn't good for a11y testing"axe-core + Selenium is battle-tested, CI-ready, and covers WCAG violations programmatically.
"We can just run a scan at the end"Shift-left: catch violations as code is written. Late scans mean expensive fixes.
"The framework handles accessibility"No framework auto-generates proper ARIA roles, labels, or keyboard interactions.
"We only need to test the homepage"Every page a user visits must be accessible. Start with high-risk pages, expand coverage.
"Skip the contrast checks, designers fix that"Automated contrast checks take seconds and prevent lawsuits. They are tests, not design reviews.
"Our users don't have disabilities"~15% of the global population has some form of disability. Accessibility is for everyone.

References


Quick Reference

TaskCode Pattern
Full page scannew AxeBuilder().withTags(List.of("wcag2aa")).analyze(driver)
Component scannew AxeBuilder().include("#selector").analyze(driver)
Exclude elementnew AxeBuilder().exclude(".ignore").analyze(driver)
Check violationsresults.getViolations().isEmpty()
Filter critical.filter(v -> v.getImpact().equals("critical"))
Get help URLviolation.getHelpUrl()
Tab navigationelement.sendKeys(Keys.TAB)
Get focused elementdriver.switchTo().activeElement()

Verification

After completing this skill's workflow, confirm:

  • Axe WebDriver audit passes — AxeBuilder.analyze(driver) returns zero violations
  • WCAG 2.1 AA compliance — All rules for AA level pass
  • ARIA labels present — All interactive elements have accessible names
  • Keyboard accessibility verified — Tab navigation reaches all interactive elements
  • Violation report saved — Accessibility results written to JSON/HTML file
  • Tests pass with Java 21+ — mvn test -Dtest=*Accessibility* passes

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

同じリポジトリのスキル

概要と使いどころ

007

無料

Security audit, hardening, threat modeling (STRIDE/PASTA), Red/Blue Team, OWASP checks, code review, incident response, and infrastructure security for any project.

日本語の概要は準備中です。原文の説明を表示しています。

aibot88/sec_skill_store42026年5月27日 更新

Guides the creation of agile user stories and Gherkin feature files. Use when the user wants to create a user story, write acceptance criteria, define Gherkin scenarios, or author BDD feature files. This should trigger for requests such as Create a user story; Write a user story; I need to write a user story. Part of cursor-rules-java project

日本語の概要は準備中です。原文の説明を表示しています。

aibot88/sec_skill_store42026年5月27日 更新

Facilitates conversational discovery to create Architectural Decision Records (ADRs) for non-functional requirements using the ISO/IEC 25010:2023 quality model. Use when the user wants to document quality attributes, NFR decisions, security/performance/scalability architecture, or design systems with measurable quality criteria. This should trigger for requests such as Create ADR for Non-functional requirements; Document Non-functional requirements; Capture Non-functional requirements; Generate Non-functional requirements in an ADR. Part of cursor-rules-java project

日本語の概要は準備中です。原文の説明を表示しています。

aibot88/sec_skill_store42026年5月27日 更新

Run a health check on an existing project: dependency audit, security scan, test runner detection, CI/CD evaluation, and missing configuration analysis. Maps the three execution gates (pre/in/post) from /10x-bootstrapper to an assessment framework for existing codebases. Reads optional context/foundation/stack-assessment.md from /10x-stack-assess to focus checks on identified gaps. Writes context/foundation/health-check.md with findings, prioritized fixes, and an agent-readiness verdict. Use when the user has an existing project and wants to verify its health before working with an agent. Trigger phrases: "health check", "check my project", "audit my project", "is my project healthy", "sprawdź projekt", "audyt projektu", "health-check", "project health". Use AFTER /10x-stack-assess (brownfield chain), BEFORE agent onboarding (m1-l4).

日本語の概要は準備中です。原文の説明を表示しています。

aibot88/sec_skill_store42026年5月27日 更新

10x-team

無料

You MUST use this when building projects end-to-end. Orchestrates all 12 team roles — automatically switches between CTO, architect, PM, engineers, SRE, security, DBA, QA, and EM based on the current phase of work. Starts with brainstorming before any implementation.

日本語の概要は準備中です。原文の説明を表示しています。

aibot88/sec_skill_store42026年5月27日 更新

Use when you need to add or configure Maven plugins in your pom.xml — including quality tools (enforcer, surefire, failsafe, jacoco, pitest, spotbugs, pmd), security scanning (OWASP), code formatting (Spotless), version management, container image build (Jib), build information tracking, and benchmarking (JMH) — through a consultative, modular step-by-step approach that only adds what you actually need. This should trigger for requests such as Add Maven plugins in pom.xml; Improve Maven plugins in pom.xml. Part of cursor-rules-java project

日本語の概要は準備中です。原文の説明を表示しています。

aibot88/sec_skill_store42026年5月27日 更新

aibot88 のスキルをすべて見る

このスキルの問題を報告する