</>

Technology

GitHub Actions

Difficulty

Intermediate

Interview Question

How do you run Cypress tests in GitHub Actions with parallel execution?

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
    },
  },
})

Follow AutomateQA

Related Topics