I’ve maintained test suites where “run Selenium tests” meant someone manually kicking off a script on their laptop, hoping their browser version matched what the tests expected. That approach falls apart the moment more than one person touches the codebase. Automating Selenium through Jenkins fixed that for good – every commit now gets tested against real browsers, consistently, without anyone needing to remember to run anything by hand. Here’s how I built that pipeline.
Why Run Selenium Tests Through Jenkins
Selenium automates real browser interactions, which makes it powerful but also fragile if run inconsistently. Jenkins solves the consistency problem by giving you:
- A fixed, repeatable environment for every test run (same browser version, same OS, same dependencies).
- Automatic triggering on every push or pull request, catching UI regressions before they reach production.
- Parallel execution across multiple browsers (Chrome, Firefox, Edge) to widen coverage without extending run time.
- Centralized reporting – screenshots, videos, and test reports collected in one place instead of scattered across developer machines.
Architecture: How the Pieces Fit Together
A typical Selenium-on-Jenkins setup has:
- Jenkins Controller/Agent – runs the test suite (via a testing framework like JUnit/TestNG for Java, pytest for Python, or Mocha for JavaScript).
- Selenium Grid (or Selenium Grid running on Kubernetes/Docker) – a hub that distributes test sessions across multiple browser nodes, so tests can run in parallel and don’t need browsers installed directly on the Jenkins agent.
- WebDriver – the protocol Selenium uses to control the browser, whether local or remote via the Grid.
- Test Reporting Plugin – e.g., JUnit or Allure, to visualize pass/fail results and attach screenshots on failure.
Step 1: Prerequisites
- Jenkins installed and running.
- A build tool for your language: Maven/Gradle for Java, pip for Python, npm for JavaScript.
- Docker installed on the agent (recommended, for running Selenium Grid in containers).
Step 2: Install Required Jenkins Plugins
From Manage Jenkins → Plugins, install:
- JUnit Plugin (test result reporting)
- HTML Publisher Plugin (for HTML test reports like Allure or Extent Reports)
- Docker Pipeline Plugin (if running Selenium Grid via Docker)
Or via CLI:
java -jar jenkins-cli.jar -s http://localhost:8080/ install-plugin junit htmlpublisher docker-workflow -restart
Step 3: Stand Up Selenium Grid with Docker Compose
Running Selenium Grid in containers avoids the headache of installing browser binaries directly on your Jenkins agents. Here’s a docker-compose.yml for a hub plus Chrome and Firefox nodes:
version: "3"
services:
selenium-hub:
image: selenium/hub:4.21.0
ports:
- "4442:4442"
- "4443:4443"
- "4444:4444"
chrome:
image: selenium/node-chrome:4.21.0
shm_size: 2gb
depends_on:
- selenium-hub
environment:
- SE_EVENT_BUS_HOST=selenium-hub
- SE_EVENT_BUS_PUBLISH_PORT=4442
- SE_EVENT_BUS_SUBSCRIBE_PORT=4443
firefox:
image: selenium/node-firefox:4.21.0
shm_size: 2gb
depends_on:
- selenium-hub
environment:
- SE_EVENT_BUS_HOST=selenium-hub
- SE_EVENT_BUS_PUBLISH_PORT=4442
- SE_EVENT_BUS_SUBSCRIBE_PORT=4443
Start it up before your tests run: docker compose up -d. Your test code then connects to http://localhost:4444/wd/hub as the Remote WebDriver endpoint.
Step 4: Write the Jenkinsfile
Here’s a complete declarative pipeline for a Java/Maven + TestNG Selenium suite, running against the Grid:
pipeline {
agent any
environment {
SELENIUM_GRID_URL = 'http://localhost:4444/wd/hub'
}
stages {
stage('Checkout') {
steps {
git branch: 'main', url: 'https://github.com/myorg/selenium-tests.git'
}
}
stage('Start Selenium Grid') {
steps {
sh 'docker compose -f docker/selenium-grid.yml up -d'
sh 'sleep 15' // give the grid time to register nodes
}
}
stage('Run Tests') {
steps {
sh 'mvn clean test -Dselenium.grid.url=$SELENIUM_GRID_URL -Dbrowser=chrome'
}
}
stage('Run Tests - Firefox') {
steps {
sh 'mvn test -Dselenium.grid.url=$SELENIUM_GRID_URL -Dbrowser=firefox'
}
}
}
post {
always {
junit 'target/surefire-reports/*.xml'
archiveArtifacts artifacts: 'target/screenshots/**', allowEmptyArchive: true
sh 'docker compose -f docker/selenium-grid.yml down'
}
}
}
Running Tests in Parallel Across Browsers
To actually cut down execution time rather than just running the same suite twice sequentially, use Jenkins’ parallel block:
stage('Cross-Browser Tests') {
parallel {
stage('Chrome') {
steps {
sh 'mvn test -Dbrowser=chrome'
}
}
stage('Firefox') {
steps {
sh 'mvn test -Dbrowser=firefox'
}
}
stage('Edge') {
steps {
sh 'mvn test -Dbrowser=edge'
}
}
}
}
Capturing Screenshots and Videos on Failure
Most flaky UI test failures are only debuggable if you have visual evidence. In your test framework’s @AfterMethod (TestNG) or tearDown hook, capture a screenshot when a test fails and save it to a directory Jenkins archives:
@AfterMethod
public void tearDown(ITestResult result) {
if (result.getStatus() == ITestResult.FAILURE) {
File src = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
FileUtils.copyFile(src, new File("target/screenshots/" + result.getName() + ".png"));
}
driver.quit();
}
Selenium Grid’s video-recording node images (selenium/video) can also record full session videos, which are archived the same way as screenshots.
Publishing Rich HTML Reports
If you use Allure Reports instead of plain JUnit XML, add the Allure Jenkins plugin and this stage:
stage('Publish Allure Report') {
steps {
allure includeProperties: false, jdk: '', results: [[path: 'target/allure-results']]
}
}
Integrating with the Wider Toolchain
- Git/GitHub – trigger the Selenium pipeline on pull requests to catch UI regressions before merge, and post results back as a PR check.
- Docker/Kubernetes – run Selenium Grid as a Kubernetes deployment (via the official Selenium Grid Helm chart) for teams that need to scale beyond a single Docker host.
- Maven – manage Selenium and TestNG/JUnit dependencies declaratively in
pom.xml, versioned alongside your application code. - Slack – notify a
#qa-alertschannel with a summary and link to the Allure report whenever the suite fails on the main branch.
Monitoring and Troubleshooting
- “Session not created” errors – usually a browser/driver version mismatch; pin your Selenium Grid image tags to match your WebDriver client library version.
- Tests timing out waiting for elements – almost always application load speed variability; use explicit waits (
WebDriverWait) instead of hard-codedsleep()calls. - Flaky tests in CI but not locally – often due to headless mode rendering differences or insufficient shared memory (
shm_size) for Chrome, which is why the compose file above setsshm_size: 2gb. - Grid nodes not registering – check that
SE_EVENT_BUS_HOSTmatches the hub’s container name and that ports 4442/4443 aren’t blocked.
Security Best Practices
- Don’t expose the Selenium Grid hub port publicly; keep it internal to the CI network.
- Run browser node containers with
shm_sizelimits and resource caps to avoid one flaky test suite starving the whole agent. - If tests touch staging environments with real data, use dedicated test accounts with limited permissions rather than production credentials.
Best Practices
- Keep test data isolated per run – use unique usernames/emails per test to avoid collisions when tests run in parallel.
- Fail fast: run a quick smoke suite first, then the full regression suite only if smoke passes.
- Tag tests (smoke, regression, critical-path) so you can selectively run subsets depending on the trigger (PR vs nightly).
- Retry flaky tests exactly once automatically, but track retry counts so genuinely flaky tests get fixed rather than permanently masked.
FAQs
Do I need Selenium Grid, or can Jenkins run browsers directly on the agent? You can install browsers directly on the agent for small setups, but Grid gives you parallelism, isolation, and easier scaling, so it’s worth adopting even for mid-sized suites.
Can I run Selenium tests headless in Jenkins? Yes, and it’s recommended for CI – both Chrome and Firefox support a --headless flag, which speeds up execution and avoids needing a display server.
How do I test on real mobile browsers, not just desktop? Use Selenium Grid with Appium nodes, or integrate a cloud device grid service (BrowserStack, Sauce Labs) as a remote WebDriver endpoint instead of your own Grid.
What’s the best way to handle test flakiness? Combine explicit waits, retry logic for known-flaky tests, and screenshot/video capture, then track flaky test rates over time rather than ignoring them.
Can this pipeline scale to hundreds of parallel test cases? Yes, especially if Selenium Grid runs on Kubernetes where you can autoscale browser node pods based on queue depth.
Summary
Setting up Selenium testing in Jenkins comes down to three pieces: a reliable Selenium Grid (ideally containerized), a Jenkinsfile that starts the Grid, runs your suite, and archives results, and good reporting so failures are actionable rather than just red X’s. Once this is in place, UI regressions get caught automatically on every push instead of relying on someone remembering to test manually, and your whole team gets a shared, trustworthy source of truth on browser compatibility.
References
- Selenium official documentation: https://www.selenium.dev/documentation/
- Selenium Grid Docker images: https://github.com/SeleniumHQ/docker-selenium
- Jenkins JUnit Plugin: https://plugins.jenkins.io/junit/
- Allure Jenkins Plugin: https://plugins.jenkins.io/allure-jenkins-plugin/
- Jenkins Pipeline Syntax reference: https://www.jenkins.io/doc/book/pipeline/syntax/
