Cypress tests running in GitHub Actions can fail because the GitHub Actions runner environment doesn’t always perfectly mimic a local development machine, leading to subtle differences in how the browser or system behaves.

Common Causes for Cypress Failures in GitHub Actions

  1. Headless Browser Environment Differences:

    • Diagnosis: The most frequent culprit is that headless Chrome/Electron in CI environments (like GitHub Actions) can have different rendering or font-rendering behaviors than a full GUI browser on your local machine. This can cause element positioning to shift, leading to cy.get() failing to find elements it should.
    • Check: Look for errors like Timed out retrying: cy.get(...) failed because the element was not found. or visual discrepancies in screenshots taken by Cypress in the Action logs.
    • Fix: Explicitly set chromeWebSecurity: false in your cypress.config.js or cypress.json file.
      // cypress.config.js
      const { defineConfig } = require('cypress');
      
      module.exports = defineConfig({
        e2e: {
          setupNodeEvents(on, config) {
            // implement node event listeners here
          },
          chromeWebSecurity: false, // Add this line
        },
      });
      
    • Why it works: Disabling Chrome web security bypasses certain browser security restrictions that might behave differently or cause issues in the isolated CI environment, allowing tests to proceed more reliably.
  2. Insufficient Runner Resources (CPU/Memory):

    • Diagnosis: CI runners, especially free-tier GitHub Actions runners, can be resource-constrained. Cypress, being a browser-based testing tool, can be memory-intensive, especially with multiple tests or complex applications. This can lead to the runner becoming unresponsive or processes being killed.
    • Check: Monitor the GitHub Actions runner’s resource usage if possible (though direct monitoring is limited). Look for generic timeouts in your workflow or Cypress logs that don’t point to a specific element. The workflow might simply stop without a clear error, or you might see Killed messages in the runner’s output.
    • Fix:
      • Option A (Upgrade Runner): If you’re on a free tier, consider upgrading your GitHub Actions minutes or using self-hosted runners with more resources.
      • Option B (Optimize Cypress):
        • Reduce parallelism if you’re running tests in parallel.
        • Close unnecessary browser tabs or windows within your tests.
        • Ensure your application under test isn’t consuming excessive memory itself.
        • Use cypress run --browser chrome --headless to ensure a consistent headless run.
    • Why it works: Providing more CPU and memory prevents the runner from hitting resource limits, allowing Cypress and the browser to execute without being terminated by the operating system.
  3. Incorrect baseUrl Configuration:

    • Diagnosis: Cypress needs to know where to find your application. If the baseUrl is not correctly set or accessible from the CI environment, tests will fail immediately when trying to visit the application.
    • Check: Errors like The base URL 'http://localhost:3000' did not resolve. or Could not connect to the server.
    • Fix: Ensure your cypress.config.js has the correct baseUrl. If your app is served locally during CI, use http://localhost:PORT where PORT is the port your app runs on. Often, you’ll start your app as a service in the GitHub Actions workflow before running Cypress.
      // cypress.config.js
      const { defineConfig } = require('cypress');
      
      module.exports = defineConfig({
        e2e: {
          setupNodeEvents(on, config) {
            // implement node event listeners here
          },
          baseUrl: 'http://localhost:3000', // Ensure this matches your app's CI port
        },
      });
      
    • Why it works: A correct baseUrl tells Cypress exactly where to navigate its browser instance to start testing your application.
  4. Missing Dependencies or Incorrect Setup:

    • Diagnosis: Your GitHub Actions workflow might not be installing all necessary Node.js dependencies, or Cypress itself might not be installed correctly. This is especially common if you’re not using npm ci or if your package.json is missing the cypress dependency.
    • Check: Look for errors like cypress: command not found or npm ERR! code MODULE_NOT_FOUND.
    • Fix: Ensure your workflow includes a step to install dependencies using npm ci (which is generally preferred in CI for deterministic installs) or yarn install --frozen-lockfile. Make sure cypress is listed in your devDependencies in package.json.
      # .github/workflows/cypress.yml
      jobs:
        e2e-tests:
          runs-on: ubuntu-latest
          steps:
            - uses: actions/checkout@v3
            - name: Use Node.js
              uses: actions/setup-node@v3
              with:
                node-version: '18'
            - name: Install dependencies
              run: npm ci # Use npm ci for clean installs
            - name: Run Cypress tests
              run: npx cypress run
      
    • Why it works: npm ci ensures that all project dependencies, including Cypress, are installed exactly as defined in your package-lock.json or npm-shrinkwrap.json, preventing issues from outdated or missing packages.
  5. Application Not Ready When Tests Run:

    • Diagnosis: Your Cypress tests might start executing before your application under test has fully initialized and is ready to accept connections or render its UI. This is particularly true if your app has a slow startup time or if you’re starting it within the same workflow.
    • Check: Errors like Could not connect to the server (if the app hasn’t started) or tests failing because elements aren’t present yet, even though the app is technically running.
    • Fix: Implement a health check or a wait mechanism. You can use a simple sleep command in your workflow (though not ideal) or, better yet, a small script that polls your application’s health endpoint or baseUrl until it responds successfully.
      # .github/workflows/cypress.yml (example using a wait script)
      jobs:
        e2e-tests:
          runs-on: ubuntu-latest
          steps:
            - uses: actions/checkout@v3
            - name: Use Node.js
              uses: actions/setup-node@v3
              with:
                node-version: '18'
            - name: Install dependencies
              run: npm ci
            - name: Start application (example)
              run: npm start & # Run your app in the background
            - name: Wait for application to be ready
              run: |
                npx wait-on http://localhost:3000 # wait-on is a common npm package for this
            - name: Run Cypress tests
              run: npx cypress run
      
    • Why it works: The wait-on command (or a similar polling mechanism) ensures that the Cypress test runner only proceeds after confirming that the application server is actively listening and responding on the specified port.
  6. Incorrect PORT or HOST Environment Variables:

    • Diagnosis: If your application’s behavior is dependent on environment variables like PORT or HOST, and these are not explicitly set or are set incorrectly in the GitHub Actions environment, your app might not start on the expected address or port.
    • Check: Application startup logs for your app in the Actions run. Verify that the baseUrl in Cypress matches where your app is actually running.
    • Fix: Explicitly define these environment variables in your GitHub Actions workflow.
      # .github/workflows/cypress.yml
      jobs:
        e2e-tests:
          runs-on: ubuntu-latest
          env:
            PORT: 3000 # Example port
            HOST: localhost
          steps:
            # ... rest of your workflow
            - name: Run Cypress tests
              run: npx cypress run
      
    • Why it works: By setting PORT and HOST in the workflow’s env block, you ensure that your application is configured to run on the expected network interface and port, which Cypress can then reliably connect to via its baseUrl.

After fixing these, the next hurdle you’ll likely encounter is dealing with flaky tests due to race conditions that are more pronounced in CI, often manifesting as intermittent Element is not clickable at point errors.

Want structured learning?

Take the full Cypress course →