Skip to main content

Jenkins CI

Serenity/JS integrates with Jenkins to run your acceptance tests and publish interactive HTML reports with trend history, flaky test detection, and error clustering.

In this guide, you'll learn how to configure Jenkins pipelines that:

Before you start

Set up a working Serenity/JS test suite using one of the official Serenity/JS Project Templates, or add Serenity/JS to your existing project by following the Serenity/JS installation guide.

If you're new to Serenity/JS, follow the tutorial to learn more about the framework.

Running Serenity/JS on Jenkins

Jenkins pipelines can run inside Docker containers using the agent { docker } directive.

To ensure a stable, reproducible testing environment, use the official Serenity/JS Docker image as your build agent. It comes pre-configured with:

  • The latest Long-Term Support (LTS) version of Node.js
  • All Playwright browser engines, plus stable Chrome and Edge
  • OpenJDK Java Runtime Environment (for teams also using Serenity BDD Reporter)
Why use a Docker agent?

Running tests inside a container eliminates environment drift between developer machines, Jenkins agents, and other CI environments. Browser versions, system dependencies, and font rendering all stay consistent — reducing flaky failures caused by infrastructure differences rather than product bugs.

Prerequisites

Ensure the following Jenkins plugins are installed:

Single-module project

A single-module project has one test suite that runs in a single pipeline. This is the most common setup for small to medium projects.

The HtmlReporter crew member handles both data collection and report generation automatically — no separate aggregation step is needed.

Basic pipeline

Jenkinsfile

--ipc=host

The --ipc=host argument prevents Chromium from running out of shared memory in containerised environments. Without it, browser tests may crash with "out of memory" errors on agents with limited /dev/shm.

Preserving trend history

To enable trend analysis across builds, restore the previous report's test-runs/ directory before running tests. The simplest approach is to archive the report and use the Copy Artifact plugin to restore it from the last successful build:

Jenkinsfile

How trend history works:

  1. The "Restore history" stage copies test-runs/ from the last successful build into the workspace.
  2. When tests run, the HtmlReporter writes new data to reports/serenity-js/test-runs/<runId>/ and aggregates all available runs into the final report.
  3. After tests complete, archiveArtifacts preserves the full report directory for the next build to restore.

Use the maxHistory option to control how many runs are retained.

Copy Artifact plugin

The "Restore history" stage requires the Copy Artifact plugin.

Multi-module project

A multi-module project runs tests across multiple parallel stages — for example, testing separate applications, browser variants, or sharded test suites. Each stage produces its own test data, and a final stage aggregates everything into one report.

Example: admin-ui and customer-ui

Consider a monorepo with two UI modules, each with its own test suite:

my-project/
├── modules/
│ ├── admin-ui/
│ │ ├── spec/
│ │ └── playwright.config.ts
│ └── customer-ui/
│ ├── spec/
│ └── playwright.config.ts
└── package.json

Step 1: Configure each module to archive data only

In each module's playwright.config.ts, use TestRunArchiver instead of the full HtmlReporter:

modules/admin-ui/playwright.config.ts
import { defineConfig } from '@playwright/test';
import type { SerenityFixtures, SerenityWorkerFixtures } from '@serenity-js/playwright-test';

export default defineConfig<SerenityFixtures, SerenityWorkerFixtures>({
testDir: './spec',

reporter: [
['line'],
['@serenity-js/playwright-test', {
crew: [
['@serenity-js/html-reporter:TestRunArchiver', {
outputDirectory: './reports/serenity-js',
specDirectory: './spec',
}],
]
}]
],
});

Step 2: Run tests in parallel and aggregate

Use Jenkins parallel stages to run modules concurrently, then aggregate in a final stage:

Jenkinsfile

What happens:

  1. Both modules run in parallel. Each produces a test-runs/ directory in its own reports/serenity-js/.
  2. The "Aggregate report" stage combines all module data plus the restored historical data into a single report.
  3. The post block archives the combined report and publishes it via the HTML Publisher plugin.

Controlling report history

The maxHistory option limits how many test runs are retained. Without it, the report grows indefinitely.

['@serenity-js/html-reporter', {
outputDirectory: './reports/serenity-js',
maxHistory: 20, // keep the last 20 runs
}]

For the CLI aggregate command:

npx @serenity-js/html-reporter aggregate \
--input "..." \
--output ./reports/serenity-js \
--max-history 20
Choosing a maxHistory value

A good starting value is the number of builds you'd realistically compare when investigating a regression. For most teams, 10–20 runs provides useful trend data without bloating artifact storage.

Generating JUnit reports

Jenkins natively recognises JUnit XML reports and surfaces test results in the build dashboard, including trend graphs and failure details.

Serenity/JS integrates with the native reporters offered by all supported test runners, including those producing JUnit reports:

To surface test results in Jenkins, add a junit post step:

Jenkinsfile
post {
always {
junit(
testResults: 'reports/junit-results.xml',
allowEmptyResults: true,
)
publishHTML(target: [
reportName: 'Serenity Report',
reportDir: 'reports/serenity-js',
reportFiles: 'index.html',
keepAll: true,
alwaysLinkToLastBuild: true,
allowMissing: true,
])
}
}
Content Security Policy

By default, Jenkins blocks inline JavaScript in published HTML reports via its Content Security Policy. The Serenity/JS HTML Report requires JavaScript to function. To allow it, configure the CSP header in Manage Jenkins → Script Console:

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

For a persistent fix, add this to your Jenkins startup arguments or use the Permissive Script Security plugin.

Using Serenity BDD Reporter

If you're using @serenity-js/serenity-bdd instead of the HTML Reporter, your pipeline needs a serenity-bdd run step after tests complete to generate the HTML report.

The official Serenity/JS Docker image includes OpenJDK, so no additional Java setup is required.

Jenkinsfile
stage('Test') {
steps {
sh 'npm test'
// package.json: "test": "failsafe clean test:execute test:report"
// where test:report runs: serenity-bdd run
}
}

post {
always {
publishHTML(target: [
reportName: 'Serenity BDD Report',
reportDir: 'target/site/serenity',
reportFiles: 'index.html',
keepAll: true,
alwaysLinkToLastBuild: true,
allowMissing: true,
])
}
}

See the Serenity BDD Reporter documentation for full configuration, or consider migrating to the HTML Reporter for a simpler CI setup with built-in trend analysis.

Learn more