Lesson 10 of 14 ~25 min
Course progress
0%

CI/CD Integration & Deployment

Integrate Selenium tests into CI/CD pipelines

Continuous Integration with Selenium

Integrate your Selenium tests into CI/CD pipelines for automated testing on every code change.

Jenkins Integration

Jenkinsfile:

pipeline {
    agent any
    
    tools {
        maven 'Maven 3.9.0'
        jdk 'JDK 17'
    }
    
    stages {
        stage('Checkout') {
            steps {
                git branch: 'main',
                    url: 'https://github.com/your-repo/selenium-framework.git'
            }
        }
        
        stage('Build') {
            steps {
                sh 'mvn clean compile'
            }
        }
        
        stage('Run Tests') {
            steps {
                sh 'mvn test -Dbrowser=chrome -Dheadless=true'
            }
        }
        
        stage('Generate Reports') {
            steps {
                publishHTML([
                    allowMissing: false,
                    alwaysLinkToLastBuild: true,
                    keepAll: true,
                    reportDir: 'reports/extent-reports',
                    reportFiles: 'test-report.html',
                    reportName: 'Test Report'
                ])
            }
        }
    }
    
    post {
        always {
            junit 'target/surefire-reports/*.xml'
            archiveArtifacts artifacts: 'screenshots/**/*.png', allowEmptyArchive: true
        }
        
        failure {
            emailext(
                subject: "Test Failure: ${currentBuild.fullDisplayName}",
                body: "Tests failed. Check console output.",
                to: "team@example.com"
            )
        }
    }
}

GitHub Actions

.github/workflows/selenium-tests.yml:

name: Selenium E2E Tests

on:
  push:
    branches: [ main, develop ]
  pull_request:
    branches: [ main ]
  schedule:
    - cron: '0 2 * * *'  # Run daily at 2 AM

jobs:
  test:
    runs-on: ubuntu-latest
    
    strategy:
      matrix:
        browser: [chrome, firefox]
    
    steps:
      - name: Checkout code
        uses: actions/checkout@v3
      
      - name: Set up JDK 17
        uses: actions/setup-java@v3
        with:
          java-version: '17'
          distribution: 'temurin'
          cache: maven
      
      - name: Install Chrome
        if: matrix.browser == 'chrome'
        uses: browser-actions/setup-chrome@latest
      
      - name: Install Firefox
        if: matrix.browser == 'firefox'
        uses: browser-actions/setup-firefox@latest
      
      - name: Run tests
        run: mvn test -Dbrowser=${{ matrix.browser }} -Dheadless=true
      
      - name: Upload screenshots
        if: failure()
        uses: actions/upload-artifact@v3
        with:
          name: screenshots-${{ matrix.browser }}
          path: screenshots/
      
      - name: Upload test reports
        if: always()
        uses: actions/upload-artifact@v3
        with:
          name: test-reports-${{ matrix.browser }}
          path: reports/
      
      - name: Publish test results
        if: always()
        uses: dorny/test-reporter@v1
        with:
          name: Test Results (${{ matrix.browser }})
          path: target/surefire-reports/*.xml
          reporter: java-junit

GitLab CI

.gitlab-ci.yml:

image: maven:3.9.0-eclipse-temurin-17

stages:
  - build
  - test
  - report

variables:
  MAVEN_OPTS: "-Dmaven.repo.local=.m2/repository"

cache:
  paths:
    - .m2/repository

build:
  stage: build
  script:
    - mvn clean compile

test:chrome:
  stage: test
  script:
    - apt-get update && apt-get install -y chromium chromium-driver
    - mvn test -Dbrowser=chrome -Dheadless=true
  artifacts:
    when: always
    paths:
      - target/surefire-reports/
      - screenshots/
      - reports/
    reports:
      junit: target/surefire-reports/*.xml

test:firefox:
  stage: test
  script:
    - apt-get update && apt-get install -y firefox-esr
    - mvn test -Dbrowser=firefox -Dheadless=true
  artifacts:
    when: always
    paths:
      - target/surefire-reports/
      - screenshots/
      - reports/

pages:
  stage: report
  script:
    - mkdir -p public
    - cp -r reports/extent-reports/* public/
  artifacts:
    paths:
      - public
  only:
    - main

Docker Integration

Dockerfile:

FROM maven:3.9.0-eclipse-temurin-17

# Install browsers and drivers
RUN apt-get update && apt-get install -y \
    chromium \
    chromium-driver \
    firefox-esr \
    wget \
    && rm -rf /var/lib/apt/lists/*

# Install geckodriver
RUN wget https://github.com/mozilla/geckodriver/releases/download/v0.33.0/geckodriver-v0.33.0-linux64.tar.gz \
    && tar -xvzf geckodriver-v0.33.0-linux64.tar.gz \
    && mv geckodriver /usr/local/bin/ \
    && chmod +x /usr/local/bin/geckodriver

WORKDIR /app

COPY pom.xml .
RUN mvn dependency:go-offline

COPY . .

CMD ["mvn", "test", "-Dheadless=true"]

docker-compose.yml:

version: '3.8'

services:
  selenium-hub:
    image: selenium/hub:latest
    ports:
      - "4444:4444"
    environment:
      - GRID_MAX_SESSION=5
      - GRID_BROWSER_TIMEOUT=300
      - GRID_TIMEOUT=300
  
  chrome:
    image: selenium/node-chrome:latest
    depends_on:
      - selenium-hub
    environment:
      - SE_EVENT_BUS_HOST=selenium-hub
      - SE_EVENT_BUS_PUBLISH_PORT=4442
      - SE_EVENT_BUS_SUBSCRIBE_PORT=4443
      - SE_NODE_MAX_SESSIONS=3
    shm_size: 2gb
  
  firefox:
    image: selenium/node-firefox:latest
    depends_on:
      - selenium-hub
    environment:
      - SE_EVENT_BUS_HOST=selenium-hub
      - SE_EVENT_BUS_PUBLISH_PORT=4442
      - SE_EVENT_BUS_SUBSCRIBE_PORT=4443
      - SE_NODE_MAX_SESSIONS=3
    shm_size: 2gb
  
  tests:
    build: .
    depends_on:
      - selenium-hub
      - chrome
      - firefox
    environment:
      - GRID_URL=http://selenium-hub:4444
      - GRID_ENABLED=true
    volumes:
      - ./reports:/app/reports
      - ./screenshots:/app/screenshots

Maven Configuration for CI

pom.xml profiles:

<profiles>
    <!-- Local Development -->
    <profile>
        <id>local</id>
        <activation>
            <activeByDefault>true</activeByDefault>
        </activation>
        <properties>
            <headless>false</headless>
            <browser>chrome</browser>
        </properties>
    </profile>
    
    <!-- CI Environment -->
    <profile>
        <id>ci</id>
        <properties>
            <headless>true</headless>
            <parallel>classes</parallel>
            <thread.count>3</thread.count>
        </properties>
    </profile>
    
    <!-- Selenium Grid -->
    <profile>
        <id>grid</id>
        <properties>
            <grid.enabled>true</grid.enabled>
            <grid.url>http://localhost:4444</grid.url>
        </properties>
    </profile>
</profiles>

Run with profile:

# Local
mvn test

# CI
mvn test -Pci

# Grid
mvn test -Pgrid

Test Reporting

Allure Reports Integration:

Add to pom.xml:

<dependency>
    <groupId>io.qameta.allure</groupId>
    <artifactId>allure-testng</artifactId>
    <version>2.24.0</version>
</dependency>

<plugin>
    <groupId>io.qameta.allure</groupId>
    <artifactId>allure-maven</artifactId>
    <version>2.12.0</version>
</plugin>

Generate and serve report:

mvn allure:serve

Notification Integration

Slack Notifications (Jenkins):

post {
    success {
        slackSend(
            color: 'good',
            message: "Tests Passed: ${env.JOB_NAME} #${env.BUILD_NUMBER}",
            channel: '#qa-automation'
        )
    }
    failure {
        slackSend(
            color: 'danger',
            message: "Tests Failed: ${env.JOB_NAME} #${env.BUILD_NUMBER}\n${env.BUILD_URL}",
            channel: '#qa-automation'
        )
    }
}

Performance Monitoring

Track test execution time:

@Listeners(PerformanceListener.class)
public class PerformanceTest {
    
    @Test
    public void measuredTest() {
        long startTime = System.currentTimeMillis();
        
        // Test execution
        
        long endTime = System.currentTimeMillis();
        long duration = endTime - startTime;
        
        System.out.println("Test duration: " + duration + "ms");
        
        // Fail if test takes too long
        Assert.assertTrue(duration < 10000, "Test took too long: " + duration + "ms");
    }
}

Best Practices for CI/CD

  1. ✅ Run tests in headless mode - Faster execution in CI
  2. ✅ Use Docker containers - Consistent environments
  3. ✅ Implement parallel execution - Reduce build time
  4. ✅ Archive test artifacts - Screenshots, reports, logs
  5. ✅ Set up notifications - Alert team of failures
  6. ✅ Run smoke tests on every commit - Quick feedback
  7. ✅ Schedule full regression nightly - Comprehensive coverage
  8. ✅ Use Selenium Grid - Distribute tests across nodes
  9. ✅ Monitor test performance - Track execution time
  10. ✅ Version your test code - Track changes and rollback

Key Takeaways

✅ CI/CD integration enables automated testing on every change
✅ Docker ensures consistent test environments
✅ Parallel execution reduces feedback time
✅ Proper reporting and notifications keep team informed

What is the benefit of running tests in headless mode?

Better screenshots
Faster execution and no GUI required
More accurate testing
Easier debugging

What is Selenium Grid used for?

Generating test reports
Writing test scripts
Distributing tests across multiple machines
Managing test data

Congratulations! 🎉

You’ve completed the Java + Selenium E2E Testing Mastery course! You now have the skills to:

  • Build robust test automation frameworks
  • Implement Page Object Model pattern
  • Use TestNG for test organization
  • Handle complex scenarios
  • Integrate tests into CI/CD pipelines

Keep practicing and happy testing! 🚀