Photo by Ryoji Iwata on Unsplash, Graphic Design by @laurejoumier

Implementing code coverage with Angular and Cypress

E2E testing is an essential task in producing high quality software and an elementary component of any good CI/CD process.

Cypress is the go-to choice E2E testing framework for many Angular users. To make sure all your critical code is actually covered with tests, you need to generate code coverage reports.

This article is part of my Angular DevOps series on Medium (more at the end of the page). Here I will provide a step-by-step tutorial in implementing code coverage for your Angular + Cypress application.

Prerequisites

For this tutorial, we assume you have an existing Angular 9+ application (9.x, 10.x, 11.x, 12.x, 13.x). If you haven’t done so yet, configure Cypress as the E2E framework for your Angular application by adding the Cypress Angular Schematic to your project:

ng add @cypress/schematic

When prompted, confirm the default command. Now, you’re ready to go for the Angular + Cypress goodness:

1. Instrumenting your project

For the Cypress code coverage plugin to measure which code statements have been executed during your E2E tests, the code needs to be instrumented (adding additional counters to your source code before running it).

This is accomplished with istanbul.js, so let's install it together with the libraries needed for istanbul to understand our TypeScript files:

npm i -D @jsdevtools/coverage-istanbul-loader @istanbuljs/nyc-config-typescript istanbul-lib-coverage nyc webpack

We can now configure istanbul to work with TypeScript by creating an istanbul configuration file .nycrc at the project root:

2. Adding Cypress code coverage and webpack configuration

We have to configure webpack to instrument the code when building our project, so we create a new file cypress/coverage.webpack.ts and add the following content:

Also, “node” to the types array in cypress.tsconfig.json to avoid the type warning.

Finally, we can install the cypress code coverage library:

npm i -D @cypress/code-coverage

3. Configure Cypress

In cypress/support/index.ts, we import the code coverage library directly below import ‘./commands’ by adding this one-liner:

import '@cypress/code-coverage/support';

Now we can update cypress/plugins/index.ts by replacing the module.exports with the following block:

4. Extending the build process

To extend the angular-cli build process, we install custom-webpack (note the fixed version, this is due to a bug with @angular-builders/custom-webpack@13.0.0 with @jsdevtools/coverage-istanbul-loader):

npm i -D @angular-builders/custom-webpack@12.1.3

In angular.json, find the line “builder”: “@angular-devkit/build-angular:browser”, and replace it with:

"builder": "@angular-builders/custom-webpack:browser",

Then, add the following additional build configuration in architect.build.configurations:

Instead of modifying the build process of our local server, we create a new ng serve command to instrument our codebase only when running E2E tests. To do so, add the following block in your angular.json file below the “serve” block (replace myproject with your project name as defined in the package.json):

Now, we replace the ng serve in the E2E section with our custom webpack configuration (replace myproject with your project name from the package.json file):

To have the commands handy, add them to the package.json “scripts” section right after the line “e2e” (replace myproject with your project name):

That’s it! We can now run our tests and view the coverage information (if you newly installed cypress and have no tests yet, remove the line cy.contains(‘Replace me with something relevant’); from integration/spec.ts):

npm run e2e:ci && npm run e2e:coverage

The console will show you the coverage percentage, when you open the index.html file inside coverage/lcov-report/, you can see a nice HTML report to inspect the E2E coverage of your application:

HTML code coverage report generated by Cypress code coverage

What now? You can now implement the coverage analysis in your CI setup (e.g. using CircleCI, Bitbucket Pipelines or Github Actions) and to connect it with your code quality inspection tool (e.g. SonarCloud).

Next up in the Angular DevOps series:

  • Angular code quality inspection with SonarCloud [coming soon]
  • Continuous Integration (CI) with Angular and Bitbucket Pipelines [coming soon]

This tutorial was respectfully inspired from these previously published articles:

Updates

13 November 2021

  • Updated tutorial to use the official Angular Cypress schematic
  • Removed the notes on Webpack ^5.0.0
  • Updated the used dependencies to use better supported packages: @jsdevtools/coverage-istanbul-loader and @angular-builders/custom-webpack
  • Removed the step of passing a custom webpack configuration to the cypress preprocessor

2 April 2021

  • Added Note on Webpack ^5.0.0 to use a temporary cypress webpack preprocessor instead of @cypress/webpack-preprocessor
  • Added Note on Webpack ^5.0.0 in step #2, on how to use a fork with a peer dependency on Webpack v5 of istanbul-instrumenter-loader.
Photo by Ryoji Iwata on Unsplash, Graphic Design by @laurejoumier

Co-Founder & CTO of menutech.com | Enthusiast of food, wine & mountain sports.