Playwright CI/CD 集成 #

CI/CD 概述 #

将 Playwright 测试集成到 CI/CD 流程,可以在每次代码变更时自动运行测试,确保代码质量。

CI/CD 集成优势 #

text
┌─────────────────────────────────────────────────────────────┐
│                   CI/CD 集成优势                              │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  ✅ 自动化测试 - 每次提交自动运行测试                          │
│  ✅ 早期发现问题 - 在合并前发现回归问题                        │
│  ✅ 团队协作 - 统一的测试环境                                 │
│  ✅ 质量保证 - 防止有问题的代码合并                           │
│  ✅ 报告生成 - 自动生成测试报告                               │
│                                                             │
└─────────────────────────────────────────────────────────────┘

GitHub Actions #

基本配置 #

yaml
# .github/workflows/playwright.yml
name: Playwright Tests

on:
  push:
    branches: [ main, develop ]
  pull_request:
    branches: [ main ]

jobs:
  test:
    timeout-minutes: 60
    runs-on: ubuntu-latest
    
    steps:
    - uses: actions/checkout@v4
    
    - uses: actions/setup-node@v4
      with:
        node-version: 20
    
    - name: Install dependencies
      run: npm ci
    
    - name: Install Playwright Browsers
      run: npx playwright install --with-deps
    
    - name: Run Playwright tests
      run: npx playwright test
    
    - uses: actions/upload-artifact@v4
      if: always()
      with:
        name: playwright-report
        path: playwright-report/
        retention-days: 30

完整配置 #

yaml
# .github/workflows/playwright.yml
name: Playwright Tests

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]
  schedule:
    - cron: '0 0 * * *'  # 每天运行一次

env:
  CI: true

jobs:
  test:
    runs-on: ${{ matrix.os }}
    timeout-minutes: 60
    
    strategy:
      fail-fast: false
      matrix:
        os: [ubuntu-latest, windows-latest, macos-latest]
        browser: [chromium, firefox, webkit]
        include:
          - os: ubuntu-latest
            browser: chromium
            shard: 1/4
          - os: ubuntu-latest
            browser: chromium
            shard: 2/4
          - os: ubuntu-latest
            browser: chromium
            shard: 3/4
          - os: ubuntu-latest
            browser: chromium
            shard: 4/4

    steps:
    - uses: actions/checkout@v4
    
    - name: Setup Node.js
      uses: actions/setup-node@v4
      with:
        node-version: 20
        cache: 'npm'
    
    - name: Install dependencies
      run: npm ci
    
    - name: Install Playwright browsers
      run: npx playwright install --with-deps ${{ matrix.browser }}
    
    - name: Run tests
      run: npx playwright test --project=${{ matrix.browser }} --shard=${{ matrix.shard }}
      env:
        BASE_URL: ${{ secrets.BASE_URL }}
    
    - name: Upload test results
      if: always()
      uses: actions/upload-artifact@v4
      with:
        name: playwright-report-${{ matrix.os }}-${{ matrix.browser }}-${{ strategy.job-index }}
        path: |
          playwright-report/
          test-results/
        retention-days: 30

  report:
    needs: test
    runs-on: ubuntu-latest
    if: always()
    
    steps:
    - uses: actions/checkout@v4
    
    - name: Download all artifacts
      uses: actions/download-artifact@v4
      with:
        path: all-reports
    
    - name: Merge reports
      run: npx playwright merge-reports --reporter html ./all-reports
    
    - name: Upload merged report
      uses: actions/upload-artifact@v4
      with:
        name: merged-playwright-report
        path: playwright-report/
        retention-days: 30

Docker 配置 #

yaml
# .github/workflows/playwright-docker.yml
name: Playwright Tests (Docker)

on:
  push:
    branches: [ main ]

jobs:
  test:
    runs-on: ubuntu-latest
    container:
      image: mcr.microsoft.com/playwright:v1.40.0-jammy
    
    steps:
    - uses: actions/checkout@v4
    
    - name: Install dependencies
      run: npm ci
    
    - name: Run tests
      run: npx playwright test
    
    - uses: actions/upload-artifact@v4
      if: always()
      with:
        name: playwright-report
        path: playwright-report/

GitLab CI #

基本配置 #

yaml
# .gitlab-ci.yml
stages:
  - test

playwright:
  stage: test
  image: mcr.microsoft.com/playwright:v1.40.0-jammy
  script:
    - npm ci
    - npx playwright test
  artifacts:
    when: always
    paths:
      - playwright-report/
    expire_in: 30 days

完整配置 #

yaml
# .gitlab-ci.yml
stages:
  - install
  - test
  - report

variables:
  npm_config_cache: '$CI_PROJECT_DIR/.npm'
  PLAYWRIGHT_BROWSERS_PATH: '$CI_PROJECT_DIR/.cache/ms-playwright'

cache:
  key: ${CI_COMMIT_REF_SLUG}
  paths:
    - .npm/
    - .cache/

install:
  stage: install
  image: node:20
  script:
    - npm ci
    - npx playwright install --with-deps
  artifacts:
    paths:
      - node_modules/
      - .cache/
    expire_in: 1 hour

test:
  stage: test
  image: mcr.microsoft.com/playwright:v1.40.0-jammy
  needs:
    - install
  parallel: 4
  script:
    - npx playwright test --shard=$CI_NODE_INDEX/$CI_NODE_TOTAL
  artifacts:
    when: always
    paths:
      - playwright-report/
      - test-results/
    expire_in: 30 days

merge_reports:
  stage: report
  image: node:20
  needs:
    - test
  script:
    - npm ci
    - npx playwright merge-reports --reporter html ./playwright-report
  artifacts:
    paths:
      - playwright-report/
    expire_in: 30 days

Jenkins #

Jenkinsfile #

groovy
// Jenkinsfile
pipeline {
  agent any
  
  environment {
    NODE_HOME = tool name: 'NodeJS-20', type: 'jenkins.plugins.nodejs.tools.NodeJSInstallation'
    PATH = "${env.NODE_HOME}/bin:${env.PATH}"
  }
  
  stages {
    stage('Checkout') {
      steps {
        checkout scm
      }
    }
    
    stage('Install') {
      steps {
        sh 'npm ci'
        sh 'npx playwright install --with-deps'
      }
    }
    
    stage('Test') {
      steps {
        sh 'npx playwright test'
      }
      post {
        always {
          archiveArtifacts artifacts: 'playwright-report/**/*', allowEmptyArchive: true
          publishHTML target: [
            allowMissing: false,
            alwaysLinkToLastBuild: true,
            keepAll: true,
            reportDir: 'playwright-report',
            reportFiles: 'index.html',
            reportName: 'Playwright Report'
          ]
        }
      }
    }
  }
  
  post {
    always {
      cleanWs()
    }
  }
}

并行执行 #

groovy
// Jenkinsfile (Parallel)
pipeline {
  agent any
  
  stages {
    stage('Test') {
      parallel {
        stage('Chromium') {
          steps {
            sh 'npx playwright test --project=chromium'
          }
        }
        stage('Firefox') {
          steps {
            sh 'npx playwright test --project=firefox'
          }
        }
        stage('WebKit') {
          steps {
            sh 'npx playwright test --project=webkit'
          }
        }
      }
    }
  }
}

CircleCI #

基本配置 #

yaml
# .circleci/config.yml
version: 2.1

orbs:
  node: circleci/node@5

jobs:
  test:
    docker:
      - image: mcr.microsoft.com/playwright:v1.40.0-jammy
    steps:
      - checkout
      - node/install-packages:
          pkg-manager: npm
      - run:
          name: Run Playwright tests
          command: npx playwright test
      - store_artifacts:
          path: playwright-report/
          destination: playwright-report

workflows:
  test:
    jobs:
      - test

并行执行 #

yaml
# .circleci/config.yml
version: 2.1

orbs:
  node: circleci/node@5

jobs:
  test:
    parallelism: 4
    docker:
      - image: mcr.microsoft.com/playwright:v1.40.0-jammy
    steps:
      - checkout
      - node/install-packages:
          pkg-manager: npm
      - run:
          name: Run Playwright tests
          command: |
            SHARD=$((${CIRCLE_NODE_INDEX}+1))
            npx playwright test --shard=${SHARD}/${CIRCLE_NODE_TOTAL}
      - store_artifacts:
          path: playwright-report/

workflows:
  test:
    jobs:
      - test

Azure DevOps #

基本配置 #

yaml
# azure-pipelines.yml
trigger:
  - main

pool:
  vmImage: 'ubuntu-latest'

steps:
  - task: NodeTool@0
    inputs:
      versionSpec: '20.x'
    displayName: 'Install Node.js'

  - script: npm ci
    displayName: 'Install dependencies'

  - script: npx playwright install --with-deps
    displayName: 'Install Playwright browsers'

  - script: npx playwright test
    displayName: 'Run Playwright tests'

  - task: PublishTestResults@2
    inputs:
      testResultsFiles: 'test-results/junit.xml'
      testRunTitle: 'Playwright Tests'
    condition: succeededOrFailed()

  - task: PublishBuildArtifacts@1
    inputs:
      PathtoPublish: 'playwright-report'
      ArtifactName: 'PlaywrightReport'
    condition: succeededOrFailed()

Docker 镜像 #

使用官方镜像 #

yaml
# GitHub Actions
jobs:
  test:
    runs-on: ubuntu-latest
    container:
      image: mcr.microsoft.com/playwright:v1.40.0-jammy

自定义 Dockerfile #

dockerfile
# Dockerfile
FROM mcr.microsoft.com/playwright:v1.40.0-jammy

WORKDIR /app

COPY package*.json ./
RUN npm ci

COPY . .

RUN npx playwright install

CMD ["npx", "playwright", "test"]

测试分片 #

配置分片 #

bash
# 将测试分成 4 份,运行第 1 份
npx playwright test --shard=1/4

# 运行第 2 份
npx playwright test --shard=2/4

GitHub Actions 分片 #

yaml
strategy:
  matrix:
    shard: [1/4, 2/4, 3/4, 4/4]

steps:
  - name: Run tests
    run: npx playwright test --shard=${{ matrix.shard }}

报告合并 #

合并多个报告 #

bash
# 合并报告
npx playwright merge-reports --reporter html ./blob-reports

GitHub Actions 合并报告 #

yaml
jobs:
  test:
    # ... 测试作业
    
  merge-reports:
    needs: test
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/download-artifact@v4
        with:
          path: all-reports
      - run: npx playwright merge-reports --reporter html ./all-reports

通知配置 #

Slack 通知 #

yaml
# GitHub Actions
- name: Notify Slack on failure
  if: failure()
  uses: slackapi/slack-github-action@v1
  with:
    channel-id: 'C0123456789'
    slack-message: 'Playwright tests failed: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}'
  env:
    SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}

邮件通知 #

yaml
# GitLab CI
notify_failure:
  stage: .post
  script:
    - echo "Sending failure notification"
  when: on_failure
  tags:
    - docker
  image: alpine
  before_script:
    - apk add --no-cache curl
  script:
    - |
      curl -X POST -H 'Content-type: application/json' \
      --data '{"text":"Playwright tests failed!"}' \
      $WEBHOOK_URL

最佳实践 #

1. 使用缓存 #

yaml
# GitHub Actions
- name: Cache node modules
  uses: actions/cache@v4
  with:
    path: |
      ~/.npm
      node_modules
    key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
    restore-keys: |
      ${{ runner.os }}-node-

2. 设置超时 #

yaml
jobs:
  test:
    timeout-minutes: 60

3. 条件执行 #

yaml
# 只在特定分支运行
on:
  push:
    branches: [ main ]

# 排除特定文件
on:
  push:
    paths-ignore:
      - '**.md'
      - 'docs/**'

4. 环境变量管理 #

yaml
env:
  CI: true
  BASE_URL: ${{ secrets.BASE_URL }}

steps:
  - name: Run tests
    run: npx playwright test
    env:
      TEST_USERNAME: ${{ secrets.TEST_USERNAME }}
      TEST_PASSWORD: ${{ secrets.TEST_PASSWORD }}

下一步 #

现在你已经掌握了 CI/CD 集成,接下来学习 最佳实践 了解更多测试技巧!

最后更新:2026-03-28