在 CI 中测试
Vitest 插件非常适合在 Storybook 中自动化 UI 测试。为了完全自信地完成工作并得到测试的支持,你需要在持续集成 (CI) 环境中运行这些自动化测试。
幸好,这相当容易!
如果你的项目无法使用 Vitest 插件,你仍然可以使用 test-runner 在 CI 中运行你的 Stories 作为测试。请遵循test-runner 文档中的说明来设置 test-runner 在项目中运行于 CI 中。
在 CI 中设置 Storybook 测试
在 CI 中运行 Storybook 测试与在本地机器上通过 CLI 运行它们非常相似:运行相同的命令,只是位置不同。
让我们一步一步进行设置。
1. 定义 package.json
脚本
为方便起见,在你的 package.json
中定义一个脚本来运行 Storybook 测试。这与你在本地运行的命令相同,但在 CI 工作流中使用它非常有用。
{
"scripts": {
"test-storybook": "vitest --project=storybook"
}
}
这个脚本调用 vitest
CLI 命令,并将其限制在你 Vitest 配置中定义的“storybook”项目,该项目在你安装 Vitest 插件时创建。(如果你重命名了项目,请相应地调整上面的脚本。)你还可以传递任何你可能需要的额外 vitest
CLI 选项。
2. 添加新的 CI 工作流
接下来,我们将创建一个新的“UI 测试”工作流,以便在 CI 环境中运行。如果你愿意,也可以调整现有的工作流。
以下是一些流行的 CI 提供商的示例配置
GitHub Actions
在你的仓库根目录下创建文件 .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.net.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
GitLab Pipelines
在你的仓库根目录下创建文件 .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.net.cn/docs/docker#pull-the-image
image: mcr.microsoft.com/playwright:v1.52.0-noble
script:
- npm run test-storybook
Bitbucket Pipelines
在你的仓库根目录下创建文件 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.net.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-storybook
Circle CI
在你的仓库根目录下创建文件 .circleci/config.yml
version: 2.1
executors:
ui-testing:
docker:
# Make sure to grab the latest version of the Playwright image
# https://playwright.net.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:
- Test
Travis CI
在你的仓库根目录下创建文件 .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-storybook
Jenkins
在你的仓库根目录下创建文件 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.net.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
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.net.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-storybook
Storybook 测试默认使用 Playwright 来渲染你的 Stories。为了获得最快的体验,你应该使用预装了 Playwright 的机器镜像(如上面大多数代码片段所示)。
2.1 调试测试失败
当 Storybook 测试失败时,失败输出会包含指向失败 Story 的链接。在本地运行时,这会指向你运行在 localhost:6006
的本地 Storybook。但在 CI 中,没有活动的 Storybook。因此,你必须首先构建并发布你的 Storybook,然后告知 Vitest 插件你的 Storybook 发布在哪里,以便它能打印出有用的 Story 链接。
这里是使用 GitHub Actions 的一个示例。其他 CI 提供商的步骤类似,但语法或配置细节可能有所不同。
当执行 Vercel、GitHub Pages 等服务的部署时,它们会遵循一个模式,即发出一个 deployment_status
事件,其中包含在 deployment_status.environment_url
下生成的新 URL。这就是发布的 Storybook 实例的 URL。
我们可以使用环境变量 SB_URL
将该 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
插件选项中使用该环境变量。
export default defineWorkspace([
// ...
{
// ...
{
plugins: [
storybookTest({
// ...
+ // 👇 Use the environment variable you passed
+ storybookUrl: process.env.SB_URL
}),
],
},
},
])
现在,当测试在 CI 中失败时,打印的 Story URL 将指向已发布的 Storybook,从而使调试该失败变得轻而易举!
2.2 计算代码覆盖率
有关代码覆盖率的更多详细信息,请查看完整指南。
你可以通过向 vitest
命令传递 --coverage
标志来计算 Storybook 测试的代码覆盖率。覆盖率最有用的是在项目中所有测试中全面计算,但你也可以只计算 Storybook 测试的覆盖率。
你可以调整 package.json
脚本中的命令
对于所有测试
{
"scripts": {
+ "test": "vitest --coverage"
- "test": "vitest"
}
}
仅针对 Storybook 测试
{
"scripts": {
+ "test-storybook": "vitest --project=storybook --coverage"
- "test-storybook": "vitest --project=storybook"
}
}
或者,如果你只想在 CI 中运行时计算覆盖率,可以如下调整你的 CI 配置
对于所有测试
+ npm run test -- --coverage
- npm run test
仅针对 Storybook 测试
+ npm run test-storybook -- --coverage
- npm run test-storybook
3. 运行你的工作流
假设你的 CI 已配置为在你将工作推送到拉取请求时运行,你可以通过创建一个新的拉取请求(例如修复 Storybook 测试发现的可访问性问题)来测试你的新工作流。
这样做之后,你应该能在拉取请求屏幕上看到测试结果作为状态检查。例如,在 GitHub 中,一次失败的测试运行会看起来像这样
点击失败链接将带你查看完整的测试输出,包括指向失败 Story 的链接(如果你已设置 SB_URL
环境变量)。
常见问题
如何将其他 Vitest 测试与我的 Storybook 测试一起运行?
一些项目除了 Storybook 中定义的测试外,还有通过 Vitest 运行的其他测试,例如单元测试。
你可以通过在单独的脚本中指定项目过滤器来独立运行这些测试。例如,对于名为“unit”的 Vitest 项目
{
"scripts": {
"test-storybook": "vitest --project=storybook",
"test-unit": "vitest --project=unit"
}
}
然后,在你的工作流中,与 Storybook 脚本一起调用此脚本
- name: Run tests
run: |
npm run test-unit
npm run test-storybook
你也可以选择将所有测试一起运行,只需从 package.json
脚本中省略 --project=storybook
过滤器即可
{
"scripts": {
"test": "vitest"
}
}
工作流看起来就像
- name: Run tests
run: |
npm run test
更多测试资源