storybook/docs/writing-tests/accessibility-testing.mdx

286 lines
15 KiB
Plaintext

---
title: 'Accessibility tests'
sidebar:
order: 3
title: Accessibility tests
---
<YouTubeCallout id="rNLL0SICr9w" title="STOP fighting accessibility | automate a11y checks" />
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.
Accessibility tests audit the rendered DOM against a set of heuristics based on [WCAG](https://www.w3.org/WAI/standards-guidelines/wcag/) rules and other industry-accepted best practices. They act as the first line of QA to catch blatant accessibility violations.
<Video src="../_assets/writing-tests/component-accessibility-testing.mp4" />
## Accessibility checks with a11y addon
Storybook provides an official [a11y addon](https://storybook.js.org/addons/@storybook/addon-a11y). Powered by Deque's [axe-core](https://github.com/dequelabs/axe-core), which automatically catches up to [57% of WCAG issues](https://www.deque.com/blog/automated-testing-study-identifies-57-percent-of-digital-accessibility-issues/).
### Set up the a11y addon
If you want to check accessibility for your stories using the [addon](https://storybook.js.org/addons/@storybook/addon-a11y/), you'll need to add it to your Storybook. You can do this by running the following command:
{/* prettier-ignore-start */}
<CodeSnippets path="storybook-a11y-add.md" />
{/* prettier-ignore-end */}
<Callout variant="info">
The CLI's [`add`](../api/cli-options.mdx#add) command automates the addon's installation and setup. To install it manually, see our [documentation](../addons/install-addons.mdx#manual-installation) on how to install addons.
</Callout>
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.
![Storybook accessibility addon running](../_assets/writing-tests/storybook-a11y-addon-optimized.png)
### How it works
Storybook's a11y addon runs [Axe](https://github.com/dequelabs/axe-core) 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:
{/* prettier-ignore-start */}
<CodeSnippets path="component-story-with-accessibility.md" />
{/* prettier-ignore-end */}
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.
![Storybook accessibility addon running](../_assets/writing-tests/storybook-a11y-addon-optimized.png)
### Configure
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](https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#api-name-axeconfigure) to best suit your needs.
#### Global a11y configuration
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`](../configure/index.mdx#configure-story-rendering):
{/* prettier-ignore-start */}
<CodeSnippets path="storybook-addon-a11y-global-config.md" />
{/* prettier-ignore-end */}
#### Component-level a11y configuration
<If renderer="svelte">
You can also customize your own set of rules for all stories of a component. If you're using Svelte CSF with the native templating syntax, you can update the `defineMeta` function. If you're using regular CSF, you can update the default export of the story file.
</If>
<If notRenderer={['svelte']}>
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:
</If>
{/* prettier-ignore-start */}
<CodeSnippets path="storybook-addon-a11y-component-config.md" />
{/* prettier-ignore-end */}
#### Story-level a11y configuration
Customize the a11y ruleset at the story level by updating your story to include a new parameter:
{/* prettier-ignore-start */}
<CodeSnippets path="storybook-addon-a11y-story-config.md" />
{/* prettier-ignore-end */}
#### Turn off automated a11y tests
<If renderer="svelte">
If you are using Svelte CSF, you can turn off automated accessibility testing for stories or components by adding globals to your story or adjusting the `defineMeta` function with the required configuration. With a regular CSF story, you can add the following to your story's export or component's default export:
</If>
<If notRenderer={['svelte']}>
Disable automated accessibility testing for stories or components by adding the following globals to your story's export or component's default export:
</If>
{/* prettier-ignore-start */}
<CodeSnippets path="storybook-addon-a11y-disable.md" />
{/* prettier-ignore-end */}
<If renderer={['react', 'vue', 'svelte']}>
## Test addon integration
The accessibility addon provides seamless integration with the [Test addon](./test-addon.mdx), 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.
![Screenshot of the accessibility test results in the Storybook UI](../_assets/writing-tests/addon-a11y-with-addon-test.png)
### Manual upgrade
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:
<CodeSnippets path="storybook-addon-a11y-test-setup.md" />
### Configure accessibility tests with the test addon
You can configure accessibility tests with the `parameters.a11y.test` [parameter](../writing-stories/parameters.mdx), which determines the behavior of accessibility tests for a story and accepts the following values:
| Value | Description |
| --------- | ------------------------------------------------------------------------------------------------------- |
| `'off'` | Do not run accessibility tests (you can still manually verify via the addon panel) |
| `'todo'` | Run accessibility tests; violations return a warning in the Storybook UI and a summary count in CLI/CI |
| `'error'` | Run accessibility tests; violations return a failing test in the Storybook UI and CLI/CI |
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:
{/* prettier-ignore-start */}
<CodeSnippets path="addon-a11y-parameter-example.md" />
{/* prettier-ignore-end */}
<Callout variant="info" icon="💡">
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.
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](#configure) when they are not applicable to your use case.
</Callout>
### Recommended workflow
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:
1. Update your project configuration to fail on accessibility violations by setting `parameters.a11y.test` to `'error'`. This ensures that all new stories are tested to meet accessibility standards.
{/* prettier-ignore-start */}
<CodeSnippets path="addon-a11y-parameter-error-in-preview.md" />
{/* prettier-ignore-end */}
1. You will likely find that many components have accessibility failures (and maybe feel a bit overwhelmed!).
1. 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.
{/* prettier-ignore-start */}
<CodeSnippets path="addon-a11y-parameter-todo-in-meta.md" />
{/* prettier-ignore-end */}
1. 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.
{/* prettier-ignore-start */}
<CodeSnippets path="addon-a11y-parameter-remove.md" />
{/* prettier-ignore-end */}
1. Pick another component and repeat the process until you've covered all your components and you're an accessibility hero!
</If>
## Automate accessibility tests with test runner
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](https://www.deque.com/axe/), on average, catches upwards to [57% of WCAG issues](https://www.deque.com/blog/automated-testing-study-identifies-57-percent-of-digital-accessibility-issues/) automatically.
These tools work by auditing the rendered DOM against heuristics based on [WCAG](https://www.w3.org/WAI/standards-guidelines/wcag/) rules and other industry-accepted best practices. You can then integrate these tools into your test automation pipeline using the Storybook [test runner](./test-runner.mdx#test-hook-api) and [axe-playwright](https://github.com/abhinaba-ghosh/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](./test-runner.mdx) before proceeding with the rest of the required configuration.
Run the following command to install the required dependencies.
{/* prettier-ignore-start */}
<CodeSnippets path="test-runner-axe-playwright.md" />
{/* prettier-ignore-end */}
Add a new [configuration file](./test-runner.mdx#test-hook-api) inside your Storybook directory with the following inside:
{/* prettier-ignore-start */}
<CodeSnippets path="test-runner-a11y-config.md" />
{/* prettier-ignore-end */}
<Callout variant="info" icon="💡">
`preVisit` and `postVisit` are convenient hooks that allow you to extend the test runner's default configuration. Read more about them [here](./test-runner.mdx#test-hook-api).
</Callout>
When you execute the test runner (for example, with `yarn test-storybook`), it will run the accessibility audit and any [component tests](./component-testing.mdx) you might have configured for each component story.
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.
![Accessibility testing with the test runner](../_assets/writing-tests/test-runner-a11y-optimized.png)
### A11y config with the test runner
The test runner provides [helper methods](./test-runner.mdx#helpers), 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:
{/* prettier-ignore-start */}
<CodeSnippets path="test-runner-a11y-configure.md" />
{/* prettier-ignore-end */}
### Disable a11y tests with the test runner
Additionally, if you have already [disabled accessibility](#turn-off-automated-a11y-tests) tests for any particular story, you can also configure the test runner to avoid testing it as well. For example:
{/* prettier-ignore-start */}
<CodeSnippets path="test-runner-a11y-disable.md" />
{/* prettier-ignore-end */}
***
#### What's the difference between browser-based and linter-based accessibility tests?
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.
<If renderer={['react', 'vue', 'svelte']}>
## Troubleshooting
### Why are my tests failing in different environments?
If you enabled the test addon (i.e.,`@storybook/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 versus the test report. 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](https://github.com/storybookjs/storybook/discussions/new?category=help), [Github issues](https://github.com/storybookjs/storybook/issues/new?template=bug_report.yml)).
</If>
<If renderer={['react']}>
### The addon panel does not show expected violations
Modern React components often use asynchronous techniques like [Suspense](https://react.dev/reference/react/Suspense) or [React Server Components (RSC)](https://react.dev/reference/rsc/server-components) 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).
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](https://react.dev/reference/react/act), which helps ensure that all updates related to a test are processed and applied before making assertions, like a11y checks.
To enable this feature flag, add the following configuration to your `.storybook/main.js|ts` file:
{/* prettier-ignore-start */}
<CodeSnippets path="main-config-features-development-mode-for-build.md" />
{/* prettier-ignore-end */}
</If>
**Learn about other UI tests**
* [Component tests](./component-testing.mdx) for user behavior simulation
* [Visual tests](./visual-testing.mdx) for appearance
* Accessibility tests for accessibility
* [Snapshot tests](./snapshot-testing/snapshot-testing.mdx) for rendering errors and warnings
* [Test runner](./test-runner.mdx) to automate test execution
* [Test coverage](./test-coverage.mdx) for measuring code coverage
* [End-to-end tests](./import-stories-in-tests/stories-in-end-to-end-tests.mdx) for simulating real user scenarios
* [Unit tests](./import-stories-in-tests/stories-in-unit-tests.mdx) for functionality