Skip to content

Latest commit

 

History

History
421 lines (344 loc) · 10.8 KB

File metadata and controls

421 lines (344 loc) · 10.8 KB

CI: GitLab CI/CD

When to use: Running Playwright tests in GitLab pipelines on merge requests, merges to main, or scheduled pipelines.

Quick Reference

# Key commands used in GitLab pipelines
npx playwright install --with-deps    # install browsers + OS deps
npx playwright test --shard=1/4       # run 1 of 4 parallel shards
npx playwright merge-reports ./blob-report  # merge shard results
npx playwright test --reporter=dot    # minimal output for CI logs

Patterns

Pattern 1: Production-Ready Pipeline (Copy-Paste Starter)

Use when: Any GitLab project with Playwright tests. This is the complete, recommended configuration.

# .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 node_modules and npm cache across pipelines
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

Pattern 2: Parallel Sharded Execution

Use when: Test suite exceeds 10 minutes. Use GitLab's parallel keyword to split across jobs automatically. Avoid when: Suite runs under 5 minutes.

# .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

Config for sharded pipelines:

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

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

Pattern 3: Merge Request Pipelines with Environment Variables

Use when: Tests need secrets (API keys, passwords) and should only run on merge requests or the default branch. Avoid when: Tests are fully self-contained with no external dependencies.

# .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:
    # Run on merge requests
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    # Run on default branch pushes
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
    # Allow manual trigger
    - when: manual
      allow_failure: true

Setting variables in GitLab: Navigate to Settings > CI/CD > Variables and add:

  • STAGING_URL -- not masked, not protected
  • TEST_PASSWORD -- masked, protected
  • API_KEY -- masked, protected

Pattern 4: Multi-Browser Testing with Child Pipelines

Use when: Running Chromium on MRs and all browsers on the default branch. Avoid when: You only test one browser.

# .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 only on merge requests (fast feedback)
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"

# All browsers on default branch
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

Pattern 5: Custom Docker Image with Application

Use when: Tests need the application running alongside Playwright, or you need custom system dependencies. Avoid when: The official Playwright image plus webServer in config handles your use case.

# .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

Pattern 6: Scheduled Nightly Regression

Use when: Full regression is too slow for every MR. Run it on a schedule.

# .gitlab-ci.yml (add to existing config)
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"

Set up the schedule in CI/CD > Schedules: 0 3 * * 1-5 (3 AM UTC, weekdays).

Decision Guide

Scenario Approach Why
Simple project, < 5 min suite Single test job using Playwright Docker image No sharding overhead; artifacts capture report
Suite > 10 min parallel: N with --shard GitLab auto-assigns CI_NODE_INDEX/CI_NODE_TOTAL
Merge request fast feedback Chromium only on MRs; all browsers on main 3x fewer pipeline minutes on MRs
External services needed (DB, Redis) services: keyword with Postgres/Redis images GitLab manages service lifecycle
Secrets for staging environment GitLab CI/CD Variables (masked + protected) Never hardcode secrets in .gitlab-ci.yml
Full nightly regression Pipeline schedule (CI_PIPELINE_SOURCE == "schedule") Avoids blocking MR pipelines
Report browsing artifacts: with paths: [playwright-report/] Browse directly in GitLab job artifacts UI

Anti-Patterns

Anti-Pattern Problem Do This Instead
Not using the Playwright Docker image Installing browsers every run adds 1-2 minutes Use mcr.microsoft.com/playwright:v1.52.0-noble as base image
artifacts: when: on_failure only No report when tests pass; can't verify results Use when: always to capture reports regardless
No expire_in on artifacts Artifacts accumulate and consume storage Set expire_in: 14 days for reports, 1 hour for intermediate artifacts
parallel: without fail-fast: false equivalent GitLab does not cancel siblings by default (good), but allow_failure: false means the pipeline fails fast Acceptable default behavior; no change needed
Hardcoding CI_NODE_TOTAL in shard flag Breaks when you change parallel: value Use --shard=$CI_NODE_INDEX/$CI_NODE_TOTAL
Skipping needs: between stages Jobs wait for all previous stage jobs, not just their dependencies Use needs: for precise dependency graphs
Large cache: including node_modules/ without key Stale cache causes version conflicts Key cache on package-lock.json hash

Troubleshooting

Browser launch fails: "Failed to launch browser"

Cause: Not using the Playwright Docker image, or using a version that doesn't match your @playwright/test version.

Fix: Match the Docker image tag to your Playwright version:

# Check your version
# npm ls @playwright/test  ->  @playwright/test@1.52.0
image: mcr.microsoft.com/playwright:v1.52.0-noble

Tests hang in GitLab runner: "Navigation timeout exceeded"

Cause: GitLab shared runners may have limited resources. Default timeouts too tight.

Fix: Reduce workers and increase timeouts:

// 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,
  },
});

Pipeline runs on every push, not just merge requests

Cause: Missing rules: configuration. Default GitLab behavior runs on every push.

Fix: Add explicit rules:

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

Services (Postgres/Redis) not reachable from tests

Cause: Using localhost instead of the service alias.

Fix: Use the service alias as hostname:

services:
  - name: postgres:16-alpine
    alias: db  # <-- use "db" as hostname

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

Merged report is empty after sharded run

Cause: Each shard job needs the blob reporter, not html. The merge step creates the HTML report.

Fix: Configure blob reporter for CI:

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

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

Related