Answer
Running Cypress Tests in GitHub Actions
Basic Cypress Workflow
YAML
# .github/workflows/cypress.yml
name: Cypress E2E Tests
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
cypress-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run Cypress tests
uses: cypress-io/github-action@v6
with:
start: npm start # start dev server
wait-on: 'http://localhost:3000'
wait-on-timeout: 60
browser: chrome
headed: false
env:
CYPRESS_BASE_URL: ${{ secrets.CYPRESS_BASE_URL }}
CYPRESS_USERNAME: ${{ secrets.TEST_USERNAME }}
CYPRESS_PASSWORD: ${{ secrets.TEST_PASSWORD }}
- name: Upload screenshots on failure
if: failure()
uses: actions/upload-artifact@v4
with:
name: cypress-screenshots
path: cypress/screenshots
if-no-files-found: ignore
- name: Upload videos
if: always()
uses: actions/upload-artifact@v4
with:
name: cypress-videos
path: cypress/videos
if-no-files-found: ignore
Parallel Execution — Matrix Strategy (Free, No Cypress Cloud)
YAML
name: Cypress Parallel Tests
on: [push, pull_request]
jobs:
cypress-parallel:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
spec:
- 'cypress/e2e/auth/**'
- 'cypress/e2e/dashboard/**'
- 'cypress/e2e/checkout/**'
- 'cypress/e2e/api/**'
name: Tests — ${{ matrix.spec }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- name: Run spec
uses: cypress-io/github-action@v6
with:
start: npm start
wait-on: 'http://localhost:3000'
spec: ${{ matrix.spec }}
env:
CYPRESS_BASE_URL: ${{ secrets.CYPRESS_BASE_URL }}
- if: always()
uses: actions/upload-artifact@v4
with:
name: results-${{ strategy.job-index }}
path: |
cypress/screenshots
cypress/videos
if-no-files-found: ignore
Parallel Execution — Cypress Cloud (Paid)
YAML
jobs:
cypress-cloud:
runs-on: ubuntu-latest
strategy:
matrix:
containers: [1, 2, 3, 4] # 4 parallel machines
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- uses: cypress-io/github-action@v6
with:
start: npm start
wait-on: 'http://localhost:3000'
record: true # ← Cypress Cloud
parallel: true # ← auto-balances specs
group: 'E2E Tests'
env:
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Cross-Browser Cypress
YAML
jobs:
cypress-cross-browser:
strategy:
matrix:
browser: [chrome, firefox, edge]
runs-on: ubuntu-latest
name: Cypress on ${{ matrix.browser }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: '20', cache: 'npm' }
- run: npm ci
- uses: cypress-io/github-action@v6
with:
browser: ${{ matrix.browser }}
start: npm start
wait-on: 'http://localhost:3000'
env:
CYPRESS_BASE_URL: ${{ secrets.CYPRESS_BASE_URL }}
- if: failure()
uses: actions/upload-artifact@v4
with:
name: screenshots-${{ matrix.browser }}
path: cypress/screenshots
cypress.config.js — CI Optimized
JavaScript
const { defineConfig } = require('cypress')
module.exports = defineConfig({
e2e: {
baseUrl: process.env.CYPRESS_BASE_URL || 'http://localhost:3000',
video: true,
screenshotOnRunFailure: true,
defaultCommandTimeout: 10000,
viewportWidth: 1280,
viewportHeight: 720,
retries: {
runMode: 2, // retry failed tests 2x in CI
openMode: 0, // no retry in interactive mode
},
},
})
