# CI:GitLab CI/CD > **使用场景**:在 GitLab 流水线中针对合并请求、推送到主分支或定时流水线运行 Playwright 测试。 ## 快速参考 ```bash # 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 项目。这是完整且推荐的配置。 ```yaml # .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 分钟。 ```yaml # .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 ``` **分片流水线的配置:** ```ts // playwright.config.ts import { defineConfig } from "@playwright/test" export default defineConfig({ reporter: process.env.CI ? [["blob"], ["dot"]] : [["html", { open: "on-failure" }]], }) ``` ### 模式 3:含环境变量的合并请求流水线 **使用场景**:测试需要密钥(API 密钥、密码),且应仅在合并请求或默认分支上运行。 **避免场景**:测试完全自包含,无外部依赖。 ```yaml # .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,在默认分支上运行所有浏览器。 **避免场景**:你只测试一个浏览器。 ```yaml # .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` 已能满足你的使用场景。 ```yaml # .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:定时夜间回归测试 **使用场景**:完整的回归测试对每个合并请求来说太慢了。按计划运行它。 ```yaml # .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 版本匹配: ```yaml # 检查你的版本 # 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 并增加超时时间: ```ts // 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 的默认行为是在每次推送时都运行。 **修复**:添加明确的规则: ```yaml rules: - if: $CI_PIPELINE_SOURCE == "merge_request_event" - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH ``` ### 测试无法访问服务(Postgres/Redis) **原因**:使用了 `localhost` 而不是服务别名。 **修复**:使用服务别名作为主机名: ```yaml services: - name: postgres:16-alpine alias: db # <-- 使用 "db" 作为主机名 variables: DATABASE_URL: "postgresql://postgres:postgres@db:5432/test" # 不是 localhost ``` ### 分片运行后合并报告为空 **原因**:每个分片作业需要 `blob` 报告器,而不是 `html`。合并步骤会创建 HTML 报告。 **修复**:为 CI 配置 blob 报告器: ```ts // 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](ci-github-actions.md) —— GitHub Actions 的等效配置 - [ci/ci-other.md](ci-other.md) —— CircleCI、Azure DevOps、Jenkins - [ci/parallel-and-sharding.md](parallel-and-sharding.md) —— 分片策略 - [ci/docker-and-containers.md](docker-and-containers.md) —— Docker 镜像详情 - [ci/reporting-and-artifacts.md](reporting-and-artifacts.md) —— 报告器配置