13 KiB
CI:GitLab 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-5(UTC 时间凌晨 3 点,工作日)。
决策指南
| 场景 | 方案 | 原因 |
|---|---|---|
| 简单项目,测试套件 < 5 分钟 | 使用 Playwright Docker 镜像的单一 test 作业 |
无需分片开销;构建产物捕获报告 |
| 测试套件 > 10 分钟 | 使用 --shard 的 parallel: 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" }]],
})
相关文档
- ci/ci-github-actions.md —— GitHub Actions 的等效配置
- ci/ci-other.md —— CircleCI、Azure DevOps、Jenkins
- ci/parallel-and-sharding.md —— 分片策略
- ci/docker-and-containers.md —— Docker 镜像详情
- ci/reporting-and-artifacts.md —— 报告器配置