Files
2026-07-13 21:36:47 +08:00

13 KiB
Raw Permalink Blame History

CIGitLab CI/CD

使用场景:在 GitLab 流水线中针对合并请求、推送到主分支或定时流水线运行 Playwright 测试。

快速参考

# GitLab 流水线中使用的关键命令
npx playwright install --with-deps    # 安装浏览器 + 操作系统依赖
npx playwright test --shard=1/4       # 运行 4 个分片中的第 1 个
npx playwright merge-reports ./blob-report  # 合并分片结果
npx playwright test --reporter=dot    # CI 日志的最小化输出

模式

模式 1:生产就绪流水线(复制粘贴即用)

使用场景:任何包含 Playwright 测试的 GitLab 项目。这是完整且推荐的配置。

# .gitlab-ci.yml
image: mcr.microsoft.com/playwright:v1.52.0-noble

stages:
  - install
  - test
  - report

variables:
  CI: "true"
  npm_config_cache: "$CI_PROJECT_DIR/.npm"

# 跨流水线缓存 node_modules 和 npm 缓存
cache:
  key:
    files:
      - package-lock.json
  paths:
    - .npm/
    - node_modules/

install:
  stage: install
  script:
    - npm ci
  artifacts:
    paths:
      - node_modules/
    expire_in: 1 hour

test:
  stage: test
  needs: [install]
  script:
    - npx playwright test
  artifacts:
    when: always
    paths:
      - playwright-report/
      - test-results/
    expire_in: 14 days
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH

模式 2:并行分片执行

使用场景:测试套件运行超过 10 分钟。使用 GitLab 的 parallel 关键字在多个作业之间自动拆分。 避免场景:测试套件运行时间少于 5 分钟。

# .gitlab-ci.yml
image: mcr.microsoft.com/playwright:v1.52.0-noble

stages:
  - install
  - test
  - report

variables:
  CI: "true"
  npm_config_cache: "$CI_PROJECT_DIR/.npm"

cache:
  key:
    files:
      - package-lock.json
  paths:
    - .npm/
    - node_modules/

install:
  stage: install
  script:
    - npm ci
  artifacts:
    paths:
      - node_modules/
    expire_in: 1 hour

test:
  stage: test
  needs: [install]
  parallel: 4
  script:
    - npx playwright test --shard=$CI_NODE_INDEX/$CI_NODE_TOTAL
  artifacts:
    when: always
    paths:
      - blob-report/
    expire_in: 1 hour
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH

merge-report:
  stage: report
  needs: [test]
  when: always
  script:
    - npx playwright merge-reports --reporter=html ./blob-report
  artifacts:
    when: always
    paths:
      - playwright-report/
    expire_in: 14 days

分片流水线的配置:

// playwright.config.ts
import { defineConfig } from "@playwright/test"

export default defineConfig({
  reporter: process.env.CI ? [["blob"], ["dot"]] : [["html", { open: "on-failure" }]],
})

模式 3:含环境变量的合并请求流水线

使用场景:测试需要密钥(API 密钥、密码),且应仅在合并请求或默认分支上运行。 避免场景:测试完全自包含,无外部依赖。

# .gitlab-ci.yml
image: mcr.microsoft.com/playwright:v1.52.0-noble

stages:
  - test

variables:
  CI: "true"

test:e2e:
  stage: test
  variables:
    BASE_URL: $STAGING_URL
    TEST_PASSWORD: $TEST_PASSWORD
    API_KEY: $API_KEY
  before_script:
    - npm ci
  script:
    - npx playwright test
  artifacts:
    when: always
    paths:
      - playwright-report/
      - test-results/
    expire_in: 14 days
  rules:
    # 在合并请求上运行
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    # 在推送到默认分支时运行
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
    # 允许手动触发
    - when: manual
      allow_failure: true

在 GitLab 中设置变量: 导航至 Settings > CI/CD > Variables 并添加:

  • STAGING_URL —— 不脱敏,不保护
  • TEST_PASSWORD —— 脱敏,受保护
  • API_KEY —— 脱敏,受保护

模式 4:使用子流水线进行多浏览器测试

使用场景:在合并请求上运行 Chromium,在默认分支上运行所有浏览器。 避免场景:你只测试一个浏览器。

# .gitlab-ci.yml
image: mcr.microsoft.com/playwright:v1.52.0-noble

stages:
  - install
  - test

variables:
  CI: "true"

install:
  stage: install
  script:
    - npm ci
  artifacts:
    paths:
      - node_modules/
    expire_in: 1 hour

# 合并请求上仅运行 Chromium(快速反馈)
test:chromium:
  stage: test
  needs: [install]
  script:
    - npx playwright test --project=chromium
  artifacts:
    when: always
    paths:
      - playwright-report/
      - test-results/
    expire_in: 14 days
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"

# 默认分支上运行所有浏览器
test:all-browsers:
  stage: test
  needs: [install]
  parallel:
    matrix:
      - PROJECT: [chromium, firefox, webkit]
  script:
    - npx playwright test --project=$PROJECT
  artifacts:
    when: always
    paths:
      - playwright-report/
      - test-results/
    expire_in: 14 days
  rules:
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH

模式 5:包含应用的自定义 Docker 镜像

使用场景:测试需要与 Playwright 一起运行应用程序,或者你需要自定义系统依赖。 避免场景:官方的 Playwright 镜像加上配置中的 webServer 已能满足你的使用场景。

# .gitlab-ci.yml
stages:
  - test

test:e2e:
  stage: test
  image: mcr.microsoft.com/playwright:v1.52.0-noble
  services:
    - name: postgres:16-alpine
      alias: db
    - name: redis:7-alpine
      alias: cache
  variables:
    CI: "true"
    DATABASE_URL: "postgresql://postgres:postgres@db:5432/test"
    REDIS_URL: "redis://cache:6379"
    POSTGRES_PASSWORD: "postgres"
    POSTGRES_DB: "test"
  before_script:
    - npm ci
    - npx prisma db push
    - npx prisma db seed
  script:
    - npx playwright test
  artifacts:
    when: always
    paths:
      - playwright-report/
      - test-results/
    expire_in: 14 days
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH

模式 6:定时夜间回归测试

使用场景:完整的回归测试对每个合并请求来说太慢了。按计划运行它。

# .gitlab-ci.yml(添加到现有配置)
test:nightly:
  stage: test
  image: mcr.microsoft.com/playwright:v1.52.0-noble
  before_script:
    - npm ci
  script:
    - npx playwright test --grep @regression
  artifacts:
    when: always
    paths:
      - playwright-report/
    expire_in: 30 days
  rules:
    - if: $CI_PIPELINE_SOURCE == "schedule"

CI/CD > Schedules 中设置定时任务:0 3 * * 1-5UTC 时间凌晨 3 点,工作日)。

决策指南

场景 方案 原因
简单项目,测试套件 < 5 分钟 使用 Playwright Docker 镜像的单一 test 作业 无需分片开销;构建产物捕获报告
测试套件 > 10 分钟 使用 --shardparallel: N GitLab 自动分配 CI_NODE_INDEX/CI_NODE_TOTAL
合并请求快速反馈 合并请求上仅运行 Chromium;主分支上运行所有浏览器 合并请求的流水线耗时减少 3 倍
需要外部服务(数据库、Redis 使用 Postgres/Redis 镜像的 services: 关键字 GitLab 管理服务生命周期
预发环境的密钥 GitLab CI/CD 变量(脱敏 + 受保护) 永远不要将密钥硬编码在 .gitlab-ci.yml
完整的夜间回归测试 流水线定时任务(CI_PIPELINE_SOURCE == "schedule" 避免阻塞合并请求流水线
报告浏览 使用 paths: [playwright-report/]artifacts: 直接在 GitLab 作业构建产物 UI 中浏览

反模式

反模式 问题 应改为
未使用 Playwright Docker 镜像 每次运行都安装浏览器,增加 1-2 分钟 使用 mcr.microsoft.com/playwright:v1.52.0-noble 作为基础镜像
仅设置 artifacts: when: on_failure 测试通过时无报告;无法验证结果 使用 when: always 来始终捕获报告
构建产物没有设置 expire_in 构建产物不断累积,消耗存储空间 为报告设置 expire_in: 14 days,为中间构建产物设置 1 hour
使用 parallel: 但没有等价的 fail-fast: false GitLab 默认不会取消同级作业(好),但 allow_failure: false 意味着流水线会快速失败 可接受的默认行为;无需更改
在分片标志中硬编码 CI_NODE_TOTAL 当更改 parallel: 值时就会失效 使用 --shard=$CI_NODE_INDEX/$CI_NODE_TOTAL
在阶段之间跳过 needs: 作业会等待前一阶段的所有作业,而不仅仅是其依赖项 使用 needs: 实现精确的依赖图
包含 node_modules/cache: 没有 key 过期的缓存导致版本冲突 将缓存键设置为基于 package-lock.json 的哈希

故障排查

浏览器启动失败:"Failed to launch browser"

原因:未使用 Playwright Docker 镜像,或使用的版本与你的 @playwright/test 版本不匹配。

修复:将 Docker 镜像标签与你的 Playwright 版本匹配:

# 检查你的版本
# npm ls @playwright/test  ->  @playwright/test@1.52.0
image: mcr.microsoft.com/playwright:v1.52.0-noble

测试在 GitLab runner 中挂起:"Navigation timeout exceeded"

原因GitLab 共享 runner 的资源可能有限。默认超时时间设置过紧。

修复:减少 workers 并增加超时时间:

// playwright.config.ts
import { defineConfig } from "@playwright/test"

export default defineConfig({
  workers: process.env.CI ? 2 : undefined,
  use: {
    navigationTimeout: process.env.CI ? 30_000 : 15_000,
  },
})

流水线在每次推送时都运行,而不仅仅是合并请求

原因:缺少 rules: 配置。GitLab 的默认行为是在每次推送时都运行。

修复:添加明确的规则:

rules:
  - if: $CI_PIPELINE_SOURCE == "merge_request_event"
  - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH

测试无法访问服务(Postgres/Redis

原因:使用了 localhost 而不是服务别名。

修复:使用服务别名作为主机名:

services:
  - name: postgres:16-alpine
    alias: db # <-- 使用 "db" 作为主机名

variables:
  DATABASE_URL: "postgresql://postgres:postgres@db:5432/test" # 不是 localhost

分片运行后合并报告为空

原因:每个分片作业需要 blob 报告器,而不是 html。合并步骤会创建 HTML 报告。

修复:为 CI 配置 blob 报告器:

// playwright.config.ts
import { defineConfig } from "@playwright/test"

export default defineConfig({
  reporter: process.env.CI ? [["blob"], ["dot"]] : [["html", { open: "on-failure" }]],
})

相关文档