ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Storybook 无障碍(a11y)测试的 `todo` 模式:在组件 meta 层将违规降级为警告的配置实战

Storybook 无障碍(a11y)测试的 `todo` 模式:在组件 meta 层将违规降级为警告的配置实战 Storybook 无障碍a11y测试的todo模式在组件 meta 层将违规降级为警告的配置实战无障碍测试是 Storybook UI 组件质量保障的重要一环。本文聚焦 a11y addon 的parameters.a11y.test参数及其取值todo结合官方文档与 code/addons/a11y 下的真实源码实现讲解如何以组件级meta为单位把“已知存在无障碍问题但暂未修复”的组件从“测试失败”降级为“UI 警告”从而在不阻塞开发的前提下持续推进可访问性治理。读完本文你将掌握off / todo / error三档语义、在 CSF 3、CSF Next、Svelte CSF 等不同语法形态下的配置写法以及 addon 底层是如何对违规结果分派failed / warning / passed状态报告的。1. 背景Storybook a11y 测试如何处理违规Storybook 的 Accessibilitya11yaddon 基于 Deque 的 axe-core 库在 story 渲染完成后对 DOM 执行审计结果在Accessibility 面板中按Violations违规、Passes通过、Incomplete需人工确认三个子标签展示。当把它与 Vitest addon 或 test-runner 集成后parameters.a11y.test这个参数决定了 a11y 检查的行为它只接受三个取值在 code/addons/a11y/src/params.ts#L18 中定义为联合类型type A11yTest off | todo | error取值行为说明off不运行无障碍测试仍可在 addon 面板中手动触发检查todo运行无障碍测试违规项不会让测试失败而是在 Storybook UI 中显示为警告warningerror运行无障碍测试违规项会让测试失败并同时反映在 Storybook UI 与 CLI/CI 输出中三档开关构成了 Storybook 无障碍治理的“推进路线”error强制新代码达标 →todo给存量问题开“豁免清单” → 修复后移除todo。具体配置的完整文档见 docs/writing-tests/accessibility-testing.mdx。2. 为什么叫todo而不是warnaccessibility-testing.mdx 专门用一段 Callout 解释了命名缘由该值意在充当代码库中一个“字面上的 TODO”。它可以用来标记那些已知存在无障碍问题、但暂时还没准备好修复的 story让问题始终可见作为 UI 警告同时不阻塞开发日后可以追踪并统一处理。与之相对off只应该用于根本无需做无障碍测试的 story——例如故意演示某个反模式antipattern用法的 story。此外如果只是个别规则不适用于你的组件也可以改用“按规则禁用”的方式见 addon-a11y-config-rules-in-story.md 中通过config关闭单条规则的做法而不是整组关闭测试。3. 在组件级 meta 中启用todoparameters.a11y是一个标准的 Storybook 参数和所有 parameters 一样支持三个作用层级项目级写在.storybook/preview.*中作用于所有 story组件/文件级写在 story 文件的 metaCSF 3 的default export中作用于该文件内全部 story单 story 级写在某个具名导出或 CSF Next 的meta.story中仅作用于该 story。本文关联文档 addon-a11y-parameter-todo-in-meta.md 演示的正是第二种写法在 meta 上声明a11y: { test: todo }。它最典型的应用是整个文件的组件还没完全通过无障碍检查先让检查照常运行、把违规降级为 Storybook UI 中的警告。下面分语法形态给出可直接套用的示例以DataTable组件为例。3.1 CSF 3 TypeScript通用 / common 形态绝大多数框架共用同一种satisfies Meta...写法区别仅在于从哪个框架包导入Meta类型// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc. import { Meta } from storybook/your-framework; import { DataTable } from ./DataTable; const meta { component: DataTable, parameters: { // This components accessibility tests will not fail // Instead, they display warnings in the Storybook UI a11y: { test: todo }, }, } satisfies Metatypeof DataTable; export default meta;对应的 JavaScript 版本把类型层去掉即可import { DataTable } from ./DataTable; export default { component: DataTable, parameters: { // This components accessibility tests will not fail // Instead, they display warnings in the Storybook UI a11y: { test: todo }, }, };框架专属的导入映射可以简单记为一张表框架导入来源组件字段写法React / Vuestorybook/react、storybook/vue3-vite等框架包导入并引用组件对象如component: DataTableAngularstorybook/angular导入组件类如component: DataTableWeb Componentsstorybook/web-components-vite使用注册的元素标签字符串如component: demo-data-table3.2 CSF 3 Angularimport { Meta } from storybook/angular; import { DataTable } from ./data-table.component; const meta: MetaDataTable { component: DataTable, parameters: { // This components accessibility tests will not fail // Instead, they display warnings in the Storybook UI a11y: { test: todo }, }, }; export default meta;3.3 CSF 3 Web ComponentsWeb Components 形态使用自定义元素名作为componentimport { Meta } from storybook/web-components-vite; const meta: MetaDataTable { component: demo-data-table, parameters: { // This components accessibility tests will not fail // Instead, they display warnings in the Storybook UI a11y: { test: todo }, }, }; export default meta;export default { component: demo-data-table, parameters: { // This components accessibility tests will not fail // Instead, they display warnings in the Storybook UI a11y: { test: todo }, }, };3.4 Svelte CSF通过defineMeta声明Svelte CSF 场景下story 以.stories.svelte文件承载需要使用storybook/addon-svelte-csf的defineMeta把参数放进 metascript module import { defineMeta } from storybook/addon-svelte-csf; import DataTable from ./DataTable.svelte; const { Story } defineMeta({ component: DataTable, parameters: { // This components accessibility tests will not fail // Instead, they display warnings in the Storybook UI a11y: { test: todo }, }, }); /script如果项目使用script langts module的 TypeScript 版本写法完全一致只是额外加上langts。3.5 CSF Nextpreview.meta在 CSF NextStorybook 新一代基于preview对象的工厂式写法中需要从.storybook/preview导入preview再用preview.meta({ ... })组装 metaimport preview from ../.storybook/preview; import { DataTable } from ./DataTable; const meta preview.meta({ component: DataTable, parameters: { // This components accessibility tests will not fail // Instead, they display warnings in the Storybook UI a11y: { test: todo }, }, });同样的preview.meta写法适用于 Angularcomponent: DataTable导入自.storybook/preview、Web Componentscomponent: demo-data-table、React 与 Vue导入对应的DataTable组件等所有 renderer参数部分保持一致如果你偏好 JS把文件后缀换成.js、去掉类型标注即可原片段中 React / Vue / Web Components 均同时提供了 JS 变体见 addon-a11y-parameter-todo-in-meta.md。4. 层级优先级meta 兜底、story 微调在 meta 上配置todo意味着该文件中所有 story 默认都不会因 a11y 违规而失败。如果其中个别 story 已经修复达标、想严格要求可以仅在单 story 上覆盖回error反之如果文件级已用error强制达标个别尚未修复的 story 可以在自身 parameters 上单独降级为todo。后一种“绝大多数失败、个别豁免”的组合示例见 addon-a11y-parameter-example.mdmeta 中a11y: { test: error }作用于全文件而NoA11yFailstory 内部parameters: { a11y: { test: todo } }则只对自己生效——其注释明确说明“该 story 不会因违规失败但仍会运行测试并展示警告”。5. 源码级实现todo是如何变成 warning 的要真正理解todo的行为需要看 addon 预览模块的两个关键实现。5.1 违规 → 状态报告的映射在 code/addons/a11y/src/preview.tsx#L32-L40 中getMode()把a11y.test的取值映射为报告状态const getMode (): (typeof reporting)[reports][0][status] { switch (a11yParameter?.test) { case todo: return warning; case error: default: return failed; } };也就是说只要存在违规test: todo就让报告状态变成warning而error以及未显式配置时落入的default分支则为failed。随后在 preview.tsx#L46-L54 中a11y 运行结果被写入reporting.addReport({ type: a11y, ..., status: hasViolations ? getMode() : passed })——没有违规时任何取值下都会标记为passed有违规时才按上述映射区分warning或failed。5.2 什么时候会跳过检查同一文件中的shouldRunEnvironmentIndependent守卫preview.tsx#L26-L30给出了 a11y 自动检查的全部跳过条件globals.ghostStories为真幽灵 story 运行a11yParameter?.disable truea11yParameter?.test offglobals.a11y?.manual true手动模式关闭自动分析。此外整段逻辑只在viewMode story时执行docs 模式下不运行运行时一旦run()抛错会以failed状态上报。5.3 测试用例的验证code/addons/a11y/src/preview.test.tsx 用vitest happy-dom 对上述行为做了逐条断言其中最相关的几个test: todo→ 报告warning当run返回的violations非空且getIsVitestStandaloneRun为false时断言addReport收到status: warningpreview.test.tsx#L142-L167test: error→ 报告failed且在 Vitest 独立运行时通过expect(result).toHaveNoViolations()抛错让测试失败preview.test.tsx#L101-L119test: off/disable: true/manual: true→ 完全不运行run与addReport均不被调用docs 模式viewMode: docs→ 不运行。正是这套状态机保证了“todo 只在 UI 中显示警告、error 才会让测试红掉”的用户感知。另外在 preview.tsx#L99-L110 中该模块还导出了initialGlobalsa11y.manual: false以及一组内含a11y.test: todo的默认 parameters 对象可作为理解 addon 内建默认值的线索。6. 底层审计执行axe 串行队列与默认禁用的规则a11y 检查的实际执行由 code/addons/a11y/src/a11yRunner.ts 承担由于 axe-core不擅长并行运行模块用一个简单的队列把检查串行化见文件中的queue与runNext实现避免多个 story 同时审计互相干扰默认禁用了region规则a11yRunner.ts#L18-L22注释说明在组件测试场景下 landmark 并不总是存在、该规则容易产生误报当用户通过options.runOnly按规则集运行时还会把config.rules中显式关闭的规则“镜像”进 run options避免axe.run({ runOnly })把已关闭规则重新启用a11yRunner.ts#L43-L63。因此a11y.test: todo实际触发的是一条完整的执行链story 渲染结束 →afterEach钩子读参数 → 命中跳过条件则退出 →run(a11yParameter, storyId)排队执行 axe → 返回violations数组 → 按test取值把状态写成warning / failed / passed→ 写入测试报告。7. 实战组合官方推荐的“渐进式无障碍”工作流在 docs/writing-tests/accessibility-testing.mdx 的 “Recommended workflow” 中todo不是孤立技巧而是渐进式治理流程的中间一环先把标准定严在项目级.storybook/preview.*中设置a11y: { test: error }让所有新增 story 必须通过无障碍检查示例见 addon-a11y-parameter-error-in-preview.md盘点存量你大概率会发现许多存量组件存在违规给问题组件开“豁免”把问题组件的 meta 加上本文的todo参数让违规保持可见但不阻塞开发——此时是提交一个“改进基线”的好时机逐个攻坚从 Button 这类被广泛复用的基础组件入手按 addon 面板的修复建议修好违规随后删除todo参数对应 addon-a11y-parameter-remove.md 中注释掉该行的形态注释写明 “Remove this once all stories pass accessibility tests”循环覆盖继续挑选下一个todo组件重复修复 移除直到全部组件达标。8. 边界与注意事项CI 行为当通过 Vitest addon 在 CI 中运行时只有parameters.a11y.test error的 story 会自动执行 a11y 测试并产生可失败的断言。若设置成todoCI 中不会出现任何 a11y 相关的 error / warning / 输出——警告只在本地 Storybook UI 中可见accessibility-testing.mdx#L198-L202 的 warning Callout。test-runner 场景下只要安装了 a11y addon 且test不是offa11y 测试就会纳入运行。todo与off的适用边界todo面向“正在修复中的组件”off只面向无需测试的展示型 story如反模式演示。如果问题仅是个别规则不适用优先用config按规则关闭见 addon-a11y-config-rules-in-story.md。运行时的展示层在 Storybook 侧边栏展开 testing widget 并勾选 Accessibility 后运行组件测试todo产生的 warning 会与 failure 分开计数且可以点击过滤出仅含 warning / failure 的 story见 accessibility-testing.mdx。9. 进一步阅读完整参数表与默认值parameters.a11y.context / config / options / test与globals.a11y.manual见 docs/writing-tests/accessibility-testing.mdx相关代码片段addon-a11y-config-in-preview.md、addon-a11y-config-in-meta-and-story.md、addon-a11y-parameter-error-in-preview.md、addon-a11y-parameter-remove.md参数类型定义code/addons/a11y/src/params.ts状态映射与执行链code/addons/a11y/src/preview.tsx、code/addons/a11y/src/a11yRunner.ts行为验证测试code/addons/a11y/src/preview.test.tsx创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表