Cypress Tests in Azure DevOps Pipeline: Step-by-Step Guide
How to run Cypress tests in Azure DevOps CI/CD pipelines. Covers Cypress installation on CI agents, YAML configuration, video and screenshot artifacts, parallel test execution with Cypress Cloud, and result publishing.
Cypress has first-class CI support and runs well on Azure DevOps with minimal configuration. This guide covers everything from basic setup to production-grade parallel execution.
Basic Cypress pipeline
trigger:
branches:
include: [main]
pool:
vmImage: ubuntu-latest
steps:
- task: NodeTool@0
inputs:
versionSpec: '20.x'
- script: npm ci
displayName: Install packages
- script: npx cypress verify
displayName: Verify Cypress install
- script: |
npx cypress run \
--browser chrome \
--reporter junit \
--reporter-options "mochaFile=cypress/results/results-[hash].xml,toConsole=true"
displayName: Run Cypress tests
env:
CYPRESS_BASE_URL: $(STAGING_URL)
CYPRESS_TEST_EMAIL: $(TEST_EMAIL)
CYPRESS_TEST_PASSWORD: $(TEST_PASSWORD)
- task: PublishTestResults@2
displayName: Publish results
inputs:
testResultsFormat: JUnit
testResultsFiles: 'cypress/results/*.xml'
mergeTestResults: true
testRunTitle: Cypress — $(Build.BuildNumber)
condition: always()
- task: PublishPipelineArtifact@1
displayName: Upload screenshots and videos
inputs:
targetPath: cypress/screenshots
artifact: cypress-screenshots
condition: failed()
- task: PublishPipelineArtifact@1
displayName: Upload videos
inputs:
targetPath: cypress/videos
artifact: cypress-videos
condition: always()Cypress configuration for CI
// cypress.config.js
const { defineConfig } = require('cypress')
module.exports = defineConfig({
e2e: {
baseUrl: process.env.CYPRESS_BASE_URL || 'http://localhost:3000',
video: true,
videoCompression: 32,
screenshotOnRunFailure: true,
defaultCommandTimeout: process.env.CI ? 10000 : 4000,
requestTimeout: process.env.CI ? 15000 : 5000,
pageLoadTimeout: process.env.CI ? 30000 : 10000,
retries: {
runMode: 2, // Retry twice in CI
openMode: 0,
},
},
})Using environment variables in tests
Cypress environment variables set with CYPRESS_ prefix are available as Cypress.env():
// In pipeline YAML
- script: npx cypress run
env:
CYPRESS_BASE_URL: $(STAGING_URL)
CYPRESS_API_KEY: $(API_KEY)
// In test code
cy.request({
url: `${Cypress.env('BASE_URL')}/api/health`,
headers: { 'X-API-Key': Cypress.env('API_KEY') }
})Parallel execution with Cypress Cloud
For large test suites, use Cypress Cloud (formerly Cypress Dashboard) to distribute tests across agents:
strategy:
matrix:
Agent1: { MACHINE_NUM: 1 }
Agent2: { MACHINE_NUM: 2 }
Agent3: { MACHINE_NUM: 3 }
maxParallel: 3
steps:
- script: npm ci
- script: |
npx cypress run \
--record \
--parallel \
--ci-build-id $(Build.BuildId) \
--group "Azure CI" \
--key $(CYPRESS_RECORD_KEY)
env:
CYPRESS_RECORD_KEY: $(CYPRESS_RECORD_KEY)
CYPRESS_BASE_URL: $(STAGING_URL)Cypress Cloud distributes tests across the 3 agents automatically based on historical execution times.
Adding the junit reporter
npm install --save-dev cypress-multi-reporters mocha-junit-reporter// reporter-config.json
{
"reporterEnabled": "spec, mocha-junit-reporter",
"mochaJunitReporterReporterOptions": {
"mochaFile": "cypress/results/results-[hash].xml"
}
}- script: |
npx cypress run \
--reporter cypress-multi-reporters \
--reporter-options configFile=reporter-config.jsonCommon errors and fixes
Error: Cypress failed to start: The Cypress App could not be started
Fix: Add DISPLAY=:99 or use npx cypress run (not cypress open). On Linux CI agents without a display server, Cypress must run in headless mode — cypress run is headless by default.
Error: Videos are recorded but empty (0 bytes)
Fix: Add ffmpeg to the agent or use Microsoft-hosted Ubuntu agents which have it pre-installed. Video recording requires ffmpeg.
Error: Timeout of 4000ms exceeded for page loads
Fix: Increase pageLoadTimeout in cypress.config.js for CI runs. Staging environments on CI agents are often accessed over slower network connections.
Error: Tests fail with cy.intercept not intercepting requests
Fix: cy.intercept() must be set up before the request is made. Move intercepts to beforeEach hooks that run before cy.visit().
Error: Cypress install hangs in pipeline
Fix: Set CYPRESS_INSTALL_BINARY=0 if you don't need the GUI binary (CI-only runs). Or cache the Cypress binary: use Cache@2 task with key based on package-lock.json.
Stay ahead in AI-driven QA
Get practical tutorials on test automation, AI testing, and quality engineering — straight to your inbox. No spam, unsubscribe any time.
Discussion
Sign in with GitHub to comment · powered by Giscus