Getting Started With Cypress To E2E Test Angular Apps

One of the key reasons I like Angular is because it comes with all the bells and whistles (unlike some other SPA JavaScript frameworks). I like rapidly prototyping applications with minimal setup and configurations which I was I massively appreciate being able to run ng new myApp and end up with a zero-configuration-needed Angular application with testing built right in!

Back in the days of AngularJS, ProtractorJS was way ahead of it's time, and that made testing AngularJS applications relatively easy. I say relatively because it still wasn't the best experience for developers… But it was the best experience for E2E testing that I knew of. With the release of Angular, Protractor was rewritten to support the new framework, and comes packaged with any Angular CLI application. But for some applications it still may not be the best experience. Since you are here reading this post, I will assume you have had a sub-par experience trying to test your Angular application with Protractor and perhaps even heard about how the grass is greener with Cypress. You are in the position I was only a few short months ago…

https://twitter.com/zaarheed/status/1070997120897961984

Cypress recently came out of Beta so I decided to give it a spin - and I was not disappointed. Protractor is a great tool, in fact most of the teams working on Google's suit of products use it to test their front-end code, but Cypress is better aligned with what I needed.

What I love about Cypress:

  • Super-simple API. Everything is based off the cy object.
  • Spin up a disposable server from within a test to act as a mock endpoint.
  • Automatically waits for network requests to complete before continuing tests.
  • A unique assertion approach whereby it will keep retrying until timed out. Super useful to avoid flaky tests as a result of slow-rendering UIs.
  • Configure timeouts on assertions and commands on a per assertion/command basis. Or configure timeouts on an entire test level.
  • Comes as standard with a GUI that shows you what's happening during each step of your tests
  • Debug-first approach to testing with the ability to time-travel through each test
  • Built-in support for screenshots, video recordings and CI servers
  • Incredible level of documentation in simple-to-understand language. Great for those who are new to testing.

With Cypress, most developers can write their first test within five minutes from scratch!

After some initial configuration, writing Cypress tests is a breeze. Below, I'll outline how I configured Cypress to work with my Angular application written by a development team of five.

Getting Started With Cypress To E2E Test Angular Apps

Step 1: Assuming you already have an Angular CLI app (created using the ng new myApp command), navigate to the root of your Angular project directory and install Cypress via NPM with the following command:

npm install cypress

This will create a directory called cypress in the root of your project alongside Protractor's e2e directory. Inside this directory you will find five folders:

  • fixtures - fixture files contain static data you may want to use in your tests
  • integrations - where all your E2E test files live
  • plugins - Cypress' mechanism for extensibility. By default the plugins/index.js file is executed before every test
  • videos - video recording of your tests where enabled
  • screenshots - screenshots from your tests where enabled

Some of these folders may not exist until you run your initial test(s).

Step 2: Next we will add two commands to our package.json file so that we can run Cypress. Since Cypress has only been installed to our project directory, and not globally, we can't run the cypress command without explicitly referencing the executable.

Add the following two lines to the scripts object in the package.json file located in the root of your Angular application:

"scripts": {
    ...
    "cypress-open": "node_modules\\.bin\\cypress open",
    "cypress-run": "node_modules\\.bin\\cypress run"
  },

All this does is allow us to run npm run cypress-open instead of $(npm bin)/cypress open to open the Cypress GUI.

Step 3: This next step is optional, but recommended for Angular projects to avoid the pain of context switching when developing and writing tests.

Though Cypress supports JavaScript, CoffeeScript, TypeScript and JavaScript XML (JSX); by default tests are written in JavaScript. To add support for TyepScript, we can use an NPM package called @bahmutov/add-typescript-to-cypress to preprocess our scripts.

Start by running the following command from the root of your Angular project:

npm i @bahmutov/add-typescript-to-cypress

Once installed you will notice a new file plugins/cy-ts-preprocessor.js and a reference to it in plugins/injex.js.

Step 4: At this point you are finished configuring Cypress for your Angular application. You can now follow the Cypress Documentation to begin writing tests in the integrations/ directory. If you are writing your tests using TypeScript, remember to save your files with the .ts extension.

If you completed Step 2 of this guide, remember to run npm run cypress-open and npm run cypress-run instead of cypress open and cypress run respectively. If you need to pass additional parameters to these commands, you'll need to use an additional -- due to the way the npm run command works. For example, instead of cypress run --record you would do npm run cypress-run -- --record.

Step 5: You may find that your code editor or IDE (VS Code in my case) sometimes fails to pick up the definitions within your Cypress test files. There are two solutions to this.

The first solution is to create a tsconfig.json in the cypress directory with the following code:

{
    "extends": "../tsconfig.json",
    "include": [
        "integration/*.ts",
        "support/*.ts",
        "../node_modules/cypress"
    ]
}

If the tsconfig.json file does not resolve the issue, you can add the following line to the top of all your .ts files:

/// <reference types="Cypress" />