Skip to content

CI/CD Integration

CI/CD Integration

This guide covers running Stepwright scripts in CI/CD pipelines, including GitHub Actions, GitLab CI, and Jenkins.

Prerequisites

  • Scripts configured for headless mode
  • Artifacts directory accessible for upload
  • Environment variables for secrets

GitHub Actions

Basic Workflow

.github/workflows/automation.yml
name: Automation Tests
on:
push:
branches: [main]
pull_request:
branches: [main]
schedule:
- cron: '0 */6 * * *' # Every 6 hours
jobs:
test:
runs-on: ubuntu-latest
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 chromium --with-deps
- name: Run automation scripts
run: npx stepwright run ./scripts/main.ts --json ./results.json
env:
HEADLESS: 'true'
- name: Upload results
if: always()
uses: actions/upload-artifact@v4
with:
name: results
path: results.json
- name: Upload failure artifacts
if: failure()
uses: actions/upload-artifact@v4
with:
name: artifacts
path: .stepwright/artifacts/

With Fixwright Auto-Fix

.github/workflows/automation-with-fix.yml
name: Automation with Auto-Fix
on:
push:
branches: [main]
workflow_dispatch:
jobs:
test:
runs-on: ubuntu-latest
outputs:
failed: ${{ steps.run.outputs.failed }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- run: npx playwright install chromium --with-deps
- name: Run automation
id: run
run: |
npx stepwright run ./scripts/main.ts --json ./results.json || echo "failed=true" >> $GITHUB_OUTPUT
continue-on-error: true
- name: Save failure case
if: steps.run.outputs.failed == 'true'
run: npx tsx scripts/generate-failure-case.ts
- name: Upload failure case
if: steps.run.outputs.failed == 'true'
uses: actions/upload-artifact@v4
with:
name: failure-case
path: failure-cases/
fix:
needs: test
if: needs.test.outputs.failed == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- name: Download failure case
uses: actions/download-artifact@v4
with:
name: failure-case
path: failure-cases/
- name: Run Fixwright
run: npx tsx scripts/fix-failures.ts
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

Matrix Testing

Run scripts across multiple configurations:

jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
browser: [chromium, firefox, webkit]
script: [login, checkout, search]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm ci
- run: npx playwright install ${{ matrix.browser }} --with-deps
- name: Run ${{ matrix.script }} on ${{ matrix.browser }}
run: |
npx stepwright run ./scripts/${{ matrix.script }}.ts \
--browser ${{ matrix.browser }} \
--json ./results-${{ matrix.browser }}-${{ matrix.script }}.json

GitLab CI

Basic Pipeline

.gitlab-ci.yml
stages:
- test
- fix
variables:
NODE_VERSION: "20"
automation:
stage: test
image: mcr.microsoft.com/playwright:v1.40.0-jammy
script:
- npm ci
- npx stepwright run ./scripts/main.ts --json ./results.json
artifacts:
when: always
paths:
- results.json
- .stepwright/artifacts/
expire_in: 1 week
rules:
- if: $CI_PIPELINE_SOURCE == "schedule"
- if: $CI_COMMIT_BRANCH == "main"
fix-failures:
stage: fix
image: node:20
needs:
- job: automation
artifacts: true
script:
- npm ci
- npx tsx scripts/fix-failures.ts
variables:
ANTHROPIC_API_KEY: $ANTHROPIC_API_KEY
GITHUB_TOKEN: $GITHUB_TOKEN
rules:
- if: $CI_JOB_STATUS == "failed"
when: on_failure

Jenkins

Declarative Pipeline

Jenkinsfile
pipeline {
agent {
docker {
image 'mcr.microsoft.com/playwright:v1.40.0-jammy'
}
}
environment {
NODE_OPTIONS = '--max-old-space-size=4096'
}
stages {
stage('Install') {
steps {
sh 'npm ci'
}
}
stage('Run Automation') {
steps {
sh 'npx stepwright run ./scripts/main.ts --json ./results.json'
}
post {
always {
archiveArtifacts artifacts: 'results.json', fingerprint: true
}
failure {
archiveArtifacts artifacts: '.stepwright/artifacts/**/*'
}
}
}
stage('Fix Failures') {
when {
expression { currentBuild.result == 'FAILURE' }
}
steps {
withCredentials([
string(credentialsId: 'anthropic-api-key', variable: 'ANTHROPIC_API_KEY'),
string(credentialsId: 'github-token', variable: 'GITHUB_TOKEN')
]) {
sh 'npx tsx scripts/fix-failures.ts'
}
}
}
}
post {
always {
cleanWs()
}
}
}

Environment Configuration

Script Configuration

Detect CI environment and configure appropriately:

scripts/main.ts
import { Stepwright } from '@korvol/stepwright';
const isCI = process.env.CI === 'true';
const script = Stepwright.create('Main Flow')
.config({
headless: isCI || process.env.HEADLESS === 'true',
screenshotOnFailure: true,
domOnFailure: true,
video: isCI ? { enabled: true, dir: './videos' } : undefined,
defaultTimeout: isCI ? 60000 : 30000,
});

Environment Variables

env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
BASE_URL: ${{ vars.BASE_URL }}

Handling Failures

Exit Codes

Stepwright CLI uses standard exit codes:

  • 0 - Success
  • 1 - Script failed
  • 2 - Error (syntax, import, etc.)

Use in conditionals:

Terminal window
npx stepwright run ./scripts/main.ts || {
echo "Script failed, generating failure case"
npx tsx scripts/generate-failure-case.ts
}

Notification Integration

scripts/notify.ts
import { Stepwright, JSONReporter } from '@korvol/stepwright';
const script = Stepwright.create('With Notifications')
.reporter(new JSONReporter({ outputPath: './results.json' }));
// After run
const result = await script.run();
if (!result.success) {
// Send to Slack
await fetch(process.env.SLACK_WEBHOOK!, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
text: `Automation failed: ${result.failedStep?.name}`,
attachments: [{
color: 'danger',
fields: [{
title: 'Error',
value: result.failedStep?.error.message,
}],
}],
}),
});
}

Docker Support

Custom Dockerfile

Dockerfile
FROM mcr.microsoft.com/playwright:v1.40.0-jammy
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
CMD ["npx", "stepwright", "run", "./scripts/main.ts"]

Docker Compose

docker-compose.yml
services:
automation:
build: .
environment:
- HEADLESS=true
volumes:
- ./results:/app/results
- ./artifacts:/app/.stepwright/artifacts

Scheduling

Cron Schedules

on:
schedule:
- cron: '0 */6 * * *' # Every 6 hours
- cron: '0 9 * * 1-5' # 9 AM on weekdays

Best Practices

1. Always Upload Artifacts

- name: Upload artifacts
if: always() # Even on failure
uses: actions/upload-artifact@v4
with:
name: artifacts
path: |
results.json
.stepwright/artifacts/
videos/

2. Use Retries for Flaky Tests

- name: Run with retries
uses: nick-fields/retry@v2
with:
timeout_minutes: 10
max_attempts: 3
command: npx stepwright run ./scripts/main.ts

3. Parallel Execution

strategy:
matrix:
shard: [1, 2, 3, 4]
fail-fast: false
steps:
- run: npx stepwright run ./scripts/main.ts --shard ${{ matrix.shard }}/4

4. Cache Dependencies

- uses: actions/cache@v4
with:
path: |
~/.npm
~/.cache/ms-playwright
key: ${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}

Next Steps