mcpField
P
playwright-testing

playwright-testing

github.com/community-access测试与质量431316 次安装1 天前更新
代码仓库

关于 playwright-testing

面向使用 Playwright 的团队,提供浏览器无障碍测试参考与测试模板。涵盖键盘、动态状态、视口、对比度和无障碍树检查,并说明 axe-core 的使用方式。

主要功能

  1. 01键盘顺序与陷阱检测
  2. 02交互后页面状态扫描
  3. 03多视口与触控目标检查
  4. 04计算样式对比度扫描
  5. 05浏览器无障碍树快照

适用场景

  1. 01检查网页键盘导航和焦点管理
  2. 02验证弹窗及手风琴展开后的内容
  3. 03在 CI 中运行无障碍测试

MCP 相关

README 列出了可用的 MCP 工具,用于键盘扫描、状态扫描、视口扫描、对比度扫描和无障碍树快照。部分扫描需要 @axe-core/playwright。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/community-access/accessibility-agents --skill playwright-testing

安装后在 Claude Code 中输入/playwright-testing确认已加载。

详细介绍

Playwright 无障碍测试

使用 Playwright 和 @axe-core/playwright 进行基于浏览器的无障碍测试的可复用知识模块。

可用的 MCP 工具

工具用途是否需要 @axe-core/playwright
run_playwright_keyboard_scanTab 顺序遍历、键盘陷阱检测否
run_playwright_state_scan点击触发器,使用 axe-core 扫描显示的内容是
run_playwright_viewport_scan多视口 axe-core 扫描 + 触控目标测量是
run_playwright_contrast_scanCSS 级联后的计算样式对比度否
run_playwright_a11y_tree浏览器无障碍树快照否

@axe-core/playwright 模式

全页面扫描
import AxeBuilder from '@axe-core/playwright';

const results = await new AxeBuilder({ page })
  .withTags(['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa', 'wcag22aa'])
  .analyze();
指定范围的元素扫描
const results = await new AxeBuilder({ page })
  .include('.modal-content')
  .withTags(['wcag2a', 'wcag2aa'])
  .analyze();
单条规则验证
const results = await new AxeBuilder({ page })
  .include('#hero-image')
  .withRules(['image-alt'])
  .analyze();
expect(results.violations).toEqual([]);
交互后扫描
await page.click('[aria-expanded="false"]');
await page.waitForSelector('.accordion-content', { state: 'visible' });
const results = await new AxeBuilder({ page })
  .include('.accordion-content')
  .analyze();

键盘遍历模式

记录 Tab 顺序
const tabStops = [];
for (let i = 0; i < maxTabs; i++) {
  await page.keyboard.press('Tab');
  const info = await page.evaluate(() => {
    const el = document.activeElement;
    return {
      tagName: el?.tagName,
      role: el?.getAttribute('role'),
      name: el?.getAttribute('aria-label') || el?.textContent?.trim().slice(0, 50),
      id: el?.id,
      tabIndex: el?.tabIndex
    };
  });
  tabStops.push(info);
}
检测键盘陷阱

连续按下 Tab 后,若同一元素再次获得焦点,则检测到键盘陷阱:

let trapCount = 0;
let lastSelector = '';
for (const stop of tabStops) {
  const currentSelector = `${stop.tagName}#${stop.id}`;
  if (currentSelector === lastSelector) {
    trapCount++;
    if (trapCount >= 3) { /* TRAP DETECTED */ }
  } else {
    trapCount = 0;
  }
  lastSelector = currentSelector;
}
模态框打开后的焦点管理
await page.click('[data-modal-trigger]');
await page.waitForSelector('[role="dialog"]', { state: 'visible' });
const focusedRole = await page.evaluate(() =>
  document.activeElement?.closest('[role="dialog"]') ? 'inside-dialog' : 'outside-dialog'
);
// focusedRole should be 'inside-dialog'

焦点管理测试模板

模态框焦点陷阱测试
test('modal traps focus correctly', async ({ page }) => {
  await page.goto(url);
  await page.click('[data-open-modal]');
  await page.waitForSelector('[role="dialog"]', { state: 'visible' });

  // Focus should be inside the dialog
  const inDialog = await page.evaluate(() =>
    document.activeElement?.closest('[role="dialog"]') !== null
  );
  expect(inDialog).toBe(true);

  // Tab through dialog — should not escape
  for (let i = 0; i < 20; i++) {
    await page.keyboard.press('Tab');
    const stillInDialog = await page.evaluate(() =>
      document.activeElement?.closest('[role="dialog"]') !== null
    );
    expect(stillInDialog).toBe(true);
  }

  // Escape should close and return focus to trigger
  await page.keyboard.press('Escape');
  const focusedId = await page.evaluate(() => document.activeElement?.id);
  expect(focusedId).toBe('modal-trigger-id');
});
跳过链接测试
test('skip link moves focus to main content', async ({ page }) => {
  await page.goto(url);
  await page.keyboard.press('Tab'); // Focus skip link
  await page.keyboard.press('Enter'); // Activate it
  const focusedId = await page.evaluate(() => document.activeElement?.id);
  expect(focusedId).toBe('main-content');
});

CI 集成

使用 Playwright 的 GitHub Actions
name: Accessibility Tests
on: [push, pull_request]

jobs:
  a11y:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
      - run: npm ci
      - run: npx playwright install --with-deps chromium
      - name: Start dev server
        run: npm run dev &
        env:
          CI: true
      - name: Wait for server
        run: npx wait-on http://localhost:3000 --timeout 30000
      - name: Run accessibility tests
        run: npx playwright test tests/a11y/
      - uses: actions/upload-artifact@v4
        if: failure()
        with:
          name: a11y-test-results
          path: test-results/
无障碍测试的 Playwright 配置
// playwright.config.js (a11y section)
export default {
  testDir: './tests/a11y',
  use: {
    baseURL: process.env.BASE_URL || 'http://localhost:3000',
    // Use Chromium only — @axe-core/playwright is Chromium-validated
    browserName: 'chromium',
  },
  webServer: {
    command: 'npm run dev',
    url: 'http://localhost:3000',
    reuseExistingServer: !process.env.CI,
  },
};

优雅降级

检测模式
let _playwrightAvailable = null;
async function isPlaywrightAvailable() {
  if (_playwrightAvailable !== null) return _playwrightAvailable;
  try {
    await import('playwright');
    _playwrightAvailable = true;
  } catch {
    _playwrightAvailable = false;
  }
  return _playwrightAvailable;
}
降级矩阵
Playwright@axe-core/playwright可用扫描
是是全部 5 种工具(键盘、状态、视口、对比度、树)
是否3 种工具(键盘、对比度、树)
否—无 — 改用代码审查 + axe-core CLI
面向用户的消息

不可用时:

Playwright not installed. Behavioral testing (keyboard traversal, dynamic states,
responsive viewport, rendered contrast) is unavailable.

Install: npm install -D playwright @axe-core/playwright && npx playwright install chromium

部分可用时:

@axe-core/playwright not installed. State scanning and viewport scanning are
unavailable. Keyboard, contrast, and accessibility tree scans will proceed.

Install: npm install -D @axe-core/playwright

WCAG 覆盖范围映射

WCAG SC描述Playwright 工具
1.3.1信息和关系无障碍树、状态扫描
1.4.3对比度(最低)对比度扫描
1.4.6对比度(增强)对比度扫描
1.4.10重排视口扫描
2.1.1键盘键盘扫描
2.1.2无键盘陷阱键盘扫描
2.4.3焦点顺序键盘扫描
2.4.7焦点可见键盘扫描
2.5.5目标尺寸(增强)视口扫描
2.5.8目标尺寸(最低)视口扫描
4.1.2名称、角色、值无障碍树、状态扫描

评论

支持 Markdown