可访问性测试
Watch a video tutorial
无障碍设计是指使网站对所有人包容的实践。这意味着支持以下要求:键盘导航、屏幕阅读器支持、触控友好、可用的颜色对比度、减少动画效果和缩放支持。
¥Accessibility is the practice of making websites inclusive to all. That means supporting requirements such as: keyboard navigation, screen reader support, touch-friendly, usable color contrast, reduced motion, and zoom support.
无障碍测试会根据 WCAG 规则和其他行业公认的最佳实践,对渲染后的 DOM 进行一系列启发式规则的审核。它们充当 QA 的第一行,以捕获明显的可访问性违规行为。
¥Accessibility tests audit the rendered DOM against a set of heuristics based on WCAG rules and other industry-accepted best practices. They act as the first line of QA to catch blatant accessibility violations.
使用 a11y 插件进行辅助功能检查
¥Accessibility checks with a11y addon
Storybook 提供了一个官方的 a11y 插件 版本。由 Deque 的 axe-core 提供支持,axe-core 会自动更新至 解决 57% 的 WCAG 问题。
¥Storybook provides an official a11y addon. Powered by Deque's axe-core, which automatically catches up to 57% of WCAG issues.
设置 a11y 插件
¥Set up the a11y addon
如果你想使用 addon 检查故事的可访问性,需要将其添加到 Storybook 中。你可以通过运行以下命令来执行此操作:
¥If you want to check accessibility for your stories using the addon, you'll need to add it to your Storybook. You can do this by running the following command:
npx storybook add @storybook/addon-a11yCLI 的 add 命令可以自动补齐插件的安装和设置。要手动安装,请参阅我们的 documentation 了解如何安装插件。
¥The CLI's add command automates the addon's installation and setup. To install it manually, see our documentation on how to install addons.
启动 Storybook,你会发现用户界面有一些明显的不同。一个新的工具栏图标和辅助功能面板,你可以在其中查看测试结果。
¥Start your Storybook, and you will see some noticeable differences in the UI. A new toolbar icon and the accessibility panel where you can inspect the results of the tests.

工作原理
¥How it works
Storybook 的 a11y 插件会在选定的故事上运行 Axe。使你能够在开发过程中发现并修复辅助功能问题。例如,如果你正在开发一个按钮组件,并包含了以下故事集:
¥Storybook's a11y addon runs Axe on the selected story. Allowing you to catch and fix accessibility issues during development. For example, if you’re working on a button component and included the following set of stories:
import type { Meta, StoryObj } from '@storybook/react';
import { Button } from './Button';
const meta: Meta<typeof Button> = {
component: Button,
argTypes: {
backgroundColor: { control: 'color' },
},
};
export default meta;
type Story = StoryObj<typeof Button>;
// This is an accessible story
export const Accessible: Story = {
args: {
primary: false,
label: 'Button',
},
};
// This is not
export const Inaccessible: Story = {
args: {
...Accessible.args,
backgroundColor: 'red',
},
};循环浏览两个故事,你会发现 Inaccessible 故事包含一些需要修复的问题。打开辅助功能面板中的“违规”选项卡,即可查看辅助功能问题的清晰描述以及相应的解决方案指南。
¥Cycling through both stories, you will see that the Inaccessible story contains some issues that need fixing. Opening the violations tab in the accessibility panel provides a clear description of the accessibility issue and guidelines for solving it.

配置
¥Configure
Storybook 的辅助功能插件默认包含一组辅助功能规则,涵盖大多数问题。你还可以微调插件配置或覆盖 Axe 的规则集 以更好地满足你的需求。
¥Out of the box, Storybook's accessibility addon includes a set of accessibility rules that cover most issues. You can also fine-tune the addon configuration or override Axe's ruleset to best suit your needs.
全局 a11y 配置
¥Global a11y configuration
如果你需要禁用某个辅助功能规则或修改其在所有故事中的设置,可以将以下内容添加到 storybook/preview.js|ts 文件中:
¥If you need to dismiss an accessibility rule or modify its settings across all stories, you can add the following to your storybook/preview.js|ts:
// Replace your-framework with the framework you are using (e.g., react, vue3)
import { Preview } from '@storybook/your-framework';
const preview: Preview = {
parameters: {
a11y: {
// Optional selector to inspect
element: 'body',
config: {
rules: [
{
// The autocomplete rule will not run based on the CSS selector provided
id: 'autocomplete-valid',
selector: '*:not([autocomplete="nope"])',
},
{
// Setting the enabled option to false will disable checks for this particular rule on all stories.
id: 'image-alt',
enabled: false,
},
],
},
/*
* Axe's options parameter
* See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#options-parameter
* to learn more about the available options.
*/
options: {},
},
},
globals: {
a11y: {
// Optional flag to prevent the automatic check
manual: true,
},
},
};
export default preview;组件级无障碍配置
¥Component-level a11y configuration
你还可以为组件的所有故事自定义规则集。更新故事文件的默认导出,并使用所需的配置添加参数和全局变量:
¥You can also customize your own set of rules for all stories of a component. Update the story file's default export and add parameters and globals with the required configuration:
// Replace your-framework with the name of your framework
import type { Meta } from '@storybook/your-framework';
import { MyComponent } from './MyComponent';
const meta: Meta<typeof MyComponent> = {
component: MyComponent,
parameters: {
a11y: {
// Optional selector to inspect
element: 'body',
config: {
rules: [
{
// The autocomplete rule will not run based on the CSS selector provided
id: 'autocomplete-valid',
selector: '*:not([autocomplete="nope"])',
},
{
// Setting the enabled option to false will disable checks for this particular rule on all stories.
id: 'image-alt',
enabled: false,
},
],
},
/*
* Axe's options parameter
* See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#options-parameter
* to learn more about the available options.
*/
options: {},
},
},
globals: {
a11y: {
manual: true,
},
},
};
export default meta;Story 级无障碍配置
¥Story-level a11y configuration
通过更新故事并添加新参数,在故事级别自定义 a11y 规则集:
¥Customize the a11y ruleset at the story level by updating your story to include a new parameter:
import type { Meta, StoryObj } from '@storybook/react';
import { MyComponent } from './MyComponent';
const meta: Meta<typeof MyComponent> = {
component: MyComponent,
};
export default meta;
type Story = StoryObj<typeof MyComponent>;
export const ExampleStory: Story = {
parameters: {
a11y: {
element: 'body',
config: {
rules: [
{
// The autocomplete rule will not run based on the CSS selector provided
id: 'autocomplete-valid',
selector: '*:not([autocomplete="nope"])',
},
{
// Setting the enabled option to false will disable checks for this particular rule on all stories.
id: 'image-alt',
enabled: false,
},
],
},
/*
* Axe's options parameter
* See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#options-parameter
* to learn more about the available options.
*/
options: {},
},
},
globals: {
a11y: {
// Optional flag to prevent the automatic check
manual: true,
},
},
};关闭自动化辅助功能测试
¥Turn off automated a11y tests
要禁用故事或组件的自动辅助功能测试,请将以下全局变量添加到故事的导出或组件的默认导出中:
¥Disable automated accessibility testing for stories or components by adding the following globals to your story’s export or component’s default export:
import type { Meta, StoryObj } from '@storybook/react';
import { MyComponent } from './MyComponent';
const meta: Meta<typeof MyComponent> = {
component: MyComponent,
};
export default meta;
type Story = StoryObj<typeof MyComponent>;
export const NonA11yStory: Story = {
globals: {
a11y: {
// This option disables all automatic a11y checks on this story
manual: true,
},
},
};测试插件集成
¥Test addon integration
辅助功能插件与 测试插件 无缝集成,使你能够在运行组件测试的同时,在后台运行所有测试的自动化辅助功能测试。如果存在任何违规,测试将会失败,你将在侧边栏中看到结果,无需任何额外设置。
¥The accessibility addon provides seamless integration with the Test addon, enabling you to run automated accessibility tests for all your tests in the background while you run component tests. If there are any violations, the test will fail, and you will see the results in the sidebar without any additional setup.

手动升级
¥Manual upgrade
如果你已启用该插件,并且手动升级到 Storybook 8.5 或更高版本,则需要调整现有配置(例如 .storybook/vitest.setup.ts)以启用集成,具体操作如下:
¥If you enabled the addon and you're manually upgrading to Storybook 8.5 or later, you'll need to adjust your existing configuration (i.e., .storybook/vitest.setup.ts) to enable the integration as follows:
import { beforeAll } from 'vitest';
import { setProjectAnnotations } from '@storybook/react';
// Import the a11y addon annotations
import * as a11yAddonAnnotations from '@storybook/addon-a11y/preview';
// Optionally import your own annotations
import * as projectAnnotations from './preview';
const project = setProjectAnnotations([
// Add the a11y addon annotations
a11yAddonAnnotations,
projectAnnotations,
]);
beforeAll(project.beforeAll);使用测试插件配置无障碍测试
¥Configure accessibility tests with the test addon
你可以使用 parameters.a11y.test 和 参数 配置辅助功能测试,它们决定故事的辅助功能测试行为,并接受以下值:
¥You can configure accessibility tests with the parameters.a11y.test parameter, which determines the behavior of accessibility tests for a story and accepts the following values:
| 值 | 描述 |
|---|---|
'off' | 请勿运行可访问性测试(你仍然可以通过插件面板手动验证) |
'todo' | 运行可访问性测试;违规会在 Storybook UI 中显示警告,并在 CLI/CI 中显示汇总计数。 |
'error' | 运行可访问性测试;违反规则会在 Storybook UI 和 CLI/CI 中返回失败的测试 |
与其他参数一样,你可以在 .storybook/preview.js|ts 中的项目级别、故事文件默认导出的组件级别或单个故事级别定义它。例如,要使文件中除一个故事之外的所有故事的可访问性测试失败:
¥Like other parameters, you can define it at the project level in .storybook/preview.js|ts, the component level in the default export of the story file, or the individual story level. For example, to fail on accessibility tests for all stories in a file except one:
// Replace your-renderer with the renderer you are using (e.g., react, vue3)
import { Meta, StoryObj } from '@storybook/your-renderer';
import { Button } from './Button';
const meta: Meta<typeof Button> = {
component: Button,
parameters: {
a11y: { test: 'error' },
},
};
export default meta;
type Story = StoryObj<typeof Button>;
// 👇 This story will use the 'error' value and fail on accessibility violations
export const Primary: Story = {
args: { primary: true },
};
// 👇 This story will not fail on accessibility violations
// (but will still run the tests and show warnings)
export const NoA11yFail: Story = {
parameters: {
a11y: { test: 'todo' },
},
};为什么值叫做 "todo" 而不是 "warn"?此值旨在用作代码库中的字面量 TODO。它可以用来标记那些你知道存在可访问性问题但尚未准备好修复的故事。这样,你就可以跟踪它们并在以后解决它们。
¥Why is the value called "todo" instead of "warn"? This value is intended to serve as a literal TODO in your codebase. It can be used to mark stories that you know have accessibility issues but are not ready to fix yet. This way, you can keep track of them and address them later.
'off' 值仅应用于无需进行可访问性测试的故事,例如用于演示组件使用中的反模式的故事。
¥The 'off' value should only be used for stories that do not need to be tested for accessibility, such as one used to demonstrate an antipattern in a component's usage.
当 禁用单个规则 不适用于你的用例时,你也可以使用它们。
¥You can also disable individual rules when they are not applicable to your use case.
推荐工作流程
¥Recommended workflow
你可以通过配置通过组合多种测试行为来逐步实现更易于访问的 UI。例如,你可以先从 'error' 开始,以解决可访问性违规问题,然后切换到 'todo' 标记需要修复的组件,最后在所有故事通过可访问性测试后删除待办事项:
¥You can use configuration to progressively work toward a more accessible UI by combining multiple test behaviors. For example, you can start with 'error' to fail on accessibility violations, then switch to 'todo' to mark components that need fixing, and finally remove the todos once all stories pass accessibility tests:
-
通过将
parameters.a11y.test设置为'error',更新你的项目配置,使其在出现可访问性违规时失败。这可确保所有新故事都经过测试,符合无障碍标准。¥Update your project configuration to fail on accessibility violations by setting
parameters.a11y.testto'error'. This ensures that all new stories are tested to meet accessibility standards..storybook/preview.ts// Replace your-renderer with the renderer you are using (e.g., react, vue3) import { Preview } from '@storybook/your-renderer'; const preview: Preview = { // ... parameters: { // 👇 Fail all accessibility tests when violations are found a11y: { test: 'error' }, }, }; export default preview; -
你可能会发现许多组件存在无障碍功能故障(并且可能会感到有点不知所措!)。
¥You will likely find that many components have accessibility failures (and maybe feel a bit overwhelmed!).
-
记录存在可访问性问题的组件,并通过应用
'todo'参数值将其故障暂时降低为警告。这可以使可访问性问题保持可见,同时不会阻碍开发。现在也是提交工作作为未来改进基准的好时机。¥Take note of the components with accessibility issues and temporarily reduce their failures to warnings by applying the
'todo'parameter value. This keeps accessibility issues visible while not blocking development. This is also a good time to commit your work as a baseline for future improvements.DataTable.stories.ts// Replace your-renderer with the renderer you are using (e.g., react, vue3) import { Meta } from '@storybook/your-renderer'; import { DataTable } from './DataTable'; const meta: Meta<typeof DataTable> = { component: DataTable, parameters: { // 👇 This component's accessibility tests will not fail // Instead, they display warnings in the Storybook UI a11y: { test: 'todo' }, }, }; export default meta; -
从刚刚标记为
'todo'的组件中选择一个合适的起点(我们推荐使用 Button 之类的组件,因为它简单易用,并且很可能在其他组件中使用)。使用插件面板中的建议修复该组件中的问题,确保其通过可访问性测试,然后移除该参数。¥Pick a good starting point from the components you just marked
'todo'(we recommend something like Button, for its simplicity and likelihood of being used within other components). Fix the issues in that component using the suggestions in the addon panel to ensure it passes accessibility tests, then remove the parameter.Button.stories.ts// Replace your-renderer with the renderer you are using (e.g., react, vue3) import { Meta } from '@storybook/your-renderer'; import { Button } from './Button'; const meta: Meta<typeof Button> = { component: Button, parameters: { // 👇 Remove this once all stories pass accessibility tests // a11y: { test: 'todo' }, }, }; export default meta; -
选择另一个组件并重复此过程,直到你覆盖所有组件,你就是无障碍访问的达人!
¥Pick another component and repeat the process until you've covered all your components and you're an accessibility hero!
使用测试运行器自动化辅助功能测试
¥Automate accessibility tests with test runner
检查辅助功能的最准确方法是在真机上手动检查。但是,你可以使用自动化工具来捕获常见的辅助功能问题。例如,Axe 平均会自动向上捕获到 解决 57% 的 WCAG 问题。
¥The most accurate way to check accessibility is manually on real devices. However, you can use automated tools to catch common accessibility issues. For example, Axe, on average, catches upwards to 57% of WCAG issues automatically.
这些工具的工作原理是根据基于 WCAG 规则和其他行业公认的最佳实践的启发式方法审核渲染的 DOM。然后,你可以使用 Storybook 测试运行器 和 axe-playwright 将这些工具集成到你的测试自动化流程中。
¥These tools work by auditing the rendered DOM against heuristics based on WCAG rules and other industry-accepted best practices. You can then integrate these tools into your test automation pipeline using the Storybook test runner and axe-playwright.
设置
¥Setup
要使用测试运行器启用辅助功能测试,你需要执行其他步骤进行正确设置。我们建议你在进行其他必要配置之前先了解 测试运行器文档。
¥To enable accessibility testing with the test runner, you will need to take additional steps to set it up properly. We recommend you go through the test runner documentation before proceeding with the rest of the required configuration.
运行以下命令安装所需的依赖。
¥Run the following command to install the required dependencies.
npm install axe-playwright --save-dev在你的 Storybook 目录中添加一个新的 配置文件,其中包含以下内容:
¥Add a new configuration file inside your Storybook directory with the following inside:
import type { TestRunnerConfig } from '@storybook/test-runner';
import { injectAxe, checkA11y } from 'axe-playwright';
/*
* See https://storybook.js.org/docs/writing-tests/test-runner#test-hook-api
* to learn more about the test-runner hooks API.
*/
const config: TestRunnerConfig = {
async preVisit(page) {
await injectAxe(page);
},
async postVisit(page) {
await checkA11y(page, 'body', {
detailedReport: true,
detailedReportOptions: {
html: true,
},
});
},
};
export default config;执行测试运行器(例如,使用 yarn test-storybook)时,它将运行辅助功能审核以及你可能为每个组件故事配置的任何 组件测试。
¥When you execute the test runner (for example, with yarn test-storybook), it will run the accessibility audit and any component tests you might have configured for each component story.
它从故事的根元素开始遍历 DOM 树,检查问题,并根据遇到的问题生成详细的报告。
¥It starts checking for issues by traversing the DOM tree starting from the story's root element and generates a detailed report based on the issues it encountered.

使用测试运行器配置 A11y 功能
¥A11y config with the test runner
测试运行器提供 辅助方法,允许访问故事信息。你可以使用它们来扩展测试运行器的配置,并为特定故事提供其他选项。例如:
¥The test runner provides helper methods, allowing access to the story's information. You can use them to extend the test runner's configuration and provide additional options you may have for a specific story. For example:
import type { TestRunnerConfig } from '@storybook/test-runner';
import { getStoryContext } from '@storybook/test-runner';
import { injectAxe, checkA11y, configureAxe } from 'axe-playwright';
/*
* See https://storybook.js.org/docs/writing-tests/test-runner#test-hook-api
* to learn more about the test-runner hooks API.
*/
const config: TestRunnerConfig = {
async preVisit(page) {
await injectAxe(page);
},
async postVisit(page, context) {
// Get the entire context of a story, including parameters, args, argTypes, etc.
const storyContext = await getStoryContext(page, context);
// Apply story-level a11y rules
await configureAxe(page, {
rules: storyContext.parameters?.a11y?.config?.rules,
});
const element = storyContext.parameters?.a11y?.element ?? 'body';
await checkA11y(page, element, {
detailedReport: true,
detailedReportOptions: {
html: true,
},
});
},
};
export default config;使用测试禁用无障碍测试测试运行器
¥Disable a11y tests with the test runner
此外,如果你已经为某个特定故事编写了 禁用辅助功能 测试,你还可以配置测试运行器以避免对其进行测试。例如:
¥Additionally, if you have already disabled accessibility tests for any particular story, you can also configure the test runner to avoid testing it as well. For example:
import type { TestRunnerConfig } from '@storybook/test-runner';
import { getStoryContext } from '@storybook/test-runner';
import { injectAxe, checkA11y } from 'axe-playwright';
/*
* See https://storybook.js.org/docs/writing-tests/test-runner#test-hook-api
* to learn more about the test-runner hooks API.
*/
const config: TestRunnerConfig = {
async preVisit(page) {
await injectAxe(page);
},
async postVisit(page, context) {
// Get the entire context of a story, including parameters, args, argTypes, etc.
const storyContext = await getStoryContext(page, context);
// Do not run a11y tests on disabled stories.
if (storyContext.parameters?.a11y?.disable) {
return;
}
await checkA11y(page, 'body', {
detailedReport: true,
detailedReportOptions: {
html: true,
},
});
},
};
export default config;基于浏览器和基于 linter 的可访问性测试有什么区别?
¥What’s the difference between browser-based and linter-based accessibility tests?
基于浏览器的可访问性测试(如 Storybook 中的测试)会评估渲染的 DOM,因为这可为你提供最高的准确性。审核尚未编译的代码与真实代码相差一步,因此你无法捕捉到用户可能遇到的所有内容。
¥Browser-based accessibility tests, like those found in Storybook, evaluate the rendered DOM because that gives you the highest accuracy. Auditing code that hasn't been compiled yet is one step removed from the real thing, so you won't catch everything the user might experience.
故障排除
¥Troubleshooting
为什么我的测试在不同环境下会失败?
¥Why are my tests failing in different environments?
如果你启用了实验性测试插件(即 @storybook/experimental-addon-test),你的测试将使用 Playwright 的 Chromium 浏览器,并按照你项目的配置在 Vitest 中运行。这可能导致 Storybook UI 或 CLI 中报告的测试结果不一致。不一致可能是由于 axe-core 在不同环境(例如浏览器版本或配置)下报告的结果不同。如果你遇到此问题,我们建议你使用默认沟通渠道(例如 GitHub 讨论、Github 问题)与我们联系。
¥If you enabled the experimental test addon (i.e.,@storybook/experimental-addon-test), your tests run in Vitest using your project's configuration with Playwright's Chromium browser. This can lead to inconsistent test results reported in the Storybook UI or CLI. The inconsistency can be due to axe-core reporting different results in different environments, such as browser versions or configurations. If you encounter this issue, we recommend reaching out using the default communication channels (e.g., GitHub discussions, Github issues).
插件面板未显示预期违规
¥The addon panel does not show expected violations
现代 React 组件通常使用 Suspense 或 React 服务器组件 (RSC) 等异步技术来处理复杂的数据获取和渲染。这些组件不会立即渲染其最终的 UI 状态。Storybook 本身并不知道异步组件何时完全渲染。因此,a11y 检查有时会在组件完成渲染之前运行过早,从而导致误报(即使存在违规,也不会报告)。
¥Modern React components often use asynchronous techniques like Suspense or React Server Components (RSC) to handle complex data fetching and rendering. These components don’t immediately render their final UI state. Storybook doesn’t inherently know when an async component has fully rendered. As a result, the a11y checks sometimes run too early, before the component finishes rendering, leading to false negatives (no reported violations even if they exist).
为了解决这个问题,我们引入了一个功能标记:developmentModeForBuild。此功能标志允许你在内置 Storybook 中将 process.env.NODE_ENV 设置为 'development',从而启用通常在生产版本中禁用的开发相关优化。React 的 act 实用程序 是这些开发优化之一,它有助于确保在进行断言(例如 a11y 检查)之前处理并应用与测试相关的所有更新。
¥To address this issue, we have introduced a feature flag: developmentModeForBuild. This feature flag allows you to set process.env.NODE_ENV to 'development' in built Storybooks, enabling development-related optimizations that are typically disabled in production builds. One of those development optimizations is React’s act utility, which helps ensure that all updates related to a test are processed and applied before making assertions, like a11y checks.
要启用此功能,请在你的 .storybook/main.js|ts 文件中添加以下配置:
¥To enable this feature flag, add the following configuration to your .storybook/main.js|ts file:
// Replace your-framework with the framework you are using (e.g., react-webpack5, vue3-vite)
import type { StorybookConfig } from '@storybook/your-framework';
const config: StorybookConfig = {
framework: '@storybook/your-framework',
stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],
features: {
developmentModeForBuild: true,
},
};
export default config;了解其他 UI 测试
¥Learn about other UI tests
-
组件测试 提供有关用户行为模拟
¥Component tests for user behavior simulation
-
视觉测试 用于外观
¥Visual tests for appearance
-
辅助功能测试
¥Accessibility tests for accessibility
-
快照测试 提供有关渲染错误和警告
¥Snapshot tests for rendering errors and warnings
-
测试运行器 用于自动化测试执行
¥Test runner to automate test execution
-
测试覆盖率 用于测量代码覆盖率
¥Test coverage for measuring code coverage
-
端到端测试 提供有关模拟真实用户场景
¥End-to-end tests for simulating real user scenarios
-
单元测试 用于功能性
¥Unit tests for functionality
