如何使用 Storybook 测试 UI
Storybook stories 是针对 UI 组件在各种状态和配置下的测试用例。使用 Storybook,你可以同时以多种方式开发和测试组件,并获得即时反馈。
¥Storybook stories are test cases for your UI components in their various states and configurations. With Storybook, you can develop and test your components at the same time, in multiple ways, with instant feedback.
Storybook 从整体角度处理 UI 组件测试,确保你不仅可以快速可靠地执行组件测试,而且还拥有完善的模式来开发、调试、维护,甚至在整个开发生命周期内协作完成这些测试。
¥Storybook tackles UI component testing from a holistic perspective, ensuring that you can not only execute component tests quickly and reliably, but that you also have well established patterns to develop, debug, maintain, and even collaborate on these tests across the development lifecycle.
开始
¥Get started
如果你的项目使用 Vite,你很可能可以使用 Vitest 插件 在 Storybook 中运行组件测试。此插件基于 Vitest 构建,Vitest 是一个快速轻量级的测试运行器,可与 Vite 无缝协作。
¥If your project is using Vite, you can likely use the Vitest addon to run your component tests in Storybook. This addon is built on top of Vitest, a fast and lightweight test runner that works seamlessly with Vite.
运行此命令,它将安装并配置 Vitest 插件和 Vitest:
¥Run this command, which will install and configure the Vitest addon and Vitest:
npx storybook add @storybook/addon-vitest完整的安装说明(包括项目要求)可在 Vitest 插件文档 中找到。
¥The full installation instructions, including project requirements, are available in the Vitest addon documentation.
项目设置完成后,你将在侧边栏底部看到一个测试小部件。运行测试后,你还会在侧边栏项目上看到测试状态指示器。此外,许多测试可以使用插件面板进行调试。
¥Once your project is set up, you will see a testing widget in the bottom of your sidebar. After running tests, you will also see test status indicators on sidebar items. Additionally, many tests can be debugged with an addon panel.

如果你无法在项目中使用 Vitest 插件,你仍然可以使用 test-runner 运行测试。
¥If you cannot use the Vitest addon in your project, you can still run tests using the test-runner.
接下来,我们将介绍 Storybook 中测试的一些关键概念。
¥Next, we’ll cover some key concepts of testing in Storybook.
关键概念
¥Key concepts
Storybook 中的测试与其他测试环境类似。你之前使用的大部分知识和技术也适用于此。但也有一些显著的改进。
¥Testing in Storybook is similar to other testing environments. Most of the knowledge and techniques you’ve been using apply here, too. But there are also some significant improvements.
组件测试
¥Component tests
组件测试是指:
¥A component test is a test which:
-
在浏览器中渲染组件以实现高保真度
¥Renders a component in the browser for high fidelity
-
模拟用户与实际 UI 交互,例如端到端 (E2E) 测试
¥Simulates a user interacting with actual UI, like an end-to-end (E2E) test
-
仅测试 UI 的一个单元(例如单个组件),并且可以深入实现以模拟内容或操作数据,就像单元测试一样。
¥Only tests a unit (e.g. a single component) of UI, and can reach into the implementation to mock things or manipulate data, like a unit test
这种使用真实浏览器、模拟行为和模拟测试的组合,为测试 UI 的功能方面提供了一种强大的方法。
¥This combination of using a real browser, simulating behavior, and mocking provides a powerful means of testing the functional aspects of your UI.
在 Storybook 中,整个测试体验都围绕组件测试构建。这意味着你可以在与故事相同的环境中使用相同的工具和技术运行测试。
¥In Storybook, the entire testing experience is built around component tests. This means that you can run your tests in the same environment as your stories, with the same tools and techniques.
Storybook 测试
¥Storybook Test
Storybook Test 通过 Vitest 插件 实时测试你的故事。它使用 Vitest 插件自动将你的故事转换为真实的 Vitest 测试,然后使用 Vitest 的浏览器模式运行。
¥Storybook Test enables real time testing of your stories, through the Vitest addon. It uses a Vitest plugin to automatically transform your stories into real Vitest tests, which are then run with Vitest’s browser mode.
观看模式
¥Watch mode
使用观察模式开发时可立即获得测试反馈。它将监视你的代码(组件源代码或测试代码)是否有更改,并自动仅重新运行相关的测试。它非常适合测试驱动开发,你可以先编写测试,然后再编写组件。
¥Get instant test feedback as you develop with watch mode. It will watch your code—either the component source or the tests—for changes and automatically re-run only the relevant tests. It’s perfect for test-driven development, where you write your tests first and then the component.
要激活观看模式,请点击测试小部件中的观看模式按钮(眼睛图标):
¥To activate watch mode, press the watch mode button (the eye icon) in the testing widget:

CI
如果你没有在 CI 中运行 Storybook Test,那么你将遗漏它提供的最大优势:在合并 PR 之前捕获错误。
¥If you’re not running Storybook Test as part of your CI, you’re missing out on the biggest benefit it provides: catching bugs on PRs before you merge them.
如果你已经在 CI 中运行 vitest,那么当你将更改提交到 Git 时,你的故事应该会自动“免费”地作为测试运行。
¥If you are already running vitest as part of your CI then your stories should automatically run as tests “for free” when you commit your changes to Git.
如果你尚未在 CI 中运行 Vitest,请进行设置。首先,在你的 package.json 中添加一个新脚本:
¥If you’re not yet running Vitest in CI, you should set that up. First by adding a new script to your package.json:
{
"scripts": {
"test-storybook": "vitest --project=storybook"
}
} 请注意,这假设你有一个名为“storybook”的 Vitest 项目用于你的故事,这是安装 Storybook Test 时的默认配置。如果你已重命名它,请相应地调整脚本。
¥Note that this assumes you have a Vitest project called “storybook” for your stories, which is the default configuration when you install Storybook Test. If you’ve renamed it, adjust the script accordingly.
接下来,添加新的 CI 工作流。
¥Next, add a new CI workflow.
If you use Github Actions that would look like:
name: Storybook Tests
on: [push]
jobs:
test:
runs-on: ubuntu-latest
container:
# Make sure to grab the latest version of the Playwright image
# https://playwright.nodejs.cn/docs/docker#pull-the-image
image: mcr.microsoft.com/playwright:v1.52.0-noble
steps:
- uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 22.12.0
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm run test-storybook如果你使用的是其他 CI 提供商,请参阅我们的完整 CI 指南 以获取更多信息。
¥If you are using a different CI provider, please consult our full CI guide for more information.
Storybook Test 默认使用 Playwright 渲染你的故事。为了获得最快的体验,你应该使用 已安装 Playwright 的机器镜像已安装(如上面的代码片段所示)。
¥Storybook Test uses Playwright to render your stories by default. For the fastest experience, you should use a machine image that has Playwright already installed (as in the snippet above).
覆盖率
¥Coverage
代码覆盖率可以洞察哪些代码经过测试,哪些未经过测试。它在你开发过程中起到护栏的作用,帮助确保你的工作得到适当的测试覆盖。
¥Code coverage provides insight into which code is tested or not. It functions as a guardrail as you develop, to help be sure your work is covered by the proper tests.
在 Storybook Test 中,你可以通过两种方式查看故事提供的覆盖率。首先,测试小部件中会显示一个摘要。其次,单击该覆盖率摘要将打开完整的交互式报告。
¥In Storybook Test, you can see the coverage provided by your stories in two ways. First, a summary is displayed in the testing widget. Second, clicking that coverage summary will open a full, interactive report.

在报告中,点击特定组件即可显示已覆盖或未覆盖的具体代码分支:
¥In the report, clicking through to a specific component shows the exact branches of code that are covered or not covered:

每个项目的覆盖率报告看起来会有所不同,但需要注意以下几点:
¥Each project’s coverage report will look different, but the important things to note are:
-
整体行/分支覆盖率,可作为高级健康检查。
¥The overall line/branch coverage, which serves as a high-level health check.
-
未涵盖的特定行/分支,这些是潜在的测试缺口。
¥Specific lines/branches that are not covered, which are potential test gaps.
我们认为,目标并非获得 100% 的覆盖率并填补所有空白,而是要有一个晴雨表来帮助你判断代码/测试变更,并让这些空白告知你尚未测试的关键状态或交互。例如,如果你正在构建原型,你可能会完全跳过测试,而在关键应用中,你可能希望对每个 i 都进行点和横线测试。
¥In our point of view, the goal is not to get 100% coverage and fill every gap, but rather to have a barometer to help you judge code/test changes, and for the gaps to inform you of key states or interactions that are untested. For example, if you’re building a prototype you might skip testing altogether, whereas in a critical app you might want to dot every i and cross every t.
运行覆盖率分析会降低测试运行速度,因此默认情况下处于关闭状态。要激活覆盖率,请选中测试小部件中的“覆盖率”复选框。
¥Running coverage analysis can slow down your test runs, so it is turned off by default. To activate coverage, check the coverage checkbox in the testing widget.

CI 中的覆盖率
¥Coverage in CI
在我们查看覆盖率的同时,请更新你的 CI 工作流程以包含以下内容:
¥And while we’re looking at coverage, update your CI workflow to include it:
- yarn test
+ yarn test --coverage为什么我们要运行所有测试(yarn test),而不是只运行 Storybook 测试(yarn test-storybook)?因为覆盖率报告在涵盖项目中的所有测试(而不仅仅是你编写的故事)时最为准确。
¥Why are we running all tests (yarn test) instead of just the Storybook tests (yarn test-storybook)? Because a coverage report is most accurate when accounting for all tests in your project, not just the stories you've written.
查看 Storybook 特定覆盖范围 可能会有所帮助,但在 CI 输出中,你希望看到项目的全面覆盖率。
¥Seeing Storybook-specific coverage can be helpful, but in CI output, you want to see the comprehensive coverage of your project.
这样,我们就可以跟踪每个 PR 中的覆盖率变化。
¥This way we can track the coverage change in every PR.
这些是你需要在 Storybook 中测试的关键概念。现在,让我们看看你可以执行的不同类型的测试。
¥Those are the key concepts you’ll need to test in Storybook. Now, let’s look at the different types of tests you can perform.
类型测试
¥Types of tests
Storybook Test 支持多种测试类型,可帮助你从多个维度验证你的工作。
¥Storybook Test supports a variety of testing types to help you validate your work in multiple dimensions.
渲染测试
¥Render tests
在 Storybook 中测试组件的最重要工具是能够在各种状态下渲染组件的故事。
¥The most important tool for testing your components in Storybook is stories that render your components in various states.
但是,你可能不知道基本故事也是 冒烟测试,我们称之为渲染测试。当故事成功渲染时,测试通过;当故事出现错误时,测试失败。
¥However, you might not be aware that a basic story is also a smoke test, which we call a render test. The test passes when the story renders successfully and fails when it errors.
根据组件的复杂程度,你可能能够通过这种方式捕获许多关键的 UI 状态。
¥Depending on the complexity of your components, you might be able to capture many of your key UI states this way.
交互测试
渲染测试是一种非常基本的交互测试。要测试有状态组件或验证交互行为,请为故事定义一个播放函数:
¥Render tests are a very basic kind of interaction test. To test stateful components or verify interactive behavior, you define a play function for your story:
// Replace your-framework with the name of your framework (e.g. react-vite, vue3-vite, etc.)
import type { Meta, StoryObj } from '@storybook/your-framework';
import { expect } from 'storybook/test';
import { Dialog } from './Dialog';
const meta = {
component: Dialog,
} satisfies Meta<typeof Dialog>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Opens: Story = {
play: async ({ canvas, userEvent }) => {
// Click on a button and assert that a dialog appears
const button = canvas.getByRole('button', { text: 'Open Modal' });
await userEvent.click(button);
await expect(canvas.getByRole('dialog')).toBeInTheDocument();
},
};但是 play 函数也可用于设置状态、创建间谍、模拟网络、模拟用户与组件的交互、断言输出等等。它们是测试的核心,也是你在 Storybook 中其余测试之旅的基础。
¥But play functions can also be used for setting up state, creating spies, mocking out the network, simulating user interactions with your components, asserting output, and more. They are the meat and potatoes of testing and are the foundation for the rest of your testing journey in Storybook.
以下是一个更复杂的例子,它通过 fn 实用程序包含 监视和模拟。
¥Here’s a more complex example, which includes spying and mocking via the fn utility.
// Replace your-framework with the name of your framework (e.g. react-vite, vue3-vite, etc.)
import type { Meta, StoryObj } from '@storybook/your-framework';
import { fn, expect } from 'storybook/test';
import { users } from '../mocks/users';
import { EventForm } from './EventForm';
const meta = {
component: EventForm,
} satisfies Meta<typeof EventForm>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Submits: Story = {
// Mock functions so we can manipulate and spy on them
args: {
getUsers: fn(),
onSubmit: fn(),
},
beforeEach: async ({ args }) => {
// Manipulate `getUsers` mock to return mocked value
args.getUsers.mockResolvedValue(users);
},
play: async ({ args, canvas, userEvent }) => {
const usersList = canvas.getAllByRole('listitem');
await expect(usersList).toHaveLength(4);
await expect(canvas.getAllByText('VIP')).toHaveLength(2);
const titleInput = await canvas.findByLabelText('Enter a title for your event');
await userEvent.type(titleInput, 'Holiday party');
const submitButton = canvas.getByRole('button', { text: 'Plan event' });
await userEvent.click(submitButton);
// Spy on `onSubmit` to verify that it is called correctly
await expect(args.onSubmit).toHaveBeenCalledWith({
name: 'Holiday party',
userCount: 4,
data: expect.anything(),
});
},
};有关如何使用 play 函数编写交互测试和模拟的更多信息,请参阅 交互测试指南。
¥For more information on how to write interaction tests and mocks using the play function, please see the interaction testing guide.
可访问性测试
Storybook 的 无障碍 (A11y) 插件 会对你的故事运行一系列自动检查,以帮助确保所有用户都能使用你的组件,无论他们使用何种能力或技术。这意味着支持以下要求:键盘导航、屏幕阅读器支持、可用的颜色对比度等。
¥Storybook’s Accessibility (A11y) addon runs a set of automated checks on your stories to help ensure your components can be used by all users, regardless of ability or technology they're using. That means supporting requirements such as: keyboard navigation, screen reader support, usable color contrast, etc.
无障碍不仅是正确的做法,而且越来越受到人们的重视。例如,欧洲无障碍 act 计划于 2025 年 6 月生效。同样,在美国,类似 美国禁用法案 (ADA) 和 《康复法案》第 508 条 的法律适用于许多面向公众的服务。
¥Accessibility is not only the right thing to do, but it is increasingly mandated. For example, the European accessibility act is scheduled to go into law in June 2025. Similarly in the US, laws like the Americans with Disabilities Act (ADA) and Section 508 of the Rehabilitation Act apply to many public-facing services.
要与组件测试一起激活可访问性检查,请选中测试小部件中的“可访问性”复选框。
¥To activate accessibility checks alongside your component tests, check the Accessibility checkbox in the testing widget.

激活后,你将在侧边栏中看到可访问性失败信息。
¥Once activated, you will see accessibility failures in the sidebar.

任何故障都可以在辅助功能插件面板中调试。
¥Any failures can be debugged in the Accessibility addon panel.

视觉测试
可视化测试是测试组件最有效的方法。只需点击按钮,你就可以为 Storybook 中的每个故事截取快照,并将这些快照与基线(已知的最新“良好”快照)进行比较。这不仅允许你检查组件的外观,还可以检查 无需编写或维护任何测试代码 的大部分组件功能!
¥Visual tests are the most efficient way to test your components. With the click of a button you can take snapshots of every story in your Storybook and compare those snapshots to baselines — last known “good” snapshots. Not only does this allow you to check the appearance of your components, but they are also able to check a large subset of component functionality without having to write or maintain any test code!
Storybook 使用 Storybook 团队开发的云服务 Chromatic,原生支持跨浏览器可视化测试。当你启用可视化测试时,每个故事都会自动变成一个测试。这会直接在 Storybook 中为你提供有关 UI 错误的即时反馈。
¥Storybook supports cross-browser visual testing natively using Chromatic, a cloud service made by the Storybook team. When you enable visual testing, every story is automatically turned into a test. This gives you instant feedback on UI bugs directly in Storybook.

快照测试
在大多数情况下,其他测试类型能够以更少的工作量提供更高的覆盖率。但在某些情况下,将故事的渲染标记与已知基线进行比较会很有帮助。例如,它可以帮助识别触发渲染错误的标记更改。
¥In most cases, the other testing types will provide more coverage with less effort. But there are scenarios where it can be helpful to compare the rendered markup of a story against a known baseline. For example, it can help identify markup changes that trigger rendering errors.
在其他测试工具中复用故事
¥Reusing stories in other testing tools
Story 可重用,因此你可以在常用的测试工具中将其用作测试用例。
¥Stories are made to be reusable, so you can use them as test cases in popular testing tools.
端到端
有时你需要测试完整的工作流程,并使用完整的运行堆栈。在这种情况下,你仍然可以通过在 Playwright 或 Cypress 端到端 (E2E) 测试中导入故事来使用它们。
¥Sometimes you need to test a full workflow, with the full running stack. In those cases, you can still use your stories by importing them within your Playwright or Cypress end-to-end (E2E) tests.
单元
¥Unit
如果你愿意,你可以在传统的测试环境(例如 Vitest 或 Jest)中重复使用你的 Storybook 故事。
¥If you prefer, you can reuse your Storybook stories in a traditional testing environment, like Vitest or Jest.
更多测试资源
¥More testing resources
-
Vitest 插件 用于在 Storybook 中运行测试
¥Vitest addon for running tests in Storybook
-
交互测试 提供有关用户行为模拟
¥Interaction testing for user behavior simulation
-
无障碍测试 用于可访问性
¥Accessibility testing for accessibility
-
可视化测试 用于外观
¥Visual testing for appearance
-
快照测试 提供有关渲染错误和警告
¥Snapshot testing for rendering errors and warnings
-
测试覆盖率 用于测量代码覆盖率
¥Test coverage for measuring code coverage
-
CI 用于在你的 CI/CD 流水线中运行测试
¥CI for running tests in your CI/CD pipeline
-
端到端测试 提供有关模拟真实用户场景
¥End-to-end testing for simulating real user scenarios
-
单元测试 用于功能性
¥Unit testing for functionality
-
测试运行器 用于自动化测试执行
¥Test runner to automate test execution
