在 CI 中测试
Vitest 插件 非常适合在 Storybook 中自动化 UI 测试。为了对你的工作充满信心,并通过测试获得支持,你需要在持续集成 (CI) 环境中运行这些自动化测试。
¥The Vitest addon is great for automating your UI tests within Storybook. To have full confidence in your work, backed by tests, you need to run those automated tests in your continuous integration (CI) environment.
谢天谢地,这很简单!
¥Thankfully, that’s quite easy!
如果你无法在项目中使用 Vitest 插件,你仍然可以使用测试运行器在 CI 中将你的故事作为测试运行。按照 测试运行器文档 中的说明设置测试运行器,使其在你的项目中的 CI 中运行。
¥If you cannot use the Vitest addon in your project, you can still run your stories as tests in CI using the test-runner. Follow the instructions in the test-runner documentation to set up the test-runner to run in CI in your project.
在 CI 中设置 Storybook 测试
¥Set up Storybook tests in CI
在 CI 中运行 Storybook 测试与在本地计算机上通过 CLI 运行它们非常相似:你运行相同的命令,只是在不同的位置。
¥Running Storybook tests in CI is very similar to running them via CLI on your local machine: you run the same command, just in a different place.
让我们逐步进行设置。
¥Let’s go step-by-step to set things up.
1. 定义 package.json 脚本
¥ Define package.json script
为方便起见,请在 package.json 中定义一个脚本来运行 Storybook 测试。这与你在本地运行的命令相同,但将其添加到你的 CI 工作流中会很有用。
¥For convenience, define a script in your package.json to run the Storybook tests. This is the same command you would run locally, but it’s useful to have it in your CI workflow.
{
"scripts": {
"test-storybook": "vitest --project=storybook"
}
}此脚本调用 vitest CLI 命令,并将其限制在你的 Vitest 配置中定义的“storybook”项目中,该项目是在你安装 Vitest 插件时创建的。(如果你已重命名项目,请相应地调整上面的脚本。)你还可以传递你可能需要的任何其他 vitest CLI 选项。
¥This script calls the vitest CLI command and restricts it to the “storybook” project defined in your Vitest config, which was created when you installed the Vitest addon. (If you’ve renamed the project, adjust the script above accordingly.) You can also pass any additional vitest CLI options you may require.
2. 添加新的 CI 工作流程
¥ Add a new CI workflow
接下来,我们将创建一个新的“UI 测试”工作流以在我们的 CI 环境中运行。如果你愿意,也可以调整现有的工作流程。
¥Next, we’ll create a new “UI Tests” workflow to run in our CI environment. You may also adjust an existing workflow, if you prefer.
以下是一些常用 CI 提供商的示例配置:
¥Here are some example configurations for popular CI providers:
GitHub Actions
在你的代码库根目录中创建一个文件 .github/workflow/test-ui.yml:
¥Create a file in the root of your repo, .github/workflow/test-ui.yml:
name: UI 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-storybookGitLab Pipelines
在你的代码库根目录中创建一个文件 .gitlab-ci.yml:
¥Create a file in the root of your repo, .gitlab-ci.yml:
image: node:jod
stages:
- UI_Tests
cache:
key: $CI_COMMIT_REF_SLUG-$CI_PROJECT_DIR
paths:
- .npm/
before_script:
# Install dependencies
- npm ci
Test:
stage: UI_Tests
# 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
script:
- npm run test-storybookBitbucket Pipelines
在你的代码库根目录中创建一个文件 bitbucket-pipelines.yml:
¥Create a file in the root of your repo, bitbucket-pipelines.yml:
image: node:jod
definitions:
caches:
npm: $HOME/.npm
pipelines:
default:
- stage:
name: "UI Tests"
steps:
- step:
name: "Run Tests"
# 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
caches:
- npm
- node
script:
# Install dependencies
- npm ci
- npm run test-storybookCircle CI
在你的代码库根目录中创建一个文件 .circleci/config.yml:
¥Create a file in the root of your repo, .circleci/config.yml:
version: 2.1
executors:
ui-testing:
docker:
# 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
working_directory: ~/repo
jobs:
Test:
executor: ui-testing
steps:
- checkout
- restore_cache:
keys:
- v1-dependencies-{{ checksum "package-lock.json" }}
- v1-dependencies-
# Install dependencies
- run: npm ci
- run: npm run test-storybook
- save_cache:
name: Save NPM cache
paths:
- ~/.npm
key: v1-dependencies-{{ checksum "package-lock.json" }}
workflows:
UI_Tests:
jobs:
- TestTravis CI
在你的代码库根目录中创建一个文件 .travis.yml:
¥Create a file in the root of your repo, .travis.yml:
language: node_js
os: linux
dist: jammy
node_js:
- 20
before_script:
# Install dependencies and Playwright browsers so Vitest browser mode can run story tests
- npm ci && npm run playwright install chromium --with-deps
cache: npm
jobs:
include:
- stage: "UI Tests"
name: "Run tests"
script: npm run test-storybookJenkins
在你的代码库根目录中创建一个文件 JenkinsFile:
¥Create a file in the root of your repo, JenkinsFile:
pipeline {
agent any
tools {nodejs "node"}
stages {
stage('UI Tests'){
agent {
docker {
/*
* 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'
reuseNode true
}
}
steps {
/* Install dependencies */
sh 'npm ci'
sh "npm run test-storybook"
}
}
}
}Azure Pipelines
在你的代码库根目录中创建一个文件 azure-pipelines.yml:
¥Create a file in the root of your repo, azure-pipelines.yml:
trigger:
- main
pool:
vmImage: "ubuntu-latest"
stages:
- stage: UI_Tests
displayName: "UI Tests"
jobs:
- job: Test
displayName: "Storybook tests"
# Make sure to grab the latest version of the Playwright image
# https://playwright.nodejs.cn/docs/docker#pull-the-image
container: mcr.microsoft.com/playwright:v1.52.0-noble
variables:
npm_config_cache: $(Pipeline.Workspace)/.npm
steps:
- task: UseNode@1
displayName: "Install Node.js"
inputs:
version: "22.12.0"
- task: Cache@2
displayName: "Install and cache dependencies"
inputs:
key: 'npm | "$(Agent.OS)" | package-lock.json'
restoreKeys: |
npm | "$(Agent.OS)"
path: $(npm_config_cache)
- script: npm ci
condition: ne(variables.CACHE_RESTORED, 'true')
- task: CmdLine@2
displayName: "Run tests"
inputs:
script: npm run test-storybookStorybook 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 most of the snippets above).
2.1 调试测试失败
¥2.1 Debug test failures
当 Storybook 测试失败时,失败输出会包含指向失败故事的链接。在本地运行时,这指向在 localhost:6006 上运行的本地 Storybook。但在 CI 中,没有活动的 Storybook。你必须先构建并发布 Storybook,然后告知 Vitest 插件你的 Storybook 发布在哪里,以便它可以打印有用的故事链接。
¥When a Storybook test fails, the failure output includes a link to the failing story. When running locally, this points to your local Storybook running at localhost:6006. But in CI, there is no active Storybook. Instead, you must first build and publish your Storybook, then inform the Vitest addon where your Storybook is published so that it can print useful story links.
这是一个使用 GitHub Actions 的示例。其他 CI 提供商的步骤类似,但语法或配置的细节可能有所不同。
¥Here's an example using GitHub Actions. The steps are similar for other CI providers, though details in the syntax or configuration may vary.
在部署 Vercel、GitHub Pages 等服务时,它们会遵循一种模式,即在 deployment_status.environment_url 下发出一个包含新生成 URL 的 deployment_status 事件。这是已发布的 Storybook 实例的 URL。
¥When deployments for services like Vercel, GitHub Pages, and others are performed, they follow a pattern of emitting a deployment_status event containing the newly generated URL under deployment_status.environment_url. This is the URL to the published Storybook instance.
我们可以使用环境变量 SB_URL 将该 URL 传递给命令。
¥We can pass that URL to the command using an environment variable, SB_URL.
name: Storybook Tests
+ # 👇 Update this to only run when a deployment status is emitted
+ on: deployment_status
- on: [push]
jobs:
test:
runs-on: ubuntu-latest
container:
image: mcr.microsoft.com/playwright:v1.52.0-noble
+ # 👇 Only run on successful deployments
+ if: github.event_name == 'deployment_status' && github.event.deployment_status.state == 'success'
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
+ # 👇 Pass the Storybook URL as an environment variable
+ env:
+ SB_URL: '${{ github.event.deployment_status.environment_url }}'最后,我们更新插件配置,以便在 storybookUrl 插件选项 中使用该环境变量。
¥Finally, we update the plugin configuration to use that environment variable in the storybookUrl plugin option.
export default defineConfig({
// ...
test: {
// ...
projects: [
{
plugins: [
storybookTest({
// ...
// 👇 Use the environment variable you passed
storybookUrl: process.env.SB_URL,
}),
],
},
],
},
});现在,当 CI 中的测试失败时,打印的故事 URL 将指向已发布的 Storybook,从而轻松调试该失败!
¥Now, when a test fails in CI, the printed story URL will point to the published Storybook, making debugging that failure a breeze!
2.2 计算代码覆盖率
¥2.2 Calculate code coverage
有关代码覆盖率的更多详细信息,请查看 完整指南。
¥For more details on code coverage, check the full guide.
你可以通过将 --coverage 标志传递给 vitest 命令来计算 Storybook 测试的代码覆盖率。覆盖率在全面计算项目所有测试的覆盖率时最有用,但你也可以仅针对 Storybook 测试进行计算。
¥You can calculate code coverage of your Storybook tests by passing the --coverage flag to the vitest command. Coverage is most useful when calculated comprehensively across all tests in your project, but you can also calculate it for just the Storybook tests.
你可以调整 package.json 脚本中的命令:
¥You can either adjust the command in your package.json scripts:
适用于所有测试:
¥For all tests:
{
"scripts": {
+ "test": "vitest --coverage"
- "test": "vitest"
}
}仅适用于 Storybook 测试:
¥For only Storybook tests:
{
"scripts": {
+ "test-storybook": "vitest --project=storybook --coverage"
- "test-storybook": "vitest --project=storybook"
}
}或者,如果你只想在 CI 中运行测试时计算覆盖率,请像这样调整你的 CI 配置:
¥Or, if you only want to calculate coverage when running tests in CI, adjust your CI configuration like so:
适用于所有测试:
¥For all tests:
+ npm run test -- --coverage
- npm run test仅适用于 Storybook 测试:
¥For only Storybook tests:
+ npm run test-storybook -- --coverage
- npm run test-storybook3. 运行工作流程
¥ Run your workflow
假设你的 CI 配置为在将工作推送到拉取请求时运行,你可以通过创建新的拉取请求来测试新的工作流程(例如修复 Storybook 测试发现的可访问性问题)。
¥Assuming your CI is configured to run when you push your work to a pull request, you can test your new workflow by creating a new pull request (perhaps to fix an accessibility issue found by Storybook Test).
执行此操作后,你应该会在拉取请求屏幕上看到测试结果作为状态检查。例如,在 GitHub 中,失败的测试运行可能如下所示:
¥When you do so, you should see the test result as a status check on the pull request screen. For example, in GitHub, a failing test run would look something like this:

点击失败案例将带你查看完整的测试输出,包括失败案例的链接(如果你使用了 设置 SB_URL 环境变量)。
¥Clicking on the failure will take you to the full test output, including the link to the failing story (if you've set up the SB_URL environment variable).

FAQs
如何在 Storybook 测试的同时运行其他 Vitest 测试?
¥How do I run other Vitest tests alongside my Storybook tests?
除了 Storybook 中定义的测试之外,某些项目还会通过 Vitest 运行其他测试,例如单元测试。
¥Some projects have other tests run via Vitest, e.g. unit tests, in addition to those defined in Storybook.
你可以通过在单独的脚本中指定项目过滤器来独立运行这些测试。例如,对于名为“unit”的 Vitest 项目:
¥You can run these tests independently by specifying the project filter in a separate script. For example, for a Vitest project called “unit”:
{
"scripts": {
"test-storybook": "vitest --project=storybook",
"test-unit": "vitest --project=unit"
}
}然后,在你的工作流程中,与 Storybook 脚本一起调用此脚本:
¥Then, in your workflow, call this script alongside the Storybook one:
- name: Run tests
run: |
npm run test-unit
npm run test-storybook你也可以选择通过简单地从 package.json 脚本中省略 --project=storybook 过滤器来一起运行所有测试:
¥You may also choose to run all tests together by simply omitting the --project=storybook filter from the package.json script:
{
"scripts": {
"test": "vitest"
}
}工作流程将如下所示:
¥The workflow would then look like:
- name: Run tests
run: |
npm run test更多测试资源
¥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
-
端到端测试 提供有关模拟真实用户场景
¥End-to-end testing for simulating real user scenarios
-
单元测试 用于功能性
¥Unit testing for functionality
-
测试运行器 用于自动化测试执行
¥Test runner to automate test execution
