Accessibility testing in CI/CD pipelines: catching WCAG violations before they ship
TL;DR
- Shift-left accessibility testing catches WCAG violations during development when fixes cost 10x less than production hotfixes.
- axe-core + Playwright is the strongest CI/CD option for ecommerce. It can test cart, checkout and account flows.
- Automated CI/CD tests catch 30-40% of WCAG violations. Combine with manual testing for full coverage.
- Start by failing builds on critical violations only. Tighten the threshold as your team fixes the backlog.
- GitHub Actions and GitLab CI examples included below, ready to copy.
Most ecommerce teams discover accessibility violations after they ship. A customer complains. A lawyer sends a demand letter. An audit reveals hundreds of WCAG failures across checkout, cart and product pages. Fixing violations in production is expensive, stressful and reactive.
CI/CD accessibility testing flips this. Every pull request, every deploy, every build runs automated WCAG checks. Violations are caught before they reach customers. Developers fix issues while the code is fresh in their minds. The cost per fix drops dramatically.
This guide covers how to set up automated accessibility testing in your CI/CD pipeline, which tools work best for ecommerce, how to handle the 30-40% automation ceiling and how to test the dynamic flows that make ecommerce uniquely challenging.
Why shift-left accessibility testing matters
The cost of fixing a defect increases exponentially as it moves through the development lifecycle. IBM Systems Sciences Institute and NIST data consistently show that a bug caught during development costs 1x to fix. The same bug caught in QA costs 5x. In production, it costs 10-30x. For accessibility violations specifically, the production cost includes legal exposure on top of engineering time.
In the US, ADA-related web accessibility lawsuits reached 3,117 federal filings in 2025, up 27% year over year. Ecommerce stores are the most targeted category. Settlements typically range from $5,000 to $25,000 per case, plus remediation costs. In the EU, the European Accessibility Act (EAA) took effect in June 2025 with fines up to 4% of revenue. These are not theoretical risks.
Shift-left testing means moving accessibility checks earlier in the pipeline. Instead of auditing after launch, you test during development. The specific stages:
- Component level. jest-axe tests individual React or Vue components as they are built. Catches missing labels, invalid ARIA and semantic issues before they reach a page.
- Page level. Playwright + axe-core tests full pages in a real browser during CI. Catches color contrast, heading hierarchy, focus management and layout issues.
- Flow level. Playwright scripts test multi-step ecommerce flows: add to cart, checkout, account management. Catches issues that only appear in specific application states.
- Deploy level. Post-deploy smoke tests run against staging or production URLs. Catches issues introduced by environment-specific configuration, CDN behavior or third-party scripts.
Each layer catches different issues. Together, they form a comprehensive automated safety net. For the full list of WCAG criteria relevant to ecommerce, see our WCAG 2.1 AA ecommerce checklist.
CI/CD tool comparison: axe-core, Pa11y CI, Lighthouse CI, cypress-axe, jest-axe
Five tools dominate CI/CD accessibility testing. Each has different strengths and trade-offs for ecommerce. For a broader comparison including browser extensions and enterprise platforms, see our accessibility testing tools comparison.
| Tool | Engine | Test type | Dynamic flows | Setup effort | Best for |
|---|---|---|---|---|---|
| @axe-core/playwright | axe-core | Integration | Full scripting | Medium | Ecommerce flows, SPAs |
| Pa11y CI | axe-core / HTML_CS | URL scanning | Puppeteer actions | Low | Batch URL testing |
| Lighthouse CI | axe-core subset | URL scanning | No | Low | Performance + a11y combo |
| cypress-axe | axe-core | Integration | Full scripting | Medium | Teams already on Cypress |
| jest-axe | axe-core | Unit / component | No (jsdom) | Low | Component testing |
@axe-core/playwright is the top recommendation for ecommerce. Playwright runs a real Chromium browser, handles JavaScript rendering and can script any user interaction. Add items to cart, navigate to checkout, fill forms, trigger error states. At each step, axe-core scans the live DOM. No other CI/CD tool matches this depth for ecommerce flow testing.
Pa11y CI is the simplest option. Give it a list of URLs, it scans them and reports violations. Good for content-heavy stores with many static pages. Limited for dynamic ecommerce flows unless you write Puppeteer action scripts.
Lighthouse CI combines accessibility with performance, SEO and best practices audits. Useful if you want one tool covering multiple quality dimensions. But its accessibility checks are a subset of axe-core, and it cannot test dynamic flows at all.
cypress-axe mirrors the axe-core/Playwright approach for teams already using Cypress. Cypress has strong ecommerce testing support and cy.checkA11y() integrates naturally into existing test suites.
jest-axe tests React components in isolation using jsdom. Fast, runs without a browser, catches missing labels and ARIA issues early. Cannot test color contrast, viewport behavior or real focus management because jsdom is not a visual rendering engine. Use it alongside, not instead of, browser-based testing.
GitHub Actions workflow with axe-core + Playwright
This workflow installs dependencies, starts your dev server, runs Playwright tests with axe-core accessibility assertions and uploads HTML reports as artifacts.
# .github/workflows/accessibility.yml
name: Accessibility Tests
on:
pull_request:
branches: [main]
push:
branches: [main]
jobs:
a11y:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
- run: npm ci
- run: npx playwright install --with-deps chromium
- name: Start dev server
run: npm run dev &
env:
PORT: 3000
- name: Wait for server
run: npx wait-on http://localhost:3000 --timeout 30000
- name: Run accessibility tests
run: npx playwright test --project=accessibility
- name: Upload report
if: always()
uses: actions/upload-artifact@v4
with:
name: a11y-report
path: playwright-report/
retention-days: 14The corresponding Playwright test file uses @axe-core/playwright to scan pages at each step of an ecommerce flow:
// tests/accessibility/checkout-flow.spec.ts
import { test, expect } from "@playwright/test";
import AxeBuilder from "@axe-core/playwright";
test.describe("Checkout flow accessibility", () => {
test("product page has no critical violations", async ({ page }) => {
await page.goto("/products/example-product");
const results = await new AxeBuilder({ page })
.withTags(["wcag2a", "wcag2aa"])
.analyze();
expect(results.violations.filter(
v => v.impact === "critical" || v.impact === "serious"
)).toHaveLength(0);
});
test("cart page has no critical violations", async ({ page }) => {
// Add item to cart first
await page.goto("/products/example-product");
await page.click("[data-testid='add-to-cart']");
await page.waitForURL("**/cart");
const results = await new AxeBuilder({ page })
.withTags(["wcag2a", "wcag2aa"])
.analyze();
expect(results.violations.filter(
v => v.impact === "critical" || v.impact === "serious"
)).toHaveLength(0);
});
test("checkout page has no critical violations", async ({ page }) => {
await page.goto("/products/example-product");
await page.click("[data-testid='add-to-cart']");
await page.waitForURL("**/cart");
await page.click("[data-testid='checkout-button']");
await page.waitForURL("**/checkout");
const results = await new AxeBuilder({ page })
.withTags(["wcag2a", "wcag2aa"])
.analyze();
expect(results.violations.filter(
v => v.impact === "critical" || v.impact === "serious"
)).toHaveLength(0);
});
});Key points in this setup. The withTags(["wcag2a", "wcag2aa"]) filter limits checks to WCAG 2.1 Level A and AA criteria, which is the standard compliance target. The violation filter only fails on critical and serious impacts, giving the team room to address moderate and minor issues without blocking deploys. For a complete picture of what WCAG criteria matter most for ecommerce, see the WCAG 2.1 AA ecommerce checklist.
GitLab CI example
The GitLab CI equivalent uses the same test code with GitLab-specific configuration:
# .gitlab-ci.yml
stages:
- test
accessibility:
stage: test
image: mcr.microsoft.com/playwright:v1.48.0-jammy
script:
- npm ci
- npm run dev &
- npx wait-on http://localhost:3000 --timeout 30000
- npx playwright test --project=accessibility
artifacts:
when: always
paths:
- playwright-report/
expire_in: 14 days
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCH == "main"The Playwright Docker image includes Chromium and all system dependencies. No additional browser installation step needed. The test code is identical to the GitHub Actions version.
For teams using GitLab's merge request pipelines, the rules block ensures accessibility tests run on every MR and on pushes to main. Reports are stored as GitLab artifacts and accessible from the pipeline page.
What to test automatically vs manually: the 30-40% reality
This is the most important concept in CI/CD accessibility testing. Automated tools detect approximately 30-40% of WCAG 2.1 AA violations. The rest require human judgment. Understanding which checks fall into which category prevents two common mistakes: over-relying on automation or dismissing it as insufficient.
| Automated (CI/CD) | Manual required |
|---|---|
| Missing alt attributes | Alt text quality and accuracy |
| Empty form labels | Label clarity and helpfulness |
| Color contrast ratios | Text over images / gradients |
| Duplicate element IDs | Logical reading order |
| Invalid ARIA attributes | ARIA communicates correct meaning |
| Missing document language | Focus order matches visual layout |
| Heading hierarchy violations | Keyboard trap detection |
| Missing skip navigation link | Screen reader experience |
| Autocomplete attributes | Touch target usability |
| Empty buttons and links | Cognitive load and clarity |
CI/CD catches the mechanical violations: things that can be verified by inspecting DOM attributes, CSS properties and HTML structure. Manual testing catches the experiential violations: whether the page actually works for someone using assistive technology. For practical guidance on the manual testing side, see our screen reader testing guide.
The 30-40% that automation catches is still immensely valuable. These are the violations that appear in every ADA lawsuit demand letter: missing alt text, unlabeled form fields, insufficient contrast. Catching them in CI/CD before they reach production eliminates the easiest attack surface.
Platform-specific setup: Shopify, WooCommerce, headless
Your ecommerce platform determines what CI/CD accessibility testing is possible and how to set it up. The three main categories have very different constraints.
Shopify: Theme Check + external CI scanning
Shopify stores cannot run locally in a traditional sense. You cannot start a Shopify server in your CI pipeline. This limits your options but does not eliminate them.
- Shopify Theme Check. Shopify's linter for Liquid templates catches some accessibility issues in theme code: missing alt attributes on images, missing form labels, improper heading order. Run it in CI with
shopify theme check. It is fast and catches template-level issues before they reach the store. - External scanning. Point Playwright at your development store URL (your-store.myshopify.com). The CI pipeline navigates the store and runs axe-core checks. Requires the development store to be accessible from CI runners. Password-protected stores need the password entered via Playwright before testing.
- Custom Liquid sections. If you build custom Liquid components, extract the HTML patterns and test them with jest-axe in isolation.
For the full list of Shopify-specific accessibility issues and fixes, see our Shopify accessibility guide.
WooCommerce: local WordPress + full CI control
WooCommerce runs on WordPress, which you can spin up locally or in CI using Docker. This gives you full CI/CD control.
# Docker Compose for WooCommerce CI testing
services:
wordpress:
image: wordpress:latest
ports:
- "8080:80"
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_NAME: wordpress
volumes:
- ./wp-content/themes/your-theme:/var/www/html/wp-content/themes/your-theme
db:
image: mysql:8.0
environment:
MYSQL_DATABASE: wordpress
MYSQL_ROOT_PASSWORD: testStart the containers in CI, install WooCommerce and your theme via WP-CLI, seed test products, then run Playwright against localhost:8080. This setup tests the complete WooCommerce experience including cart and checkout. For WooCommerce-specific issues, see our WooCommerce accessibility guide.
Headless commerce: full CI/CD control
Headless stores built with Next.js, Nuxt, Remix or similar frameworks have the easiest CI/CD story. The frontend is a standard web application. Start the dev server in CI, run Playwright against it, scan every page and flow.
The challenge with headless is different: because you control the entire frontend, you are responsible for all accessibility. No theme vendor to blame. Every ARIA label, every focus management pattern, every keyboard interaction is your code. CI/CD testing becomes even more critical because there is no fallback.
Mock the commerce API (Shopify Storefront API, commercetools, etc.) in your test environment so tests are fast, deterministic and do not depend on external services. For the unique accessibility challenges of headless architectures, see our headless commerce accessibility guide.
Setting violation thresholds and failing builds on regressions
The biggest question teams face: should accessibility violations fail the build? The answer is yes, but the implementation matters.
If you have an existing store with 200 violations and you set the threshold to zero, every build fails. The team ignores the failures. The tests become useless. Instead, use a ratchet approach:
- Baseline. Run a full scan of your current site. Record the number of critical, serious, moderate and minor violations per page.
- Initial threshold. Set the threshold at your current violation count. The build fails only if new violations are introduced.
- Tighten over time. Each sprint, reduce the threshold by the number of violations your team fixed. If you fixed 10 critical violations, lower the threshold by 10.
- Target: zero critical and serious. Moderate and minor violations should be tracked but may not need to block deploys initially.
// playwright.config.ts - custom threshold logic
import { defineConfig } from "@playwright/test";
export default defineConfig({
projects: [
{
name: "accessibility",
testDir: "./tests/accessibility",
use: {
// Custom fixture for violation thresholds
a11yThresholds: {
critical: 0, // Never allow critical violations
serious: 5, // Current baseline: reduce each sprint
moderate: 20, // Track but don't block (yet)
minor: null, // No threshold
},
},
},
],
});// tests/accessibility/helpers.ts
import AxeBuilder from "@axe-core/playwright";
import { Page, expect } from "@playwright/test";
interface Thresholds {
critical?: number | null;
serious?: number | null;
moderate?: number | null;
minor?: number | null;
}
export async function checkA11y(page: Page, thresholds: Thresholds = {}) {
const results = await new AxeBuilder({ page })
.withTags(["wcag2a", "wcag2aa"])
.analyze();
const counts = {
critical: results.violations.filter(v => v.impact === "critical").length,
serious: results.violations.filter(v => v.impact === "serious").length,
moderate: results.violations.filter(v => v.impact === "moderate").length,
minor: results.violations.filter(v => v.impact === "minor").length,
};
if (thresholds.critical !== null && thresholds.critical !== undefined) {
expect(counts.critical,
`Found ${counts.critical} critical a11y violations (threshold: ${thresholds.critical})`
).toBeLessThanOrEqual(thresholds.critical);
}
if (thresholds.serious !== null && thresholds.serious !== undefined) {
expect(counts.serious,
`Found ${counts.serious} serious a11y violations (threshold: ${thresholds.serious})`
).toBeLessThanOrEqual(thresholds.serious);
}
return results;
}This approach prevents regressions immediately while giving the team a realistic path to zero violations. The threshold numbers live in version control, making the accessibility commitment visible and measurable.
Testing dynamic ecommerce flows: cart, checkout, modals, filters
Static page scanning misses the majority of ecommerce accessibility issues. The checkout flow, cart interactions, product filtering and modal dialogs are where the most impactful violations hide. These are also the flows that generate the most ADA lawsuit complaints.
Cart interactions
The cart page is dynamic. Quantity changes, item removal, price updates and promo code application all modify the DOM without a full page reload. Each state change needs accessibility testing.
test("cart quantity update is accessible", async ({ page }) => {
// Navigate to cart with items
await page.goto("/products/example");
await page.click("[data-testid='add-to-cart']");
await page.goto("/cart");
// Scan initial cart state
let results = await new AxeBuilder({ page })
.withTags(["wcag2a", "wcag2aa"])
.analyze();
expect(results.violations.filter(
v => v.impact === "critical"
)).toHaveLength(0);
// Update quantity and scan again
await page.fill("[data-testid='quantity-input']", "3");
await page.click("[data-testid='update-cart']");
await page.waitForResponse("**/cart/update**");
results = await new AxeBuilder({ page })
.withTags(["wcag2a", "wcag2aa"])
.analyze();
expect(results.violations.filter(
v => v.impact === "critical"
)).toHaveLength(0);
});Checkout multi-step forms
Checkout typically has multiple steps: shipping address, shipping method, payment, review. Each step renders different form fields. Test each step independently.
test("checkout steps are accessible", async ({ page }) => {
// Setup: add item and go to checkout
await page.goto("/products/example");
await page.click("[data-testid='add-to-cart']");
await page.goto("/checkout");
// Step 1: Shipping address
const step1 = await new AxeBuilder({ page })
.withTags(["wcag2a", "wcag2aa"])
.analyze();
expect(step1.violations.filter(
v => v.impact === "critical" || v.impact === "serious"
)).toHaveLength(0);
// Fill shipping and proceed
await page.fill("#email", "test@example.com");
await page.fill("#firstName", "Test");
await page.fill("#lastName", "User");
await page.fill("#address1", "123 Test St");
await page.fill("#city", "New York");
await page.selectOption("#state", "NY");
await page.fill("#zip", "10001");
await page.click("[data-testid='continue-to-shipping']");
// Step 2: Shipping method
await page.waitForSelector("[data-testid='shipping-methods']");
const step2 = await new AxeBuilder({ page })
.withTags(["wcag2a", "wcag2aa"])
.analyze();
expect(step2.violations.filter(
v => v.impact === "critical" || v.impact === "serious"
)).toHaveLength(0);
});Modal dialogs
Product quick-view modals, size guides, shipping calculators and cookie consent dialogs all need focus trapping, proper ARIA roles and keyboard dismissal. Test the modal in its open state.
test("product quick-view modal is accessible", async ({ page }) => {
await page.goto("/collections/all");
await page.click("[data-testid='quick-view-trigger']");
await page.waitForSelector("[role='dialog']");
const results = await new AxeBuilder({ page })
.withTags(["wcag2a", "wcag2aa"])
.analyze();
expect(results.violations.filter(
v => v.impact === "critical" || v.impact === "serious"
)).toHaveLength(0);
});Product filters
Filtering by size, color, price or brand updates the product grid without a page reload. The new content needs to be announced to screen readers, and the filter controls themselves need to be accessible. Scan after each filter application.
Reporting: HTML reports, PR comments, Slack notifications
Running tests is only half the story. The results need to reach the right people in the right format.
HTML reports as CI artifacts
Playwright generates HTML reports by default. Configure it to include accessibility violation details:
// playwright.config.ts
export default defineConfig({
reporter: [
["html", { open: "never", outputFolder: "playwright-report" }],
["json", { outputFile: "a11y-results.json" }],
],
});Upload the playwright-report/ directory as a CI artifact. Team members can download and open the report in a browser to see violations with screenshots, DOM selectors and WCAG criteria references.
PR comments with violation summaries
Post a summary directly on the pull request so developers see violations without digging through CI logs. Use a custom reporter or a post-test script:
# .github/workflows/a11y-comment.yml (additional step)
- name: Post a11y summary to PR
if: github.event_name == 'pull_request' && always()
uses: actions/github-script@v7
with:
script: |
const fs = require("fs");
const results = JSON.parse(
fs.readFileSync("a11y-results.json", "utf8")
);
const violations = results.suites
.flatMap(s => s.specs)
.filter(s => s.ok === false);
if (violations.length === 0) {
const body = "**Accessibility check passed.** No new violations.";
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body,
});
} else {
const body = [
"**Accessibility check failed.** Found violations:",
"",
...violations.map(v =>
`- ${v.title}: ${v.tests[0]?.results[0]?.error?.message || "Failed"}`
),
"",
"See the [full report](link-to-artifact) for details.",
].join("\n");
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body,
});
}Slack notifications for critical violations
Send alerts to your team's Slack channel when critical accessibility violations are detected:
# Additional GitHub Actions step
- name: Notify Slack on a11y failure
if: failure()
uses: slackapi/slack-github-action@v1
with:
payload: |
{
"text": "Accessibility test failed on ${github.head_ref}",
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Accessibility violations detected*\nBranch: `${github.head_ref}`\nPR: <${github.event.pull_request.html_url}|#${github.event.pull_request.number}>"
}
}
]
}
env:
SLACK_WEBHOOK_URL: ${secrets.SLACK_WEBHOOK_URL}Critical violations should be loud. Moderate violations should be visible but not disruptive. Minor violations should be tracked in reports but not sent to Slack.
Common CI/CD accessibility testing mistakes
These are the patterns we see most often when auditing ecommerce store CI/CD setups:
| Mistake | Why it happens | Fix |
|---|---|---|
| Only testing the homepage | Simplest to set up | Test every page template: PDP, PLP, cart, checkout, account, search results |
| Ignoring dynamic content | Static scans are easier | Script interactions: open modals, apply filters, trigger AJAX updates, then scan |
| Not testing mobile viewport | CI defaults to desktop | Add a mobile project in Playwright config (375x667 viewport) |
| Treating automation as sufficient | Green CI feels complete | Schedule quarterly manual audits with keyboard and screen reader testing |
| Setting threshold to zero immediately | Ambition exceeds reality | Use the ratchet approach: baseline, then tighten |
| Not testing error states | Happy path bias | Submit forms with invalid data. Error messages need accessible associations. |
| Ignoring third-party scripts | Not your code | Third-party chat widgets, reviews and analytics can inject inaccessible elements. Test the full page. |
| No reporting or visibility | Tests run but no one checks | PR comments, Slack alerts, weekly summary reports to stakeholders |
The most damaging mistake is the first one: testing only the homepage. Ecommerce accessibility lawsuits almost always cite checkout barriers, not homepage issues. If your CI/CD pipeline only scans the homepage, it misses the pages that generate legal risk. Script the full purchase flow.
Combining CI/CD testing with production monitoring
CI/CD testing and production monitoring serve different purposes. CI/CD catches issues before deploy. Production monitoring catches issues that slip through: third-party script changes, CMS content updates, A/B test variants and CDN-level modifications.
A complete accessibility testing strategy uses both:
| Layer | When | What it catches | Tool |
|---|---|---|---|
| Component tests | Every commit | Missing labels, ARIA issues | jest-axe |
| Integration tests | Every PR | Page-level and flow violations | Playwright + axe-core |
| Deploy smoke tests | Every deploy | Environment-specific issues | Playwright + axe-core |
| Production monitoring | Weekly / daily | Third-party changes, CMS updates | Scheduled scans, Complyko |
| Manual audit | Quarterly | Screen reader, keyboard, cognitive | Human testers |
CI/CD tests run in a controlled environment. Production monitoring tests the real site as customers experience it. Third-party scripts are a major source of production-only accessibility violations. A chat widget update, a review platform change or a new analytics script can inject inaccessible elements that CI/CD never sees because those scripts are not present in the test environment.
Schedule production scans at least weekly. Run them against the same page templates your CI/CD tests cover: homepage, product pages, collection pages, cart, checkout. Compare production results against your CI/CD baseline to catch drift.
For the most impactful ecommerce flow to monitor, the checkout pipeline is the priority. See our ecommerce checkout accessibility guide for the specific WCAG criteria that matter most in the purchase flow.
Frequently asked questions
- Can automated CI/CD testing catch all WCAG accessibility violations?
- No. Automated tools in CI/CD pipelines catch approximately 30-40% of WCAG 2.1 AA violations. They reliably detect missing alt text, empty form labels, insufficient color contrast ratios and invalid ARIA attributes. The remaining 60-70% require manual testing with keyboards, screen readers and human judgment. CI/CD automation is a safety net, not a complete solution.
- Which CI/CD accessibility testing tool is best for ecommerce?
- axe-core with Playwright is the strongest option for ecommerce CI/CD testing. Playwright can script dynamic flows like adding items to cart, navigating checkout steps and filling forms. axe-core then scans the DOM at each step. This combination reaches page states that static scanners cannot access. See our full tool comparison for alternatives.
- How do I add accessibility testing to GitHub Actions?
- Create a workflow file that installs Node.js and Playwright, starts your dev server, then runs your Playwright test suite with @axe-core/playwright assertions. Tests that call checkA11y() will fail the build if critical or serious WCAG violations are found. A working example is included above.
- Should accessibility violations fail the CI/CD build?
- Yes, but with the right threshold. Start by failing builds only on critical violations. As your team fixes existing issues, tighten the threshold to include serious violations. Never allow new violations to ship. Use the ratchet approach described in this guide.
- How do I test ecommerce checkout accessibility in CI/CD?
- Use Playwright to script the full checkout flow: navigate to a product page, add to cart, proceed to checkout, fill shipping and payment forms. Run axe-core accessibility checks at each step. This requires a test environment with working products and a checkout that does not process real payments. See our checkout accessibility guide for what to test.
- What is the difference between Pa11y CI and axe-core with Playwright?
- Pa11y CI is a standalone URL-based scanner that tests a list of URLs and outputs results. It is simpler to set up but cannot easily test authenticated pages or dynamic flows. axe-core with Playwright integrates into your existing test suite and can test any page state including cart, checkout and account pages behind login.
- How do I test Shopify store accessibility in CI/CD?
- Shopify stores have limited CI/CD options because you cannot run Shopify locally. Use Shopify Theme Check for Liquid template linting, then run axe-core against your preview theme URL in CI. For full flow testing, point Playwright at your development store. See our Shopify accessibility guide for platform-specific issues.
- Can jest-axe replace Playwright accessibility testing?
- jest-axe tests rendered React components in jsdom, which is useful for component-level checks during development. However, jsdom does not run a real browser, so jest-axe cannot test CSS-dependent issues like color contrast, viewport behavior or real focus management. Use jest-axe for unit tests and Playwright with axe-core for integration tests. Both are complementary.
- How do I generate accessibility reports from CI/CD pipelines?
- axe-core and Pa11y both output JSON results. Use reporters to convert these to HTML reports and upload them as CI artifacts. For GitHub Actions, use actions/upload-artifact. Post summaries as PR comments using the GitHub API. Send critical violation alerts to Slack via webhooks.
- What accessibility issues should I test in CI/CD vs manually?
- CI/CD automated tests should cover: missing alt text, empty form labels, color contrast ratios, duplicate IDs, invalid ARIA, missing document language, heading hierarchy and keyboard focus indicators. Manual testing should cover: screen reader experience, logical reading order, focus trap behavior, alt text quality, touch target usability and cognitive load assessment.
Complyko scans your ecommerce store's cart and checkout flows using Playwright and axe-core. One scan covers WCAG accessibility, PCI DSS and privacy compliance. No CI/CD setup required: we handle the infrastructure.
Get your free scan →