TestKase Docs
AutomationTest Frameworks

Cypress

Set up Cypress for end-to-end testing and integrate test results with TestKase.

Overview

Cypress is a JavaScript end-to-end testing framework built for the modern web. It features time-travel debugging, automatic waiting, real-time reloads, and consistent results with its unique architecture that runs tests directly in the browser.

To integrate Cypress results with TestKase, use either:

  • --format junit with JUnit XML output (via mocha-junit-reporter)
  • --format cypress with Mochawesome JSON output (via cypress-mochawesome-reporter)

Prerequisites

  • Node.js 18+
  • A web application to test (running locally or deployed)

Installation

Install Cypress as a dev dependency:

npm install --save-dev cypress

Open Cypress for the first time to generate the default directory structure:

npx cypress open

This creates the cypress/ directory with scaffolded folders and example specs.

Project Setup

Create or update cypress.config.js in your project root:

// cypress.config.js
const { defineConfig } = require('cypress');

module.exports = defineConfig({
  e2e: {
    baseUrl: 'http://localhost:3000',
    specPattern: 'cypress/e2e/**/*.cy.{js,ts}',
    supportFile: 'cypress/support/e2e.js',
  },
});

Directory Structure

After setup, your Cypress project will have this structure:

cypress/
  e2e/           # Test spec files
  fixtures/      # Test data (JSON files)
  support/       # Custom commands and setup
    e2e.js       # Support file loaded before each spec
cypress.config.js

Writing Tests

Create a test file (e.g., cypress/e2e/login.cy.js):

// cypress/e2e/login.cy.js
describe('Login', () => {
  beforeEach(() => {
    cy.visit('/login');
  });

  it('[48271] should login with valid credentials', () => {
    cy.get('[data-testid="email"]').type('user@example.com');
    cy.get('[data-testid="password"]').type('password123');
    cy.get('[data-testid="login-button"]').click();
    cy.url().should('include', '/dashboard');
  });

  it('[48272] should display error for invalid password', () => {
    cy.get('[data-testid="email"]').type('user@example.com');
    cy.get('[data-testid="password"]').type('wrong');
    cy.get('[data-testid="login-button"]').click();
    cy.get('.error-message').should('be.visible');
  });

  it('[48273] should require email field', () => {
    cy.get('[data-testid="login-button"]').click();
    cy.get('[data-testid="email-error"]').should('contain', 'Email is required');
  });
});

Each test name includes a 5-digit Automation ID in square brackets. The @testkase/reporter CLI extracts these IDs using the regex \[(\d{5})\]. For the example above, the extracted Automation IDs are:

  • 48271 → linked to the "valid login" test case in TestKase
  • 48272 → linked to the "invalid password" test case in TestKase
  • 48273 → linked to the "email required" test case in TestKase

Generate Automation IDs in TestKase first, then embed them in your it() names. The [XXXXX] pattern can appear anywhere in the test name — the reporter extracts all 5-digit IDs found in brackets.

Running Tests

Run tests in headless mode:

npx cypress run

Open the interactive Test Runner:

npx cypress open

Generating JUnit XML Output

Install the mocha-junit-reporter package:

npm install --save-dev mocha-junit-reporter

Add the reporter configuration to cypress.config.js:

// cypress.config.js
const { defineConfig } = require('cypress');

module.exports = defineConfig({
  e2e: {
    baseUrl: 'http://localhost:3000',
    specPattern: 'cypress/e2e/**/*.cy.{js,ts}',
    supportFile: 'cypress/support/e2e.js',
  },
  reporter: 'mocha-junit-reporter',
  reporterOptions: {
    mochaFile: 'test-results/junit-[hash].xml',
    toConsole: false,
  },
});

Then run tests as usual:

npx cypress run

The JUnit XML files will be written to the test-results/ directory.

The [hash] placeholder in mochaFile ensures each spec file generates a unique XML file, preventing overwrites when running multiple specs. You can point the reporter to a specific file or use a glob pattern.

TestKase Integration

After generating the JUnit XML files, report results to TestKase:

npx @testkase/reporter report \
  --token $TESTKASE_PAT \
  --project-id PRJ-1 \
  --org-id 1173 \
  --cycle-id TCYCLE-5 \
  --format junit \
  --results-file "test-results/junit-*.xml"

--cycle-id is optional. If not provided, results are reported to TCYCLE-1 — the master test cycle for the project.

If you have a single output file (without the [hash] pattern), point to it directly:

  --results-file test-results/junit.xml

Automation ID Mapping

The reporter extracts 5-digit Automation IDs from Cypress test names using the [XXXXX] bracket pattern:

Test CodeExtracted ID
it('[48271] should login with valid credentials', ...)48271
it('[48272] should display error for invalid password', ...)48272
describe('Cart', () => { it('[48273] calculates total', ...) })48273

The [XXXXX] pattern can appear anywhere in the it() name. The describe block structure does not affect the Automation ID — only the 5-digit number inside brackets matters.

Complete Example

1. Test File

// cypress/e2e/login.cy.js
describe('Login', () => {
  beforeEach(() => {
    cy.visit('/login');
  });

  it('[48271] should login with valid credentials', () => {
    cy.get('[data-testid="email"]').type('user@example.com');
    cy.get('[data-testid="password"]').type('password123');
    cy.get('[data-testid="login-button"]').click();
    cy.url().should('include', '/dashboard');
  });

  it('[48272] should display error for invalid password', () => {
    cy.get('[data-testid="email"]').type('user@example.com');
    cy.get('[data-testid="password"]').type('wrong');
    cy.get('[data-testid="login-button"]').click();
    cy.get('.error-message').should('be.visible');
  });
});

2. Run Tests (JUnit output configured in cypress.config.js)

npx cypress run

3. Report Results to TestKase

npx @testkase/reporter report \
  --token $TESTKASE_PAT \
  --project-id PRJ-1 \
  --org-id 1173 \
  --cycle-id TCYCLE-5 \
  --format junit \
  --results-file "test-results/junit-*.xml"

Troubleshooting

Multiple XML files generated

When using mocha-junit-reporter with the [hash] pattern, each spec file produces a separate XML file. This is expected behavior. You have two options:

  1. Use a glob pattern to pass all files to the reporter:

    --results-file "test-results/junit-*.xml"
  2. Use a single file by removing the [hash] placeholder (note that results from multiple specs will overwrite each other unless you run a single spec):

    reporterOptions: {
      mochaFile: 'test-results/junit.xml',
    }

Cypress not finding test files

Verify that your specPattern in cypress.config.js matches your test file names and locations:

e2e: {
  specPattern: 'cypress/e2e/**/*.cy.{js,ts}',
}

Common issues:

  • Test files use .spec.js extension instead of .cy.js — update the pattern to include both
  • Test files are in the wrong directory — ensure they are under cypress/e2e/
  • The e2e config block is missing from cypress.config.js

baseUrl connection refused

Cypress cannot connect to your application if it is not running. Ensure your dev server is started before running tests:

# Start your app first
npm run dev &

# Then run Cypress
npx cypress run

For CI environments, use the start-server-and-test package to start the server and run tests in sequence:

npm install --save-dev start-server-and-test
{
  "scripts": {
    "dev": "next dev",
    "test:e2e": "start-server-and-test dev http://localhost:3000 'cypress run'"
  }
}