Automating Regression Testing with Cypress and GitHub Actions
Run Cypress end-to-end tests in GitHub Actions so pull requests catch regressions before they reach production.
Introduction
Manual regression testing breaks down as an application grows. Cypress runs browser-level tests against real flows, and GitHub Actions can run those tests on every pull request and push.
Why Automate Regression Testing?
- Catch Breakages Early Every commit runs the regression suite, so failures show up before a release.
- Consistent Environments CI runners use the same browser versions and OS, which reduces local drift.
- Faster Feedback Developers get pass/fail results in minutes, reducing context-switching.
Setting Up Cypress
- Install dependencies
npm install --save-dev cypress # or yarn add --dev cypress - Initialize config
npx cypress open - Configure base URL (in cypress.config.js)
const { defineConfig } = require('cypress')
module.exports = defineConfig({
e2e: {
baseUrl: 'http://localhost:3000',
specPattern: 'cypress/e2e/**/*.cy.{js,ts}'
}
})
Writing Regression Tests
Place your critical “happy-path” and edge-case flows under cypress/e2e/regression/:
// cypress/e2e/regression/login.cy.js
describe('Regression: Login Flow', () => {
beforeEach(() => {
cy.visit('/login')
})
it('logs in with valid credentials', () => {
cy.get('input[name="email"]').type('user@example.com')
cy.get('input[name="password"]').type('correct horse battery staple')
cy.get('button[type="submit"]').click()
cy.url().should('include', '/dashboard')
cy.contains('Welcome back').should('be.visible')
})
it('shows error on invalid password', () => {
cy.get('input[name="email"]').type('user@example.com')
cy.get('input[name="password"]').type('wrongpassword')
cy.get('button[type="submit"]').click()
cy.contains('Invalid credentials').should('be.visible')
})
})
Integrating with GitHub Actions
Create a workflow file under .github/workflows/cypress-regression.yml:
name: Regression Tests
on:
push:
branches:
- main
pull_request:
jobs:
cypress:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Start application
run: npm start &
env:
CI: true
- name: Wait for server
uses: jakejarvis/wait-action@v1
with:
timeout: '60' # seconds
check-url: 'http://localhost:3000'
- name: Run Cypress regression suite
uses: cypress-io/github-action@v5
with:
start: npm start
wait-on: 'http://localhost:3000'
spec: 'cypress/e2e/regression/**/*.cy.{js,ts}'
- name: Upload test artifacts
if: failure()
uses: actions/upload-artifact@v3
with:
name: cypress-videos
path: cypress/videos
How it works
- Checkout & install with caching.
- Start your app in the background.
- Wait until the server responds.
- Run Cypress Action against only the regression specs.
- Upload artifacts (videos, screenshots) on failure for debugging.
Best Practices
- Isolate tests: Keep regression specs focused on critical flows.
- Tag and filter: Use CI-specific tags such as
@regressionto limit scope. - Parallelize: Use Cypress Dashboard or a GitHub matrix to split heavy suites.
- Reduce flakes: Use stable selectors such as
data-cyattributes and avoid network randomness.
Conclusion
Cypress and GitHub Actions give the team a repeatable check before code reaches users. Start with the flows that break most often, run them on pull requests, and use failure artifacts to fix regressions quickly.