GitHub Actions Selenium CI: Complete Setup Guide (2026)
Run Selenium tests in CI with GitHub Actions — step-by-step setup, parallel matrix execution, artifact upload, and best practices for 2026. Includes complete YAML examples.

In this article
- Prerequisites
- The Complete Workflow
- Step-by-Step Explanation
- Headless Mode in CI
- Parallel Execution
- Caching for Speed
- Conditional Execution
- Environment Variables for Secrets
- Slack Notifications
- Branch Protection Rules
- Advanced GitHub Actions Patterns for Selenium
- Debugging CI Failures
- Frequently asked questions
Last updated: June 27, 2026 · 8 min read
Run your Selenium Java tests in CI with GitHub Actions — step by step. Includes the complete selenium-ci.yml you can copy-paste. For framework foundations, pair this with our Selenium WebDriver Guide and Java for Selenium tutorial.
Prerequisites
- Java Selenium project in a GitHub repository
- Maven (or Gradle)
- Tests run via
mvn testor./gradlew test
The Complete Workflow
Create .github/workflows/selenium-ci.yml:
name: Selenium CI
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
selenium-tests:
runs-on: ubuntu-latest
strategy:
matrix:
browser: [chrome, firefox, edge]
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: '17'
cache: maven
- name: Build with Maven
run: mvn clean compile
- name: Run Selenium tests
run: mvn test -Dbrowser=${{ matrix.browser }}
- name: Upload screenshots on failure
if: failure()
uses: actions/upload-artifact@v4
with:
name: selenium-failures-${{ matrix.browser }}
path: target/screenshots/
retention-days: 7
- name: Upload test reports
if: always()
uses: actions/upload-artifact@v4
with:
name: test-reports-${{ matrix.browser }}
path: target/surefire-reports/
retention-days: 30This workflow runs on every push to main/develop and every PR, tests against 3 browsers in parallel, caches Maven dependencies, and uploads screenshots and reports on failure.
Step-by-Step Explanation
Step 1 — Triggers
on:
push:
branches: [main, develop]
pull_request:
branches: [main]The workflow runs on every push to main and develop, and on every PR targeting main.
Step 2 — Browser matrix
strategy:
matrix:
browser: [chrome, firefox, edge]Runs the workflow 3 times — once per browser. Each run gets its own job in the GitHub Actions UI.
Step 3 — Java setup
- uses: actions/setup-java@v4
with:
distribution: temurin
java-version: '17'
cache: mavenUses the Temurin distribution of OpenJDK 17. The cache: maven directive caches ~/.m2/repository to speed up subsequent runs.
Step 4 — Browser installation
Selenium 4's Selenium Manager auto-installs browser drivers. But the actual browsers must be installed on the runner:
- name: Install Chrome
run: |
wget -q -O - https://dl.google.com/linux/linux_signing_key.pub | apt-key add -
echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" > /etc/apt/sources.list.d/google-chrome.list
apt-get update
apt-get install -y google-chrome-stableFor Firefox and Edge, similar steps. Or use the browser-actions/setup-chrome action.
Step 5 — Run tests
- run: mvn test -Dbrowser=${{ matrix.browser }}Pass the browser as a Maven property. Your test code reads it:
String browser = System.getProperty("browser", "chrome");
WebDriver driver;
switch (browser) {
case "chrome": driver = new ChromeDriver(); break;
case "firefox": driver = new FirefoxDriver(); break;
case "edge": driver = new EdgeDriver(); break;
}Step 6 — Artifact upload
- if: failure()
uses: actions/upload-artifact@v4
with:
name: selenium-failures-${{ matrix.browser }}
path: target/screenshots/When tests fail, upload screenshots so you can download and view them in the GitHub Actions UI.
Headless Mode in CI
Always run headless in CI for speed and reliability:
ChromeOptions options = new ChromeOptions();
options.addArguments("--headless=new");
options.addArguments("--disable-gpu");
options.addArguments("--no-sandbox");
options.addArguments("--window-size=1920,1080");
WebDriver driver = new ChromeDriver(options);Use xvfb if you need a virtual display for non-headless mode:
- name: Install Xvfb
run: sudo apt-get install -y xvfb
- name: Run tests with Xvfb
run: xvfb-run --auto-servernum mvn testParallel Execution
The strategy.matrix already runs 3 browsers in parallel. For more parallelism, use TestNG parallel mode:
<suite name="Suite" parallel="methods" thread-count="4">For Selenium Grid with parallel nodes, see our Selenium Grid setup guide.
Caching for Speed
- uses: actions/setup-java@v4
with:
cache: mavenThis caches the entire ~/.m2/repository directory between runs. Saves 1–3 minutes per run.
Conditional Execution
Run tests only when relevant files change:
on:
push:
paths:
- 'src/**'
- 'pom.xml'
- '.github/workflows/selenium-ci.yml'This skips the workflow when only README.md or docs change.
Environment Variables for Secrets
- name: Run tests
env:
ADMIN_PASSWORD: ${{ secrets.ADMIN_PASSWORD }}
API_KEY: ${{ secrets.API_KEY }}
run: mvn testNever commit secrets to your repo. Use GitHub Secrets for sensitive values.
Slack Notifications
- name: Notify Slack on failure
if: failure()
uses: slackapi/slack-github-action@v1
with:
payload: |
{
"text": "Selenium CI failed on ${{ github.ref }}: ${{ github.run_id }}"
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }}Branch Protection Rules
In GitHub repo settings, require this workflow to pass before merging:
Settings → Branches → Add rule → Require status checks to pass → Select "Selenium CI"
This blocks PRs that have failing tests. For more CI/CD patterns, see our Selenium WebDriver Guide and our Java for Selenium guide.
Advanced GitHub Actions Patterns for Selenium
Reusable Workflows
Create a reusable workflow at .github/workflows/selenium-reusable.yml:
name: Selenium Reusable
on:
workflow_call:
inputs:
browser:
required: true
type: string
secrets:
ADMIN_PASSWORD:
required: true
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with: { distribution: temurin, java-version: '17', cache: maven }
- run: mvn test -Dbrowser=${{ inputs.browser }}
env:
ADMIN_PASSWORD: ${{ secrets.ADMIN_PASSWORD }}
- uses: actions/upload-artifact@v4
if: failure()
with:
name: selenium-failures-${{ inputs.browser }}
path: target/screenshots/Call it from your app repo:
jobs:
selenium:
uses: your-org/selenium-workflows/.github/workflows/selenium-reusable.yml@v1
with:
browser: chrome
secrets:
ADMIN_PASSWORD: ${{ secrets.ADMIN_PASSWORD }}Caching Test Results
- name: Cache Maven dependencies
uses: actions/cache@v4
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
restore-keys: |
${{ runner.os }}-maven-
${{ runner.os }}-Scheduled Nightly Runs
on:
schedule:
- cron: '0 2 * * *' # 2 AM UTC daily
workflow_dispatch: # Allow manual triggerThese advanced patterns are common in 2026 enterprise Selenium CI/CD pipelines.
Debugging CI Failures
When your Selenium CI fails, follow this debugging process:
Step 1 — View the workflow logs
Click the failed job in GitHub Actions. Expand each step. Look for test failure messages, stack traces, browser driver errors, and network timeouts.
Step 2 — Download artifacts
If you uploaded screenshots or videos, download them. Look at what the browser saw when the test failed.
Step 3 — Reproduce locally
mvn test -Dbrowser=chrome -Dtest=FailedTestRun with the same browser and the same failing test class locally.
Step 4 — Common root causes
| Symptom | Likely cause | Fix |
|---|---|---|
| Tests pass locally, fail in CI | Timing/race condition | Add explicit waits |
| Specific browser fails | Browser version mismatch | Pin browser versions in CI |
| Random failures | Network instability | Use retries or mocks |
| Element not found | Locator changed | Update locators + run on dev first |
Step 5 — Add the fix and re-run
Make the fix, push, and let CI validate. If it still fails, repeat from Step 1. For more debugging strategies, see our Playwright Complete Guide which has better debugging via the Trace Viewer, or compare tools in Playwright vs Selenium.
Frequently asked questions
How long does a Selenium CI run take?
With the matrix above (3 browsers, ~100 tests): 5–10 minutes. Cache dependencies to speed it up.
Should I run tests headless in CI?
Yes — always. Headless is faster and uses less memory. The --headless=new flag in Chrome 132+ is reliable.
How do I view failure screenshots in CI?
GitHub Actions uploads artifacts that you can download from the workflow run page. Use the actions/upload-artifact action.
Can I run tests on a schedule (nightly)?
Yes — use the schedule trigger with a cron expression like '0 2 * * *' for 2 AM UTC daily.
How do I parallelize within a single browser run?
Use TestNG parallel mode (parallel='methods' thread-count='4'), or split tests across multiple jobs in the matrix.
Practice these questions
Work through 300+ Selenium questions with Java code snippets, Selenium 4, Grid, framework patterns and CI/CD scenarios.
Was this article helpful?
Keep building your QA edge
Pillar guidesContinue reading

Why Every QA Engineer Must Master CI/CD Pipelines in 2026 (Or Risk Obsolescence)
12 min read
Is Cypress Dead? Analyzing 2026 Playwright Market Share
12 min read
Why Tests Pass Locally But Fail in CI/CD (And the 6 Fixes That Actually Work in 2026)
13 min readJoin the QA Community
Connect with fellow testers, share job leads, and get career advice.
Stop Reinventing the Wheel. Upgrade Your QA Arsenal.
Take your testing skills from beginner to Lead Engineer. Supercharge your daily workflow with our premium digital resources.
- ⚡ Ready-to-use testing strategy templates
- 🔥 Advanced API & UI automation guides
- ⏱️ Save 10+ hours a week on test planning