Time for a production-ready Jenkinsfile. This is what you would use on a real project. It has parameterized builds, headless mode, test reports, email notifications, and proper error handling. Copy this, modify the URLs and email addresses, and you are done.
pipeline {
agent any
tools {
maven 'Maven-3.9'
jdk 'JDK-17'
}
parameters {
choice(name: 'BROWSER', choices: ['chrome', 'firefox'], description: 'Browser')
choice(name: 'SUITE', choices: ['testng-smoke.xml', 'testng-regression.xml', 'testng.xml'], description: 'Suite')
choice(name: 'ENV', choices: ['staging', 'production'], description: 'Environment')
booleanParam(name: 'HEADLESS', defaultValue: true, description: 'Headless mode')
}
environment {
BASE_URL = getBaseUrl(params.ENV)
}
stages {
stage('Checkout') {
steps {
checkout scm
echo "Branch: ${env.GIT_BRANCH}"
echo "Commit: ${env.GIT_COMMIT}"
}
}
stage('Build') {
steps {
sh 'mvn clean compile -DskipTests'
}
}
stage('Run Tests') {
steps {
sh """
mvn test \
-DsuiteXmlFile=${params.SUITE} \
-Dbrowser=${params.BROWSER} \
-Dbase.url=${BASE_URL} \
-Dheadless=${params.HEADLESS}
"""
}
}
stage('Publish Reports') {
steps {
// TestNG report
testNG(reportFilenamePattern: '**/testng-results.xml')
// Allure report
allure([
results: [[path: 'target/allure-results']]
])
// Archive screenshots and logs
archiveArtifacts artifacts: 'target/screenshots/**,target/surefire-reports/**',
allowEmptyArchive: true
}
}
}
post {
success {
echo "All tests passed on ${params.BROWSER} against ${params.ENV}!"
}
failure {
emailext(
subject: "FAILED: ${env.JOB_NAME} #${env.BUILD_NUMBER}",
body: """Tests failed on ${params.BROWSER} against ${params.ENV}.
\nReport: ${env.BUILD_URL}allure
\nConsole: ${env.BUILD_URL}console""",
to: 'qa-team@company.com'
)
}
always {
cleanWs()
}
}
}
def getBaseUrl(env) {
switch (env) {
case 'production': return 'https://www.example.com'
default: return 'https://staging.example.com'
}
}CI servers do not have a monitor. There is no screen to display Chrome. You must run browsers in headless mode — the browser renders pages in memory, no visible window. Your BaseTest should read the headless flag from system properties.
// BaseTest.java — headless support
ChromeOptions options = new ChromeOptions();
boolean headless = Boolean.parseBoolean(
System.getProperty("headless", "false")
);
if (headless) {
options.addArguments("--headless=new"); // New headless mode
options.addArguments("--no-sandbox"); // Required in Docker/CI
options.addArguments("--disable-dev-shm-usage"); // Prevent shared memory issues
options.addArguments("--window-size=1920,1080"); // Consistent viewport
options.addArguments("--disable-gpu"); // Stability in CI
}
driver = new ChromeDriver(options);Never skip --no-sandbox in CI environments. Without it, Chrome crashes in Docker containers. And always set --window-size — headless mode defaults to 800x600, which breaks responsive elements and makes your tests fail for no reason.
Test your pipeline locally first. Run "mvn clean test -DsuiteXmlFile=testng.xml -Dheadless=true" from your terminal. If it works locally in headless mode, it will work in Jenkins.
Q: Walk me through your Jenkinsfile for running Selenium tests.
A: My Jenkinsfile has 4 stages. Checkout pulls code from Git. Build compiles with "mvn clean compile -DskipTests" to catch compilation errors early. Run Tests executes the TestNG suite with parameterized browser, environment, and headless mode. Publish Reports generates Allure and TestNG reports and archives screenshots. In the post section, failure triggers an email notification with report links, and always runs cleanWs() to free disk space. The pipeline is parameterized so the team can choose browser, environment, and suite from a dropdown. For nightly regression, cron triggers it automatically with defaults.
Key Point: A production Jenkinsfile has parameterized builds, headless mode, reports (TestNG + Allure), email on failure, and workspace cleanup.