Add Cypress and Cucumber to your Angular project

Posted on: 22-2-2024

To add Cypress 13 to your Angular 17 project and use Cucumber to write feature files you have to follow the following steps.

  1. Add Cypress
  2. Add dependencies
  3. Extend Cypress config
  4. Add section to package.json
  5. Write feature files
  6. Write step definitions
  7. Run test

1. Add Cypress

Use the Angular CLI to automatically add cypress to your project by running the following command.
ng e2e

If you run this command for the first time you get asked to choose between different packages that offer e2e capabilities.

Choose Cypress and select all the default options during setup. This will add cypress and makes it possible to run e2e tests and component tests.

Now you can run the created default test by running

ng e2e

and using the cypress UI.

OR

don't use the Angular CLI and add cypress manually.

npm install cypress --save-dev

Create a tsconfig.json inside the cypress folder and give it the following content:

{
  "compilerOptions": {
    "target": "es5",
    "lib": ["es5", "dom"],
    "types": ["cypress", "node"]
  },
  "include": ["**/*.ts"]
}

You can run cypress using the following command:

npx cypress open

(make sure your application is running before running this command).

Now that cypress works, let's add the cucumber preprocessor to make it possible to write feature files in the Gherkin DSL.

2. Add dependencies

Add the Cucumber preprocessor by installing it using a package manager.
npm install --save-dev @badeball/cypress-cucumber-preprocessor

Also add the following dependency:

npm install --save-dev @bahmutov/cypress-esbuild-preprocessor

3. Extend Cypress config

We have got to extend our Cypress config to make sure the Cucumber preprocessor and Cypress can work together.

Add the following key-value pair to your config to make sure future .feature files get found when running cypress:

specPattern: '**/*.feature',

Add the following snippet to your config to add the Cucumber preprocessor and make sure it works together with Cypress:

async setupNodeEvents(
  on: Cypress.PluginEvents,
  config: Cypress.PluginConfigOptions
): Promise<Cypress.PluginConfigOptions> {
  await addCucumberPreprocessorPlugin(on, config);

  on(
    "file:preprocessor",
    createBundler({
      plugins: [createEsbuildPlugin(config)],
    })
  );

  // Make sure to return the config object as it might have been modified by the plugin.
  return config;
}

This is what your cypress.config file should look like:

import { defineConfig } from 'cypress'
import {addCucumberPreprocessorPlugin} from "@badeball/cypress-cucumber-preprocessor";
import createBundler from "@bahmutov/cypress-esbuild-preprocessor";
import { createEsbuildPlugin } from "@badeball/cypress-cucumber-preprocessor/esbuild";

export default defineConfig({
  e2e: {
    specPattern: '**/*.feature',
    baseUrl: 'http://localhost:4200',
    async setupNodeEvents(
      on: Cypress.PluginEvents,
      config: Cypress.PluginConfigOptions
    ): Promise<Cypress.PluginConfigOptions> {
      await addCucumberPreprocessorPlugin(on, config);

      on(
        "file:preprocessor",
        createBundler({
          plugins: [createEsbuildPlugin(config)],
        })
      );

      // Make sure to return the config object as it might have been modified by the plugin.
      return config;
    }
  },
  component: {
    devServer: {
      framework: 'angular',
      bundler: 'webpack',
    },
  }
})

4. Add section to package.json

Add the following to your package.json so your step definitions can get found:
"cypress-cucumber-preprocessor": {
    "stepDefinitions": [
      "cypress/support/step_definitions/**/*.{js,ts}"
    ]
}

5. Write feature files

Write a feature file and place it in cypress/e2e/features.
Feature: App
  Scenario: some scenario
    Given some given
    When some when
    Then some then

6. Write step definitions

Write step definitions for the steps you created in your feature file.

Create a folder called cypress/support/step_definitions. This is where your step definitions will live.

Note that this folder needs to have the same name as the one provided in package.json.

Create a file and give it a name, e.g. app.ts and give it the following content:

import {Given, Then, When} from "@badeball/cypress-cucumber-preprocessor";

Given('some given', () => {
  cy.visit('/');
});

When('some when', () => {
  cy.contains('congratulations');
});

Then('some then', () => {
  cy.contains('app is running');
});

7. Run test

Run
ng e2e

again to run your tests and see that the feature files work!

Links

preprocessor repo

preprocessor quick start

preprocessor step definitions