文档
Storybook 文档

CI 中的测试

Vitest 插件 非常适合在 Storybook 中自动化您的 UI 测试。为了让您对您的工作充满信心,并有测试支持,您需要在持续集成 (CI) 环境中运行这些自动化测试。

幸运的是,这非常简单!

如果您无法在项目中使用 Vitest 插件,您仍然可以使用 test-runner 在 CI 中运行您的 story 作为测试。请按照 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 Tests”工作流来在我们的 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 Test 默认使用 Playwright 来渲染您的 story。为了获得最快的体验,您应该使用 已经安装了 Playwright 的机器镜像(如上面的大多数代码片段所示)。

2.1 调试测试失败

当 Storybook 测试失败时,失败输出会包含一个指向失败 story 的链接。在本地运行时,这会指向您本地运行的 Storybook,地址为 localhost:6006。但在 CI 中,没有活动 Storybook。相反,您必须先构建并发布您的 Storybook,然后告知 Vitest 插件您的 Storybook 发布在哪里,以便它能够打印有用的 story 链接。

以下是使用 GitHub Actions 的一个示例。其他 CI 提供商的步骤类似,尽管语法或配置的细节可能会有所不同。

当 Vercel、GitHub Pages 等服务的部署执行时,它们会遵循一个模式:发出一个 deployment_status 事件,其中包含新生成的 URL,位于 deployment_status.environment_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.config.ts
export default defineConfig({
  // ...
  test: {
    // ...
    projects: [
      {
        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 Test 发现的可访问性问题)来测试您的新工作流。

这样做时,您应该在拉取请求屏幕上看到测试结果作为状态检查。例如,在 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

更多测试资源