How to Use Jenkins with Cypress for End-to-End Testing

How to Use Jenkins with Cypress for End-to-End Testing

Unit tests give you confidence that individual functions work, but they’ve never once caught the kind of bug that shows up when a real user clicks through an actual checkout flow and hits a broken redirect. That’s the gap Cypress fills, and wiring it into Jenkins was one of the more satisfying integrations I’ve set up — watching a full browser-based test suite run automatically on every pull request, complete with screenshots and videos of any failures, genuinely changed how confident my team felt about shipping.

This article walks through setting up Jenkins to run Cypress end-to-end tests, from a basic setup to advanced patterns like parallel test splitting, Docker-based execution, and integration with reporting tools.

Why Cypress for End-to-End Testing

Cypress is a JavaScript-based end-to-end testing framework that runs directly in the browser, giving it much better visibility into your application than older tools like Selenium (which communicate with the browser over a remote protocol). Cypress can:

  • Wait automatically for elements and network requests, reducing flaky tests.
  • Take automatic screenshots and record videos of test runs.
  • Provide time-travel debugging, letting you see the exact DOM state at each test step.
  • Run directly against real browsers (Chrome, Firefox, Edge, Electron).

Running Cypress in Jenkins means every code change gets validated against real user workflows automatically, rather than relying solely on manual QA passes before releases.

Jenkins Architecture Context

Cypress tests need a running instance of your application to test against — meaning this pipeline stage typically comes after deployment to a test environment (or after starting your app locally within the same pipeline, for simpler setups). Jenkins agents running Cypress need Node.js and either a full browser install or Cypress’s official Docker images, which bundle all required browser dependencies.

Prerequisites

  • Node.js installed on the Jenkins agent (or use Cypress’s official Docker image).
  • Your application’s test/staging environment reachable from the Jenkins agent.
  • cypress added as a dev dependency in your project (npm install cypress --save-dev).

Step 1: Basic Project Setup

Assuming Cypress is already part of your package.json:

{
  "devDependencies": {
    "cypress": "^13.6.0"
  },
  "scripts": {
    "cypress:run": "cypress run"
  }
}

Step 2: Basic Jenkinsfile Running Cypress Directly

pipeline {
    agent any

    tools {
        nodejs 'NodeJS-20'
    }

    stages {
        stage('Checkout') {
            steps {
                checkout scm
            }
        }

        stage('Install Dependencies') {
            steps {
                sh 'npm ci'
            }
        }

        stage('Start Application') {
            steps {
                sh 'npm run start &'
                sh 'npx wait-on http://localhost:3000'
            }
        }

        stage('Run Cypress Tests') {
            steps {
                sh 'npx cypress run --reporter junit --reporter-options "mochaFile=results/cypress-[hash].xml"'
            }
        }
    }

    post {
        always {
            junit 'results/*.xml'
            archiveArtifacts artifacts: 'cypress/screenshots/**/*.png', allowEmptyArchive: true
            archiveArtifacts artifacts: 'cypress/videos/**/*.mp4', allowEmptyArchive: true
        }
        failure {
            mail to: 'qa-team@example.com',
                 subject: "Cypress Tests Failed: ${env.JOB_NAME} #${env.BUILD_NUMBER}",
                 body: "Check archived screenshots and videos at ${env.BUILD_URL}"
        }
    }
}

The wait-on package here is important — it prevents Cypress from starting before your application is actually ready to accept requests, which is one of the most common causes of flaky CI test failures.

Step 3: Running Cypress via Docker (Recommended for Consistency)

Rather than installing browsers directly on Jenkins agents (which can lead to version drift and “works on my machine” issues), I strongly recommend using Cypress’s official Docker images:

pipeline {
    agent {
        docker {
            image 'cypress/included:13.6.0'
            args '-u root'
        }
    }

    stages {
        stage('Install Dependencies') {
            steps {
                sh 'npm ci'
            }
        }

        stage('Run Cypress Tests') {
            steps {
                sh 'cypress run --reporter junit --reporter-options "mochaFile=results/cypress-[hash].xml"'
            }
        }
    }

    post {
        always {
            junit 'results/*.xml'
            archiveArtifacts artifacts: 'cypress/screenshots/**/*.png', allowEmptyArchive: true
            archiveArtifacts artifacts: 'cypress/videos/**/*.mp4', allowEmptyArchive: true
        }
    }
}

The cypress/included image bundles Cypress itself plus all browser dependencies, meaning you don’t need to manage Chrome/Firefox installs on your Jenkins agents at all.

Step 4: Parallel Test Execution with Cypress

For large test suites, splitting tests across multiple parallel Jenkins stages dramatically cuts total run time. Combine this with Jenkins Pipeline’s parallel directive:

pipeline {
    agent none
    stages {
        stage('E2E Tests') {
            parallel {
                stage('Auth Flow Tests') {
                    agent { docker { image 'cypress/included:13.6.0' } }
                    steps {
                        sh 'npm ci'
                        sh 'cypress run --spec "cypress/e2e/auth/**/*.cy.js"'
                    }
                }
                stage('Checkout Flow Tests') {
                    agent { docker { image 'cypress/included:13.6.0' } }
                    steps {
                        sh 'npm ci'
                        sh 'cypress run --spec "cypress/e2e/checkout/**/*.cy.js"'
                    }
                }
                stage('Dashboard Tests') {
                    agent { docker { image 'cypress/included:13.6.0' } }
                    steps {
                        sh 'npm ci'
                        sh 'cypress run --spec "cypress/e2e/dashboard/**/*.cy.js"'
                    }
                }
            }
        }
    }
}

Alternatively, if you have a Cypress Cloud account, cypress run --record --parallel automatically load-balances test files across whatever number of Jenkins agents/containers you spin up, without you having to manually partition specs by folder.

Step 5: Cypress with Docker Compose for Full-Stack Testing

For applications with multiple dependent services (frontend, backend API, database), Docker Compose is often cleaner than trying to manage everything in raw shell steps:

# docker-compose.ci.yml
version: '3.8'
services:
  app:
    build: .
    ports:
      - "3000:3000"
    depends_on:
      - db
  db:
    image: postgres:15
    environment:
      POSTGRES_PASSWORD: testpass
  cypress:
    image: cypress/included:13.6.0
    depends_on:
      - app
    environment:
      CYPRESS_baseUrl: http://app:3000
    volumes:
      - ./cypress:/e2e/cypress
      - ./cypress.config.js:/e2e/cypress.config.js
    working_dir: /e2e
stage('Run Full-Stack E2E Tests') {
    steps {
        sh 'docker-compose -f docker-compose.ci.yml up --abort-on-container-exit --exit-code-from cypress'
    }
}

post {
    always {
        sh 'docker-compose -f docker-compose.ci.yml down -v'
    }
}

Integrating with Git and GitHub

Post Cypress results back to pull requests using GitHub status checks, and consider posting a summary comment with pass/fail counts and a link to archived screenshots/videos for failed tests:

post {
    failure {
        githubNotify status: 'FAILURE', context: 'cypress-e2e', description: 'E2E tests failed'
    }
    success {
        githubNotify status: 'SUCCESS', context: 'cypress-e2e', description: 'All E2E tests passed'
    }
}

Integrating with Kubernetes

For teams deploying preview environments per pull request in Kubernetes, trigger Cypress only after confirming the preview environment is healthy:

stage('Wait for Preview Environment') {
    steps {
        sh 'kubectl rollout status deployment/preview-${env.CHANGE_ID} --timeout=120s'
    }
}

stage('Run Cypress Against Preview') {
    steps {
        sh "CYPRESS_baseUrl=https://pr-${env.CHANGE_ID}.preview.myapp.com cypress run"
    }
}

This pattern — spin up an ephemeral preview environment per PR, then run Cypress against it — gives reviewers real confidence that a change works end-to-end before merging, not just that unit tests pass.

Monitoring and Reporting

Beyond JUnit XML for Jenkins’ built-in test reporting, consider integrating:

  • Cypress Cloud for a persistent dashboard of test runs, flaky test detection, and historical trends across builds.
  • Allure Report as an alternative rich reporting format if your team already uses Allure for other test types.
  • Slack notifications summarizing pass/fail counts per run, especially useful for nightly full-regression suites.

Troubleshooting Common Issues

  • Flaky tests due to timing — avoid hardcoded cy.wait(5000) calls; use Cypress’s built-in retry-ability and cy.intercept() to wait on actual network responses instead.
  • Tests pass locally but fail in CI — often caused by viewport size differences, missing environment variables, or the app not being fully ready when tests start; always use wait-on or a health-check step before running tests. & Videos/screenshots missing from archived artifacts — double check your cypress.config.js has video: true and that the archive step’s path glob matches your actual output directory.
  • Docker permission errors — Cypress’s Docker images sometimes need -u root or proper /dev/shm size configuration (--shm-size=1gb) to avoid Chrome crashing mid-test.

Best Practices

  • Use Cypress’s official Docker images to avoid browser version drift across agents.
  • Always wait for your application to be genuinely ready (via wait-on or health checks) before starting tests.
  • Split large suites using parallel stages or Cypress Cloud’s load balancing to keep pipeline duration reasonable.
  • Archive screenshots and videos on failure — they save enormous debugging time compared to reading raw logs alone.
  • Run smoke-level Cypress suites on every PR, and reserve full regression suites for nightly or pre-release runs if your suite is large.

FAQs

Do I need a Cypress Cloud subscription to use Cypress in Jenkins? No, cypress run works completely standalone and free; Cypress Cloud is an optional paid add-on for recording, dashboards, and automatic parallelization load-balancing.

Can Cypress test against a locally started app within the same Jenkins job, or does it need a separate deployed environment? Both work — for quick smoke tests you can start your app locally in the same pipeline job; for closer-to-production validation, testing against a real deployed staging or preview environment is generally more reliable.

How do I handle authentication in Cypress tests without repeating login steps in every test? Use Cypress’s cy.session() API to cache authenticated sessions across tests, dramatically speeding up suites that require login.

Is Cypress better than Selenium for CI/CD pipelines? Cypress generally offers faster, less flaky tests for modern JavaScript-heavy applications due to its architecture running inside the browser, though Selenium still has broader cross-browser and multi-language support in some enterprise contexts.

Summary

Integrating Cypress into Jenkins gives your pipeline real, browser-level confidence that critical user flows actually work — not just that isolated functions return the right values. Whether you run it directly on agents, inside Docker containers for consistency, or split across parallel stages for speed, the core pattern stays the same: get your application into a testable state, run Cypress, and archive results (JUnit XML, screenshots, videos) so failures are easy to diagnose without needing to reproduce them locally.

References

  • Cypress Official Documentation: https://docs.cypress.io/
  • Cypress Docker Images: https://github.com/cypress-io/cypress-docker-images
  • Cypress Cloud (Dashboard) Documentation: https://docs.cypress.io/guides/cloud/introduction
  • Jenkins JUnit Plugin: https://plugins.jenkins.io/junit/
Total
1
Shares

Leave a Reply

Previous Post
How to Set Up Jenkins for Continuous Deployment to AWS Lambda

How to Set Up Jenkins for Continuous Deployment to AWS Lambda

Next Post
How to Set Up Jenkins for Container Vulnerability Scanning with Trivy

How to Set Up Jenkins for Container Vulnerability Scanning with Trivy

Related Posts