Skip to content

Cypress Developer Guide

Paulo Gomes da Cruz Junior edited this page Jul 14, 2026 · 5 revisions

Developer Guide

This guide covers everything a developer needs to set up, run, and extend the Cypress end-to-end test suite.

Project structure

cypress/
├── cypress.config.ts          # Cypress configuration (env vars, plugins, reporter)
├── package.json               # Dependencies and npm scripts
├── tsconfig.json              # TypeScript configuration
├── .env                       # Local credentials (git-ignored, create manually)
├── README.md                  # Quick start guide
├── summary.md                 # Generated test summary (after run)
├── cypress/
│   ├── e2e/                   # Feature files (.feature)
│   ├── fixtures/              # Static test data
│   ├── screenshots/           # Auto-captured failure screenshots
│   ├── videos/                # Recorded test videos
│   └── support/
│       ├── commands.ts        # Custom Cypress commands (UI/UX checks)
│       ├── cypress.d.ts       # TypeScript declarations for custom commands
│       ├── e2e.ts             # Support entry point
│       ├── helpers/           # Helper modules
│       │   ├── index.ts
│       │   ├── a11y.helpers.ts
│       │   ├── designTokens.helpers.ts
│       │   ├── elements.helpers.ts
│       │   ├── general.helpers.ts
│       │   ├── input.helpers.ts
│       │   ├── lighthouse.helpers.ts
│       │   ├── tokens.helpers.ts
│       │   └── uxui.helpers.ts
│       └── step_definitions/  # Shared step definitions
│           ├── hooks/               # Hooks
│           │   ├── index.ts
│           │   ├── browser.hooks.ts   # Browser hooks (@chromeOnly)
│           │   └── logins.hooks.ts    # Authentication hooks
│           └── steps/               # Step definitions
│               ├── a11y.steps.ts         # Accessibility checks
│               ├── button.steps.ts       # Button interactions
│               ├── common.steps.ts       # Navigation
│               ├── designTokens.steps.ts # Design token validation
│               ├── input.steps.ts        # Form inputs and selections
│               ├── lighthouse.steps.ts   # Lighthouse/performance checks
│               ├── text.steps.ts         # Text assertions
│               └── uiux.steps.ts         # UI/UX quality checks
├── scripts/                   # Report generation scripts
│   ├── parse-report.js        # Main report parser
│   ├── modules/               # Report modules
│   │   ├── accessibilityModule.js
│   │   ├── lighthouseModule.js
│   │   ├── mochawesomeModule.js
│   │   └── uiuxModule.js
│   ├── parsers/               # JSON parsers
│   │   └── mochawesomeParser.js
│   └── renderers/             # Output renderers
│       └── markdownWriter.js
└── reports/                   # Generated reports (after run)
    ├── mochawesome/           # Test results JSON
    ├── a11y/                  # Accessibility results JSON
    ├── lighthouse/            # Lighthouse results JSON
    └── uiux/                  # UI/UX results JSON

Environment variables

The test suite requires credentials to authenticate during login hooks. They are loaded via dotenv in cypress.config.ts and exposed through Cypress.env().

Variable Description
idir_username Username for the IDIR login
idir_password Password for the IDIR login
bceid_username Username for the BCeID login
bceid_password Password for the BCeID login
MOCHAWESOME_REPORT Enable mochawesome JSON output

The baseUrl is not an environment variable — it is passed directly to Cypress via the --config flag (see Running the tests).

Local development — .env file

Create a .env file in the cypress/ directory (it is git-ignored):

idir_username=your_idir_username
idir_password=your_idir_password
bceid_username=your_bceid_username
bceid_password=your_bceid_password
MOCHAWESOME_REPORT=true

Note

Environment variables in the .env file use lowercase names (idir_username, bceid_username). The Cypress configuration reads these directly.

GitHub Actions workflow

In CI, the same variables must be available as repository secrets. The workflow uses the CYPRESS_ prefix for environment variables when using the cypress-io/github-action:

jobs:
  cypress:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6

      - name: Run Cypress tests
        uses: cypress-io/github-action@v5
        working-directory: cypress
        env:
          CYPRESS_baseUrl: https://${{ vars.BASE_URL }}
          CYPRESS_idir_username: ${{ secrets.IDIR_USERNAME }}
          CYPRESS_idir_password: ${{ secrets.IDIR_PASSWORD }}
          CYPRESS_bceid_username: ${{ secrets.BCEID_USERNAME }}
          CYPRESS_bceid_password: ${{ secrets.BCEID_PASSWORD }}
          MOCHAWESOME_REPORT: true
        with:
          browser: chrome

Tip

Store credentials in GitHub Secrets (Settings → Secrets and variables → Actions) and the base URL in GitHub Variables so it can be changed without a code commit.

Cypress configuration settings

The cypress.config.ts file sets several options that affect test behavior. These are not documented elsewhere.

Setting Value Effect
defaultCommandTimeout 10000ms How long Cypress waits for DOM elements to appear before failing
pageLoadTimeout 60000ms Maximum time Cypress waits for a page to finish loading
viewportWidth 1920 Default viewport width for screenshots and Lighthouse desktop mode
viewportHeight 1080 Default viewport height for screenshots
video true Records video for every spec file (saved to cypress/videos/)
trashAssetsBeforeRuns true Deletes previous screenshots, videos, and downloads before each run
chromeWebSecurity false Disables same-origin policy and cross-origin security checks
includeShadowDom false Cypress ignores shadow DOM elements when querying
retries.runMode 1 Retries failed tests once in headless mode
retries.openMode 0 No retries in interactive mode

The chromeWebSecurity: false setting allows Cypress to visit external domains (like the IDIR login page at logontest7.gov.bc.ca) without cross-origin errors. This is required for the login hooks to work.

Creating a feature file

Create a new file with the .feature extension inside cypress/cypress/e2e/. Feature files use Gherkin syntax.

Feature: User Registration
  As a new user
  I want to register on the website
  So that I can access exclusive content

For the basics of writing features and scenarios, see Writing Test Scenarios.

Step definitions structure

Step definitions are the TypeScript implementation of Gherkin steps. Shared step definitions live in cypress/cypress/support/step_definitions/ and are organized by concern:

File Responsibility
steps/common.steps.ts Navigation (I visit ...)
steps/text.steps.ts Text assertions (I can read ..., I cannot see ..., I wait for ...)
steps/button.steps.ts Button clicks (I click on ..., I search)
steps/input.steps.ts Form inputs (I type ..., I clear ..., I select ...)
steps/a11y.steps.ts Accessibility checks (axe, keyboard navigation)
steps/lighthouse.steps.ts Lighthouse/perceived performance checks
steps/uiux.steps.ts UI/UX style checks
steps/designTokens.steps.ts Design token validation
hooks/browser.hooks.ts Browser hooks (@chromeOnly)
hooks/logins.hooks.ts Authentication hooks (@loginAsIDIR, @loginAsBCeID)

When adding a new shared step, place it in the most appropriate file above.

The package.json sets nonGlobalStepDefinitions: true for the Cucumber preprocessor. This means step definitions in support/step_definitions/ are shared across all feature files globally, rather than being colocated per feature file. You do not need to create a matching .ts file for each .feature file.

Running the tests

With the Cypress UI (interactive)

# Against localhost:3000
npm run cy:open:local

Headless (CI-friendly)

# Against localhost (127.0.0.1:3000)
npm run cy:run:local

# Against localhost with JSON report generation
npm run cy:run:md:local

Running with a custom URL

# Interactive mode
npx cypress open --config "baseUrl=https://your-app-url.example.com"

# Headless mode
npx cypress run --config "baseUrl=https://your-app-url.example.com"

You can target either the deployed application or a local environment. Ideally the results should be the same in both cases.

Running subsets of tests

You don't always need to run the entire suite. Several options let you target specific tests.

By feature file

# Run only the search feature
npx cypress run --spec "cypress/e2e/search.feature"

# Run multiple specific files
npx cypress run --spec "cypress/e2e/search.feature,cypress/e2e/logouts.feature"

By tag

Cucumber preprocessor supports --env with a grep option:

# Run only scenarios tagged @loginAsBCeID
npx cypress run --env grepTags="@loginAsBCeID"

# Run only Chrome-only scenarios (Lighthouse, etc.)
npx cypress run --env grepTags="@chromeOnly"

# Combine tags (AND logic)
npx cypress run --env grepTags="@loginAsBCeID @chromeOnly"

By grep pattern

# Run scenarios whose name contains "search"
npx cypress run --env grep="search"

# Run scenarios matching a regex
npx cypress run --env grep="Search for.*RU"

Interactive mode subsets

In cypress open, you can click on individual scenarios to run them. The grep options also work in interactive mode:

npx cypress open --env grepTags="@loginAsBCeID"

Lighthouse configuration

Lighthouse runs in-process via the lighthouse npm package, connected to Chrome through the remote debugging port. The system resolves whether to run in mobile or desktop mode using this fallback chain:

  1. env.lighthouseFormFactor — explicit override
  2. env.formFactor — alternative override
  3. env.platform — platform hint
  4. env.targetPlatform — target platform hint
  5. env.deviceType — device type hint
  6. Viewport width ≤ 768 → mobile, otherwise → desktop

Set any of these via environment variables or the env block in cypress.config.ts:

env: {
  lighthouseFormFactor: "mobile", // or "desktop"
}

Mobile emulation uses: 390×844 viewport, 2× device scale factor, formFactor: "mobile".

Desktop emulation uses: 1920×1080 viewport, 1× device scale factor, formFactor: "desktop" with the Lighthouse desktop config.

Lighthouse reports are cached per URL and options combination within a single spec file. If two scenarios visit the same URL with the same options, only one Lighthouse audit runs.

Test results, summary, and report generation

After execution, Cypress generates artifacts as proof of the run:

  • Screenshots — captured automatically on failure (in cypress/cypress/screenshots/)
  • Videos — recorded for each spec file (in cypress/cypress/videos/)
  • Mochawesome JSON — machine-readable test results (reports/mochawesome/)
  • Accessibility JSON — accessibility checks metadata (reports/a11y/)
  • Lighthouse JSON — Lighthouse audits (reports/lighthouse/)
  • UI/UX JSON — UI/UX quality checks (reports/uiux/)
  • summary.md — markdown summary for GitHub Actions or manual review

Summary generation

The summary.md file combines all report data into a human-readable markdown format. It includes:

  • Test summary — total tests, passed, failed, pending, skipped, and duration
  • Accessibility checks — checks executed and violations found
  • Lighthouse Quality Report — performance, accessibility, best-practices, SEO scores per path
  • UI/UX Report Summary — violations by taxonomy (typography, color, spacing, border)
  • Other failed tests — list of failed tests with error messages

Generate the summary by running:

# Generate summary.md from reports
npm run report:md

Report pipeline: During the test run, cy.task() calls accumulate results in Node.js arrays (a11yResults, uiuxResults, lighthouseResults). The before:run hook clears stale report files. The after:run hook writes each array to its JSON file under reports/. Then npm run report:md runs parse-report.js, which reads all four JSON directories and produces summary.md.

The summary script is located at cypress/scripts/parse-report.js and uses these modules:

Module Purpose
scripts/parse-report.js Main entry point, orchestrates all modules
scripts/modules/mochawesomeModule.js Reads mochawesome JSON, produces test result table and failed-test list
scripts/modules/accessibilityModule.js Reads a11y JSON, produces violation count table and top violations
scripts/modules/lighthouseModule.js Reads Lighthouse JSON, produces per-URL tables with category scores, metric values, and failed thresholds
scripts/modules/uiuxModule.js Reads UI/UX JSON, produces per-scenario violation tables grouped by taxonomy
scripts/parsers/mochawesomeParser.js Locates and reads mochawesome JSON files from reports/mochawesome/
scripts/renderers/markdownWriter.js Writes the final markdown string to summary.md

Running tests with report generation

# Run tests and generate JSON reports (without summary)
npm run cy:run:local

# Run tests and generate JSON reports AND summary markdown
npm run cy:run:md:local

CI Integration

In GitHub Actions, the summary is appended to the workflow run:

cat cypress/summary.md >> "$GITHUB_STEP_SUMMARY"

Note

When a feature file has a step without a corresponding step definition, the test will fail. Don't panic — this is expected when adding new instructions. A developer will be notified to implement the missing step.

Error handling and console behavior

The support entry point (cypress/cypress/support/e2e.ts) configures two global handlers:

Uncaught exception handler: Catches all uncaught exceptions thrown by the application during test execution. Only ResizeObserver errors are suppressed (these are benign browser noise from Carbon components). All other exceptions fail the test. If your application throws a new non-critical error during tests, add it to the filter in e2e.ts.

Console log forwarding: Intercepts console.log calls from the browser and forwards them to the Cypress command log. This makes browser logs visible in the test runner output and in CI logs, which helps with debugging failed tests.

See also

Waste Plus Wiki

Home

Architecture

Codes

Decisions

Knowledge Base

Development

Changes

Clone this wiki locally