@a11y-oracle/cypress-plugin

中文文档
1.3.2发布于 2026/03/12MITTypeScriptES Module近 30 天下载 2479

Cypress 自定义的可访问语音断言命令,带有 iframare-aware CDP 路由

中文使用文档
文档目录31 节
  1. 安装
  2. 设置
  3. 1. 进口命令
  4. 2. 配置浏览器
  5. 使用量
  6. 发言请求
  7. 统一国家(言论+焦点+指标)
  8. 标签顺序和键盘陷阱检测
  9. 问题报告
  10. 节点系统报告设置
  11. 使用地标和结构
  12. 结构化演讲结果
  13. 配置选项
  14. API 参考
  15. 语音命令
  16. 国家统一指挥部
  17. 报告命令
  18. CDP 适应器
  19. 生命周期
  20. 类型
  21. 如何运作
  22. Cypress Iframe 架构
  23. CDP 流量
  24. 类型脚本
  25. 已知的限制
  26. CDP 长期试验服中的资源积累
  27. 解决问题
  28. "无法找到AUT Iframe"
  29. 语音输出包含 Cypress UI 元素
  30. 空语音字符串
  31. 重点指标显示 contrastRatio: null

@a11y- oracle/ cypress- plugin (韩语)

A11y-Oracle的 Cypress 集成 . 提供自定义命令,通过Chrome DevTools协议读取浏览器的可访问性树,发送本地键盘事件,并分析视觉焦点指标.

describe('Navigation', () => {
  beforeEach(() => {
    cy.visit('/dropdown-nav.html');
    cy.initA11yOracle();
  });

  afterEach(() => {
    cy.disposeA11yOracle();
  });

  it('Tab to button announces name and role', () => {
    cy.a11yPress('Tab')
      .should('contain', 'Home')
      .and('contain', 'menu item');
  });
});

安装

npm install -D @a11y-oracle/cypress-plugin @a11y-oracle/core-engine cypress

仅铬/铬. 该插件使用CDP,它只在Chrome-family浏览器中提供.

QQ稳定通知——剧作家推荐. Cypress插件具有功能性,但已经知道带有大型测试套件的稳定性限制. 我们建议使用 @a11y-oracle/playwright-plugin 对于最可靠的经验。 见 已知的限制 详情见下文.

设置

1. 进口命令

将插件添加到您的 Cypress 支持文件 :

// cypress/support/e2e.ts (or cypress/support/e2e.js)
import '@a11y-oracle/cypress-plugin';

就是这样。 正在自动导入包登记所有自定义命令 .

2. 配置浏览器

保证您的 Cypress 配置在 Chrome 中运行测试 :

// cypress.config.ts
import { defineConfig } from 'cypress';

export default defineConfig({
  e2e: {
    baseUrl: 'http://localhost:4200',
    specPattern: 'cypress/e2e/**/*.cy.ts',
    supportFile: 'cypress/support/e2e.ts',
  },
});

与 Chrome 运行 :

npx cypress run --browser chrome

使用量

发言请求

describe('My Form', () => {
  beforeEach(() => {
    cy.visit('/form.html');
    cy.initA11yOracle();
  });

  afterEach(() => {
    cy.disposeA11yOracle();
  });

  it('Tab navigates to submit button', () => {
    cy.a11yPress('Tab');
    cy.a11yPress('Tab');
    cy.a11yPress('Tab')
      .should('equal', 'Submit, button');
  });

  it('checkbox announces checked state', () => {
    cy.a11yPress('Tab');
    cy.a11yPress('Space')
      .should('contain', 'checkbox')
      .should('contain', 'checked');
  });
});

统一国家(言论+焦点+指标)

it('Tab returns unified accessibility state', () => {
  cy.a11yPressKey('Tab').then((state) => {
    // Speech
    expect(state.speech).to.contain('Submit');
    expect(state.speechResult?.role).to.equal('button');

    // Focused element
    expect(state.focusedElement?.tag).to.equal('BUTTON');
    expect(state.focusedElement?.id).to.equal('submit-btn');

    // Focus indicator (WCAG 2.4.12 AA)
    expect(state.focusIndicator.isVisible).to.be.true;
    expect(state.focusIndicator.meetsWCAG_AA).to.be.true;
  });
});

it('Shift+Tab navigates backward', () => {
  cy.a11yPressKey('Tab');
  cy.a11yPressKey('Tab');
  cy.a11yPressKey('Tab', { shift: true }).then((state) => {
    expect(state.focusedElement).to.not.be.null;
  });
});

标签顺序和键盘陷阱检测

it('page has correct tab order', () => {
  cy.a11yTraverseTabOrder().then((report) => {
    expect(report.totalCount).to.be.greaterThan(0);
    expect(report.entries[0].tag).to.equal('A');
  });
});

it('modal does not trap keyboard focus', () => {
  cy.a11yTraverseSubTree('#modal-container', 20).then((result) => {
    expect(result.isTrapped).to.be.false;
    expect(result.escapeElement).to.not.be.null;
  });
});

问题报告

检查焦点指标和键盘陷阱,自动报告问题。 问题通过 cy.task('logOracleIssues') 并且可以在运行结束时写入JSON报告.

describe('Accessibility audit', () => {
  beforeEach(() => {
    cy.visit('/my-page.html');
    cy.initA11yOracle();
  });

  afterEach(() => {
    cy.disposeA11yOracle();
  });

  it('focus indicators pass oracle rules', () => {
    cy.a11yPressKey('Tab');
    cy.a11yCheckFocusAndReport();   // checks + reports issues

    cy.a11yPressKey('Tab');
    cy.a11yCheckFocusAndReport();   // check each focused element
  });

  it('modal is not a keyboard trap', () => {
    cy.get('#open-modal').click();
    cy.a11yCheckTrapAndReport('#modal-dialog', 10);
  });
});

WCAG 级别和规则配置

通过 WCAG 兼容级别过滤出问题或通过 Cypress env 禁用特定规则:

// cypress.config.ts
export default defineConfig({
  e2e: {
    env: {
      wcagLevel: 'wcag21aa',                       // WCAG 2.1 Level AA (default: 'wcag22aa')
      disabledRules: ['oracle/positive-tabindex'],  // Suppress specific rules
    },
  },
});

支助 wcagLevel 值( 匹配轴- 核心标记格式) :

  • 'wcag2a' 编号 : 'wcag2aa' - WCAG 2.0
  • 'wcag21a' 编号 : 'wcag21aa' - 《世界保护法院规约》2.1
  • 'wcag22a' 编号 : 'wcag22aa' - WCAG 2.2(违约)

或覆盖每个命令 :

cy.a11yCheckFocusAndReport({ wcagLevel: 'wcag22a' });
cy.a11yCheckFocusAndReport({ disabledRules: ['oracle/focus-low-contrast'] });

设定 Cypress.env('failOnErrors') 改为 true 在发现问题时立即失败的测试:

// cypress.config.ts
export default defineConfig({
  e2e: {
    env: { failOnErrors: true },
  },
});

关于每项规则的详细补救指导意见,见 补救指南。 。 。 .

节点系统报告设置

在所有层面累积问题并编写 JSON 报告文件, 调用 setupOracleReporting() 在您的 Cypress 配置中 :

// cypress.config.ts
import { defineConfig } from 'cypress';
import { setupOracleReporting } from '@a11y-oracle/cypress-plugin';

export default defineConfig({
  e2e: {
    setupNodeEvents(on, config) {
      setupOracleReporting(on, config);
    },
    env: { projectName: 'my-app' },
  },
});

登记 logOracleIssues 任务和写入 oracle-results-{projectName}.json 运行完成后.

与轴心侵犯行为相结合: 如果您想要在与您的轴- 核心违反相同的阵列中出现甲骨文问题( 仅上传到灯塔), 请手动添加任务处理器 :

setupNodeEvents(on, config) {
  const allViolations: any[] = [];

  on('task', {
    logAxeViolations(violations) { allViolations.push(...violations); return null; },
    logOracleIssues(issues) { allViolations.push(...issues); return null; },
  });

  on('after:run', () => {
    if (allViolations.length > 0) {
      fs.writeFileSync('a11y-results.json', JSON.stringify(allViolations, null, 2));
    }
  });
},

使用地标和结构

使用 getA11yFullTreeSpeech() 检查没有焦点的元素:

it('navigation landmark exists', () => {
  cy.getA11yFullTreeSpeech().then((tree) => {
    const nav = tree.find(r => r.speech.includes('navigation landmark'));
    expect(nav).to.exist;
    expect(nav.speech).to.contain('Main');
  });
});

结构化演讲结果

使用 getA11ySpeechResult() 访问语音输出的各个部分:

it('returns structured data', () => {
  cy.a11yPress('Tab');
  cy.getA11ySpeechResult().then((result) => {
    expect(result).to.not.be.null;
    expect(result.name).to.equal('Home');
    expect(result.role).to.contain('menu item');
    expect(result.states).to.be.an('array');
    expect(result.rawNode).to.exist;
  });
});

配置选项

将选项传递到 initA11yOracle() 自定义行为 :

// Include descriptions from aria-describedby
cy.initA11yOracle({ includeDescription: true });

// Disable "landmark" suffix on landmark roles
cy.initA11yOracle({ includeLandmarks: false });

// Adjust focus settle delay for slow CSS transitions
cy.initA11yOracle({ focusSettleMs: 100 });
选项类型默认说明
includeLandmarksbooleantrue在标志性角色中添加"地印"
includeDescriptionbooleanfalse包含 aria-describedby 输出中的文本
focusSettleMsnumber50在按下焦点/ CSS 键后延迟

API 参考

语音命令

cy.initA11yOracle(options?)

初始化插件 。 必须在之后调用 cy.visit() 在A11y-Oracle命令之前 典型的调用 beforeEach()。 。 。 .

启用 CDP 域,发现 AUT iframe,创建语音引擎和管弦乐器.

cy.a11yPress(key)

通过 CDP 按下键盘键,并返回新聚焦元素的语音. Yi取一弦.

cy.a11yPress('Tab').should('contain', 'button');
cy.a11yPress('Enter').should('contain', 'expanded');
cy.a11yPress('Escape').should('contain', 'collapsed');

支持的密钥 : Tab, (中文(简体) ), Enter, (中文(简体) ), Space, (中文(简体) ), Escape, (中文(简体) ), ArrowUp, (中文(简体) ), ArrowDown, (中文(简体) ), ArrowLeft, (中文(简体) ), ArrowRight, (中文(简体) ), Home, (中文(简体) ), End, (中文(简体) ), Backspace, (中文(简体) ), Delete。 。 。 .

cy.getA11ySpeech()

获取当前焦点元素的语音字符串而不按键 。 Yi取一弦.

cy.getA11ySpeechResult()

获取焦点元素的全部结构化结果. 也门 SpeechResult | null。 。 。 .

cy.getA11yFullTreeSpeech()

在无障碍树上获取所有非被忽略的节点的语音. 也门 SpeechResult[]。 。 。 .

国家统一指挥部

cy.a11yPressKey(key, modifiers?)

通过本地 CDP 发送按下一个密钥,并返回统一无障碍状态. 也门 A11yState。 。 。 .

cy.a11yPressKey('Tab').then((state) => {
  expect(state.speech).to.contain('button');
  expect(state.focusIndicator.meetsWCAG_AA).to.be.true;
});

// With modifier keys
cy.a11yPressKey('Tab', { shift: true }).then((state) => {
  expect(state.focusedElement).to.not.be.null;
});

cy.a11yState()

在不按键的情况下获得当前统一无障碍状态. 也门 A11yState。 。 。 .

cy.get('#my-button').focus();
cy.a11yState().then((state) => {
  expect(state.speech).to.contain('Submit');
});

cy.a11yTraverseTabOrder()

在 DOM 标签顺序中提取所有可制表元素 。 也门 TabOrderReport。 。 。 .

cy.a11yTraverseTabOrder().then((report) => {
  expect(report.totalCount).to.be.greaterThan(0);
});

cy.a11yTraverseSubTree(selector, maxTabs?)

检测容器是否夹住键盘焦点(WCAG 2.1.2)。 也门 TraversalResult。 。 。 .

cy.a11yTraverseSubTree('#modal', 20).then((result) => {
  expect(result.isTrapped).to.be.false;
});

报告命令

cy.a11yCheckFocusAndReport(context?)

检查当前重点要素,并通过 cy.task('logOracleIssues')。运行所有基于州的规则: oracle/focus-not-visible, (中文(简体) ), oracle/focus-low-contrast, (中文(简体) ), oracle/focus-missing-name, (中文(简体) ), oracle/focus-generic-role,以及 oracle/positive-tabindex。 。 。 .

  • context - 可选 Partial<AuditContext>默认为 { project: Cypress.env('projectName'), specName: Cypress.spec.name, wcagLevel: Cypress.env('wcagLevel'), disabledRules: Cypress.env('disabledRules') }。 。 。 .

cy.a11yCheckTrapAndReport(selector, maxTabs?, context?)

检查一个容器中的键盘陷阱并报告任何问题 cy.task('logOracleIssues')。 。 。 .

  • selector 用于测试容器的CSS选择器.
  • maxTabs ——最大标签在宣布陷阱前按下. 默认 50。 。 。 .
  • context - 可选 Partial<AuditContext>。 。 。 .

setupOracleReporting(on, config)

节点侧函数(不是 Cypress 命令). 进来吧 setupNodeEvents() 登记 logOracleIssues 任务和撰写 JSON 报告 after:run。见 节点系统报告设置。 。 。 .

import { setupOracleReporting } from '@a11y-oracle/cypress-plugin';

CDP 适应器

createCypressCDPAdapter()

创建现成的使用 CDPSessionLike 用于自定义集成的适配器. 当您需要打电话时,这个是有用的 @a11y-oracle/axe-bridge是因为 resolveAllIncomplete() 直接而不是使用内置 Cypress 命令.

该函数囊括所有 CDP 管道:

  • 启用 DOM.enable 财务报告和审定财务报表 Page.enable CDP 域数
  • 发现 AUT 框架 ID 从 Page.getFrameTree
  • 在 AUT 框架中创建孤立的世界执行上下文
  • 检测到 Iframe 位置和 CSS 变换规模
  • 回返a CDPSessionLike 具有规模意识的适配器 Page.captureScreenshot 坐标翻译
import { createCypressCDPAdapter } from '@a11y-oracle/cypress-plugin';
import { resolveAllIncomplete } from '@a11y-oracle/axe-bridge';

// In your custom Cypress command:
cy.wrap(null).then(async () => {
  const cdp = await createCypressCDPAdapter();
  const resolved = await resolveAllIncomplete(cdp, axeResults, options);
});

生命周期

cy.disposeA11yOracle()

处理插件并释放 CDP 资源. 典型的调用 afterEach()。 。 。 .

类型

类型从 @a11y-oracle/core-engine 财务报告和审定财务报表 @a11y-oracle/audit-formatter数字 :

import type {
  // Core engine types
  CDPSessionLike,
  SpeechResult,
  A11yState,
  A11yFocusedElement,
  A11yFocusIndicator,
  A11yOrchestratorOptions,
  ModifierKeys,
  TabOrderReport,
  TabOrderEntry,
  TraversalResult,
  FocusIndicator,
  // Audit formatter types
  OracleIssue,
  OracleNode,
  OracleCheck,
  OracleImpact,
  OracleResultType,
  AuditContext,
} from '@a11y-oracle/cypress-plugin';

如何运作

Cypress 插件使用浏览器侧式 CDP 方法通过 Cypress.automation('remote:debugger:protocol') - 与下列情况相同的模式: cypress-real-events 活动。需要节点边任务或外部库.

Cypress Iframe 架构

Cypress在测试(AUT)下运行该应用在其跑取页内的iframe内. 这造成了挑战: CDP 命令默认瞄准跑者页面,而不是AUT. 插件以透明方式处理 :

  1. 框架发现 - 打开 initA11yOracle(),插件调用 Page.getFrameTree() 以列举所有框架。 它通过过滤出 Cypress 内部帧来识别 AUT 框架(/__/, (中文(简体) ), __cypress, (中文(简体) ), about:blank) (中文(简体) ).

  2. 框架范围访问 —— CDP 适配器注入 AUT frameId 输入 Accessibility.getFullAXTree() 调用,确保无障碍树被范围化为应用,而不是跑取UI.

  3. 孤立的执行背景 为: Runtime.evaluate 调用(焦点指标分析、标签顺序、陷阱检测),插件通过 Page.createIsolatedWorld这个孤立的世界拥有同样的DOM(包括: document.activeElement,计算样式等)但有自己的JavaScript范围,确保评价针对AUT内容.

  4. 屏幕截图坐标翻译 —— 说 getBoundingClientRect() 在 AUT iframe 内返回 iframe 相对坐标, 但是 Page.captureScreenshot 来自顶级浏览器取景端的剪辑. 插件查询了AUT iframe在取景口的位置,并相应抵消了所有的截图剪辑坐标. 它还能检测到CSS的变换尺度,Cypress适用于AUT Iframe包装机(一般为~0.66x在无头电子中),并将其应用于坐标,维度,和剪辑 scale 属性。 这保证了像素级分析(颜色对比,焦点指标diffing),即使在AUT以缩放的尺寸提供时也能捕捉到正确的区域.

  5. 重点管理 — 每次键盘事件之前,插件使用 DOM.focus() 在AUT iframe 元素上这样 Input.dispatchKeyEvent 到达正确的框架.

CDP 流量

cy.a11yPressKey('Tab')
  │
  ├─ DOM.focus() on AUT iframe
  ├─ Input.dispatchKeyEvent (keyDown + keyUp)
  ├─ 50ms delay for focus/ARIA state updates
  ├─ Accessibility.getFullAXTree({ frameId: autFrameId })
  ├─ Runtime.evaluate({ contextId: autContextId }) — focused element
  ├─ Runtime.evaluate({ contextId: autContextId }) — focus indicator CSS
  ├─ Find focused node in AXTree → speech string
  └─ Assemble A11yState { speech, focusedElement, focusIndicator }

类型脚本

该插件将增强 Cypress.Chainable 接口。 TypeScript 在导入支持文件中的插件时会自动取取命令类型.

如果您在测试文件中需要类型而不导入支持文件 :

/// <reference types="@a11y-oracle/cypress-plugin" />

已知的限制

CDP 长期试验服中的资源积累

Cypress在测试(AUT)下运行应用程序,运行在运行器页内的iframe. 要与 AUT 的无障碍树交互,插件必须创建 单独处决世界 在AUT框架中通过 Page.createIsolatedWorld 每页 initA11yOracle() 电话 与提供本土一等CDP会话的Playwright不同,Cypress的iframe架构意味着这些被孤立的世界会积累出Chrome没有完全恢复的浏览器侧面资源,即使在之后 disposeA11yOracle() 清净其自所引.

这在实践中意味着什么:

  • 包含多个 spec文件的测试套件或每个文件的许多测试,在运行过程中可能会遇到越来越多的内存压力.
  • 在v1.3.0和早些时候,这导致大约16起死亡事件之后的确定性绞刑 init编号 :dispose 周期,因为 Accessibility.getFullAXTree 当节点横跨所有累积的上下文时(#14号) (中文(简体) ).
  • v1.3.1通过妥善地摧毁被处置的被孤立的世界来缓解绞刑,但潜在的建筑制约——Cypress代理所有CDP通过跑道呼叫并管理与Playwright不同的帧环境——依然存在.

建议: 如果您正在启动一个新项目, 或者您可以灵活选择您的 E2E 框架, 请使用 @a11y-oracle/playwright-plugin. Playwright提供直接的CDP会话访问而无需iframe间接,使其内在的稳定性和性能更能为A11y-Oracle的CDP繁忙工作流程所提供.

如果你需要留在Cypress上,插件是完全功能性的——只需意识到这些对非常大的套房的限制.

解决问题

"无法找到AUT Iframe"

此错误意味着 initA11yOracle() 之前被调用过 cy.visit()。在Cypress装入一页之前,AUT iframe是不存在的.

// Wrong
cy.initA11yOracle();
cy.visit('/page.html');

// Correct
cy.visit('/page.html');
cy.initA11yOracle();

语音输出包含 Cypress UI 元素

如果断言符合Cypress跑道元素(如"停止,按钮"或"可选,按钮"),帧扫描可能失败了. 确保:

  • 你在克罗姆跑步--browser chrome(中文(简体) )
  • cy.visit() 完成时间 cy.initA11yOracle()
  • AUT URL 不是一个 about:blank

空语音字符串

a11yPress() 当元素在按下键后没有焦点时,返回空字符串。 如果:

  • 键盘将焦点移出页面外( 例如 Tab 超过最后一个元素)
  • 重点要素 role="presentation" 或者说 role="none"
  • 重点要素是 RootWebArea (文件正文)

重点指标显示 contrastRatio: null

这发生在焦点指标颜色无法可靠地解析时. 常见原因:

  • 复杂的 CSS 颜色函数( R)color-mix(), (中文(简体) ), hsl(),命名颜色)
  • 多层梯度作为重点指标
  • currentColor 作为大纲颜色

关于角色和状态图的完整清单,见 @a11y- oracle/ 核心引擎 README。 。 。 .

版本与发布记录

@a11y-oracle/cypress-plugin 共发布 10 个版本,首次发布于 2026/03/05;过去 12 个月发布了 10 个版本。

版本发布日期距今
1.3.2latest2026/03/127 个月前
1.3.12026/03/117 个月前
1.3.02026/03/068 个月前
1.2.02026/03/068 个月前
1.1.42026/03/068 个月前
1.1.32026/03/068 个月前

关于 @a11y-oracle/cypress-plugin 的常见问题

@a11y-oracle/cypress-plugin 是什么?

Cypress 自定义的可访问语音断言命令,带有 iframare-aware CDP 路由

如何安装 @a11y-oracle/cypress-plugin?

在项目目录运行 npm install @a11y-oracle/cypress-plugin,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:cypress(>=12.0.0)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@a11y-oracle/cypress-plugin 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@a11y-oracle/cypress-plugin 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@a11y-oracle/cypress-plugin 可以商用吗?

@a11y-oracle/cypress-plugin 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@a11y-oracle/cypress-plugin 的下载量有多少?

根据 npm 官方下载统计,@a11y-oracle/cypress-plugin 在 2026/10/05 – 2026/11/03 这 30 天内被下载 2,479 次,日均约 83 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@a11y-oracle/cypress-plugin 还在维护吗?

最新版本 1.3.2 发布于 2026/03/12(7 个月前);至今共发布 10 个版本,其中过去 12 个月发布了 10 个;首次发布于 2026/03/05。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。