加入直播会话:美东时间周四上午 11 点,Storybook 9 发布及 AMA
文档
Storybook Docs

在 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 工作流中使用它非常有用。

package.json
{ 
  "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

.github/workflows/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

.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

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

.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

.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

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

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 传递给命令。

.github/workflows/test-storybook.yml
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 插件选项中使用该环境变量。

vitest.workspace.ts
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 脚本中的命令

对于所有测试

package.json
{ 
  "scripts": {
+   "test": "vitest --coverage"
-   "test": "vitest"
  }
}

仅针对 Storybook 测试

package.json
{ 
  "scripts": {
+   "test-storybook": "vitest --project=storybook --coverage"
-   "test-storybook": "vitest --project=storybook"
  }
}

或者,如果你只想在 CI 中运行时计算覆盖率,可以如下调整你的 CI 配置

对于所有测试

CI 工作流文件
+ npm run test -- --coverage
- npm run test

仅针对 Storybook 测试

CI 工作流文件
+ npm run test-storybook -- --coverage
- npm run test-storybook

3. 运行你的工作流

假设你的 CI 已配置为在你将工作推送到拉取请求时运行,你可以通过创建一个新的拉取请求(例如修复 Storybook 测试发现的可访问性问题)来测试你的新工作流。

这样做之后,你应该能在拉取请求屏幕上看到测试结果作为状态检查。例如,在 GitHub 中,一次失败的测试运行会看起来像这样

GitHub pull request status checks, with a failing "UI Tests / test" check

点击失败链接将带你查看完整的测试输出,包括指向失败 Story 的链接(如果你已设置 SB_URL 环境变量)。

Test failure output in CI environment, with a link to the Storybook to debug

常见问题

如何将其他 Vitest 测试与我的 Storybook 测试一起运行?

一些项目除了 Storybook 中定义的测试外,还有通过 Vitest 运行的其他测试,例如单元测试。

你可以通过在单独的脚本中指定项目过滤器来独立运行这些测试。例如,对于名为“unit”的 Vitest 项目

package.json
{ 
  "scripts": {
    "test-storybook": "vitest --project=storybook",
    "test-unit": "vitest --project=unit"
  }
}

然后,在你的工作流中,与 Storybook 脚本一起调用此脚本

.github/workflows/test.yml
- name: Run tests
  run: |
    npm run test-unit
    npm run test-storybook

你也可以选择将所有测试一起运行,只需从 package.json 脚本中省略 --project=storybook 过滤器即可

package.json
{ 
  "scripts": {
    "test": "vitest"
  }
}

工作流看起来就像

.github/workflows/test.yml
- name: Run tests
  run: |
    npm run test

更多测试资源