Jenkins blocks JavaScript in HTML reports by default: the Content Security Policy header prevents the Playwright report from rendering unless you explicitly relax it in Jenkins Script Console or the HTML Publisher plugin settings. The other common failure is missing system libraries on the agent, which the official Playwright Docker image fixes by packaging all browser dependencies. This guide covers the complete Jenkinsfile from minimal working example to multi-stage pipeline with parallel browser execution, sharding across agents, secrets management, and scheduled nightly runs.

Why Jenkins Is Still Relevant

  • Many enterprises have decade-long investments in Jenkins infrastructure
  • On-premise hosting for security/compliance requirements
  • Highly customizable — plugins for virtually everything
  • Some CI/CD setups are Jenkins + Kubernetes at scale

If your company uses Jenkins, you can't just switch to GitHub Actions. You work with what you have.

Prerequisites

  • Jenkins installed (on-premise or via Jenkins in Docker)
  • Playwright project in Git (GitHub, GitLab, Bitbucket, etc.)
  • Jenkins plugins: Pipeline, Git, HTML Publisher, JUnit

Basic Jenkinsfile

Jenkins pipelines are defined in a Jenkinsfile at the root of your repository. There are two syntaxes — Declarative (structured) and Scripted (Groovy). Use Declarative unless you need advanced logic.

// Jenkinsfile
pipeline {
    agent {
        docker {
            image 'mcr.microsoft.com/playwright:v1.44.0-jammy'
            args '-u root'  // Run as root to avoid permission issues
        }
    }
    
    environment {
        BASE_URL = credentials('staging-base-url')  // From Jenkins credentials
        CI = 'true'
    }
    
    stages {
        stage('Install') {
            steps {
                sh 'npm ci'
            }
        }
        
        stage('Run Tests') {
            steps {
                sh 'npx playwright test --reporter=list,junit'
            }
            post {
                always {
                    // Publish JUnit results
                    junit 'test-results/results.xml'
                    
                    // Publish HTML report
                    publishHTML([
                        allowMissing: false,
                        alwaysLinkToLastBuild: true,
                        keepAll: true,
                        reportDir: 'playwright-report',
                        reportFiles: 'index.html',
                        reportName: 'Playwright Report'
                    ])
                }
            }
        }
    }
    
    post {
        failure {
            // Notify on failure
            emailext(
                subject: "FAILED: ${env.JOB_NAME} #${env.BUILD_NUMBER}",
                body: "Tests failed. See: ${env.BUILD_URL}",
                to: 'qa-team@mycompany.com'
            )
        }
    }
}

Multi-Stage Pipeline

A realistic pipeline has more stages — linting, unit tests, then E2E:

pipeline {
    agent {
        docker {
            image 'mcr.microsoft.com/playwright:v1.44.0-jammy'
            args '-u root'
        }
    }
    
    environment {
        BASE_URL = credentials('staging-url')
        NODE_ENV = 'test'
    }
    
    stages {
        stage('Install Dependencies') {
            steps {
                sh 'npm ci'
            }
        }
        
        stage('Lint') {
            steps {
                sh 'npm run lint'
            }
        }
        
        stage('Unit Tests') {
            steps {
                sh 'npm run test:unit -- --reporter=junit'
            }
            post {
                always {
                    junit 'unit-test-results/*.xml'
                }
            }
        }
        
        stage('Smoke Tests') {
            steps {
                sh '''
                    npx playwright test \
                        --grep @smoke \
                        --project=chromium \
                        --reporter=list,junit
                '''
            }
            post {
                always {
                    junit 'test-results/results.xml'
                }
            }
        }
        
        stage('Full Regression') {
            when {
                anyOf {
                    branch 'main'
                    branch 'release/*'
                }
            }
            steps {
                sh '''
                    npx playwright test \
                        --workers=4 \
                        --reporter=list,junit,html
                '''
            }
            post {
                always {
                    junit 'test-results/results.xml'
                    publishHTML([
                        reportDir: 'playwright-report',
                        reportFiles: 'index.html',
                        reportName: 'Full Regression Report',
                        keepAll: true
                    ])
                }
            }
        }
    }
}

Parallel Test Execution

Run tests across multiple browsers in parallel using Jenkins' parallel step:

stage('Cross-Browser Tests') {
    parallel {
        stage('Chrome') {
            steps {
                sh 'npx playwright test --project=chromium --reporter=junit'
            }
            post {
                always {
                    junit 'test-results/chromium-results.xml'
                }
            }
        }
        
        stage('Firefox') {
            steps {
                sh 'npx playwright test --project=firefox --reporter=junit'
            }
            post {
                always {
                    junit 'test-results/firefox-results.xml'
                }
            }
        }
        
        stage('Safari') {
            steps {
                sh 'npx playwright test --project=webkit --reporter=junit'
            }
            post {
                always {
                    junit 'test-results/webkit-results.xml'
                }
            }
        }
    }
}

For this to work, your playwright.config.ts must output to separate files per project:

reporter: [
  ['junit', { 
    outputFile: `test-results/${process.env.BROWSER || 'all'}-results.xml` 
  }],
],

And run with:

BROWSER=chromium npx playwright test --project=chromium

Sharding Across Multiple Agents

For large test suites, split across multiple Jenkins agents:

pipeline {
    agent none  // Each stage picks its own agent
    
    stages {
        stage('Test') {
            parallel {
                stage('Shard 1/3') {
                    agent { docker { image 'mcr.microsoft.com/playwright:v1.44.0-jammy' } }
                    steps {
                        sh 'npm ci'
                        sh 'npx playwright test --shard=1/3 --reporter=blob'
                    }
                    post {
                        always {
                            archiveArtifacts 'blob-report/**'
                        }
                    }
                }
                
                stage('Shard 2/3') {
                    agent { docker { image 'mcr.microsoft.com/playwright:v1.44.0-jammy' } }
                    steps {
                        sh 'npm ci'
                        sh 'npx playwright test --shard=2/3 --reporter=blob'
                    }
                    post {
                        always {
                            archiveArtifacts 'blob-report/**'
                        }
                    }
                }
                
                stage('Shard 3/3') {
                    agent { docker { image 'mcr.microsoft.com/playwright:v1.44.0-jammy' } }
                    steps {
                        sh 'npm ci'
                        sh 'npx playwright test --shard=3/3 --reporter=blob'
                    }
                    post {
                        always {
                            archiveArtifacts 'blob-report/**'
                        }
                    }
                }
            }
        }
        
        stage('Merge Reports') {
            agent { docker { image 'mcr.microsoft.com/playwright:v1.44.0-jammy' } }
            steps {
                // Download artifacts from all shards
                copyArtifacts(projectName: env.JOB_NAME, selector: specific(env.BUILD_NUMBER))
                sh 'npx playwright merge-reports --reporter html,junit ./blob-report'
            }
            post {
                always {
                    junit 'test-results/results.xml'
                    publishHTML([
                        reportDir: 'playwright-report',
                        reportFiles: 'index.html',
                        reportName: 'Merged Report'
                    ])
                }
            }
        }
    }
}

Credentials and Secrets

Never hardcode credentials in Jenkinsfile. Use Jenkins Credentials Manager:

environment {
    // String credential
    BASE_URL = credentials('staging-base-url')
    
    // Username + password credential (creates two env vars)
    ADMIN = credentials('admin-credentials')
    // Creates: ADMIN_USR (username) and ADMIN_PSW (password)
}

steps {
    withCredentials([
        string(credentialsId: 'stripe-test-key', variable: 'STRIPE_KEY'),
        usernamePassword(
            credentialsId: 'db-credentials',
            usernameVariable: 'DB_USER',
            passwordVariable: 'DB_PASS'
        )
    ]) {
        sh 'npx playwright test'
    }
}

Triggering Tests

On every push

triggers {
    // Poll SCM every 5 minutes (less ideal than webhooks)
    pollSCM('H/5 * * * *')
}

Better: configure webhook in GitHub/GitLab to trigger Jenkins builds automatically.

Scheduled runs (nightly)

triggers {
    // Run at 2 AM every night
    cron('0 2 * * *')
}

On PR creation

Use the GitHub Branch Source or Multibranch Pipeline plugin. Jenkins automatically runs tests on every PR and reports status back to GitHub.

Common Jenkins + Playwright Issues

"No such file or directory: /home/pwuser/..."

Playwright runs as a non-root user inside its Docker image. Add args '-u root' to the docker agent or adjust file paths.

"Failed to launch chromium: error while loading shared libraries"

Missing system dependencies. Use the official Playwright Docker image — it has everything pre-installed.

HTML report not showing in Jenkins

Jenkins' Content Security Policy blocks JavaScript in HTML reports. Run this in Jenkins Script Console:

System.setProperty("hudson.model.DirectoryBrowserSupport.CSP", "")

Or use the HTML Publisher plugin configuration to relax CSP.

Tests pass locally, fail in Jenkins

Check: environment variables, base URL, browser sandbox settings. Add --no-sandbox flag if needed (Docker containers often need this for Chromium).

Minimal Working Jenkinsfile

If you just want something that works:

pipeline {
    agent {
        docker {
            image 'mcr.microsoft.com/playwright:v1.44.0-jammy'
            args '-u root'
        }
    }
    stages {
        stage('Test') {
            steps {
                sh 'npm ci'
                sh 'npx playwright test --reporter=junit'
            }
            post {
                always {
                    junit 'test-results/results.xml'
                }
            }
        }
    }
}

This is the minimum. Start here, then add stages, parallel execution, and notifications as needed.

Summary

| Concept | Implementation |

|---------|---------------|

| Agent | Official Playwright Docker image |

| Secrets | Jenkins Credentials Manager |

| Results | JUnit plugin + publishHTML |

| Parallel | parallel {} block or multiple agents |

| Sharding | --shard=X/Y + merge-reports |

| Scheduling | cron() trigger |

| On PR | GitHub Branch Source plugin + webhook |

Jenkins is more work than GitHub Actions, but once configured it's stable and powerful. The Jenkinsfile approach (pipeline-as-code) means your CI configuration lives in Git alongside your tests — version-controlled, reviewable, and reproducible.

→ See also: CI/CD for QA: GitHub Actions, Jenkins, and GitLab Compared | GitHub Actions for Playwright Tests: The Complete Setup (2026) | Parallel Execution in Playwright: Workers, Shards, and Sharding for Speed