首页 / Playwright 入门教程 / 可访问性测试 Accessibility

Playwright 入门教程

可访问性测试 Accessibility

本教程共 59 篇 · 第 51 篇 · 更新于 2026-08-04 · 约 8 分钟阅读

Playwright可访问性Accessibilityaxeaxe-coreWCAG无障碍测试

51. 可访问性测试 Accessibility

本节目标:学完你能把无障碍检查接进 Playwright 测试,自动抓出颜色对比、缺标签、重复 id 这类常见问题。

可访问性(accessibility,常缩写为 a11y)讲的是:残障用户能不能用好你的网站。自动测试抓不了全部,但能拦下不少低级错误——比如文字和背景对比太低、按钮没标签、重复 id 把辅助技术搞晕。

Note

自动化只能发现一部分问题。完整的覆盖还要靠人工评估和无障碍用户实测。Playwright 官方推荐配 Accessibility Insights for Web 一起用。

靠哪个引擎

Playwright 自己不带无障碍引擎,它接的是社区成熟的 axe(由 Deque 出品)。装这个包就能用:

npm install -D @axe-core/playwright

扫整页

写法和普通 Playwright 测试没两样:导航、调用 AxeBuilder.analyze() 扫描、再用断言看有没有违规。

import { test, expect } from '@playwright/test';
import AxeBuilder from '@axe-core/playwright';

test.describe('homepage', () => {
  test('should not have any automatically detectable accessibility issues', async ({ page }) => {
    await page.goto('https://your-site.com/');

    const accessibilityScanResults = await new AxeBuilder({ page }).analyze();

    expect(accessibilityScanResults.violations).toEqual([]);
  });
});

violations 是数组,空数组就表示没发现问题。断言一失败,里面会列出每条违规的细节。

只扫页面某块

用 Builder 模式的 include(),把扫描范围缩到某个区域。比如先点开导航菜单,等它出现,再扫它:

test('navigation menu should not have violations', async ({ page }) => {
  await page.goto('https://your-site.com/');
  await page.getByRole('button', { name: 'Navigation Menu' }).click();

  // 先等元素出现,再扫,否则 axe 可能扫不到
  await page.locator('#navigation-menu-flyout').waitFor();

  const results = await new AxeBuilder({ page })
    .include('#navigation-menu-flyout')
    .analyze();

  expect(results.violations).toEqual([]);
});
Tip

analyze() 扫的是「当下」的页面状态。动态出现的内容,先交互、等它稳定,再调 analyze()

按 WCAG 标签筛

axe 的规则很多,有些对应 WCAG 标准,有些只是「最佳实践」。想只查 WCAG A/AA 级,用 withTags()

test('should not have WCAG A or AA violations', async ({ page }) => {
  await page.goto('https://your-site.com/');

  const results = await new AxeBuilder({ page })
    .withTags(['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa'])
    .analyze();

  expect(results.violations).toEqual([]);
});
Warning

自动化测不出所有 WCAG 违规。标签筛只是收窄范围,不代表「过了就合规」。

处理已知问题

真实项目常有暂时修不了的老问题。三种压制办法:

排除某个元素:用 exclude() 把它和它所有子节点踢出扫描。简单,但会顺带关掉所有规则,慎用于子节点多的组件。

const results = await new AxeBuilder({ page })
  .exclude('#element-with-known-issue')
  .analyze();

关掉某条规则:问题遍布全站、且都属同一条规则,用 disableRules() 临时关:

const results = await new AxeBuilder({ page })
  .disableRules(['duplicate-id'])
  .analyze();

用快照允许特定问题:想更精细,别直接 toMatchSnapshot() 整个 violations(那里面有渲染 HTML 片段,组件一改就碎)。改成只快照「指纹」:

function violationFingerprints(scanResults) {
  return JSON.stringify(
    scanResults.violations.map(v => ({
      rule: v.id,
      targets: v.nodes.map(n => n.target),
    })),
    null, 2
  );
}

expect(violationFingerprints(accessibilityScanResults)).toMatchSnapshot();

把扫描结果存为附件

想调试「为什么没扫到预期的违规」,把完整结果作为测试附件挂上,报告里就能看:

test('example with attachment', async ({ page }, testInfo) => {
  await page.goto('https://your-site.com/');
  const results = await new AxeBuilder({ page }).analyze();

  await testInfo.attach('accessibility-scan-results', {
    body: JSON.stringify(results, null, 2),
    contentType: 'application/json',
  });

  expect(results.violations).toEqual([]);
});

用 fixture 复用配置

很多测试要用同一套 axe 配置?扩展一个 test,把 withTagsexclude 预先配好:

// axe-test.ts
import { test as base } from '@playwright/test';
import AxeBuilder from '@axe-core/playwright';

type AxeFixture = { makeAxeBuilder: () => AxeBuilder };

export const test = base.extend<AxeFixture>({
  makeAxeBuilder: async ({ page }, use) => {
    const makeAxeBuilder = () => new AxeBuilder({ page })
      .withTags(['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa'])
      .exclude('#commonly-reused-element-with-known-issue');
    await use(makeAxeBuilder);
  },
});

export { expect } from '@playwright/test';

用的时候直接取这个夹具:

import { test, expect } from './axe-test';

test('example using custom fixture', async ({ page, makeAxeBuilder }) => {
  await page.goto('https://your-site.com/');
  const results = await makeAxeBuilder()
    .include('#specific-element-under-test')
    .analyze();
  expect(results.violations).toEqual([]);
});

什么时候该用

每次页面结构大改、或加新组件时跑一遍无障碍扫描,能提前挡掉一大批硬伤。把它当「质量门禁」接进 CI 最划算。但记住:自动过不等于真无障碍,关键路径还是得人工和无障碍用户实测。

小结

这章把 @axe-core/playwright 接进测试,用 AxeBuilder 扫整页或局部,按 WCAG 标签筛规则。已知问题可以排除元素、关规则、或者只快照「指纹」避免报告脆弱。几个注意点:动态内容先交互再扫,exclude() 会关掉该节点下所有规则,别图省事滥用。自动扫描只是底线,别拿它当无障碍的终点。