How to get started with Cypress

If you’ve been developing frontend applications recently, you’ve undoubtedly heard of Cypress.io. Cypress is a powerful testing framework that makes writing tests easy and really fun. I’ve used Cypress on a number of projects, and had a great experience. In this post I’m going to introduce Cypress, and walkthrough using Cypress with an Angular project.

This post was originally posted on Rhythm and Binary check it out here.


The Angular project that I use for this post can be found at the GitHub repo here.

What is Cypress?

Traditionally speaking, writing tests for projects has been a chore for developers. Cypress is a framework that enables you to more easily write tests for your frontend applications. One of the best parts about Cypress is that it makes testing fun. When you have developers that want to write tests, you get better projects for both the developer and user.

Why is testing important? Having tests enables you to quickly verify changes, be pseudo documentation, verify your apps health, and promote good code practices overall.

Cypress makes tests easier as it is (1) interactive and (2) runs alongside your application. This means that the Cypress test runner has full access to your code, and doesn’t run externally like Selenium frameworks do.

Cypress also sits on top of:

Since it uses these known frameworks, the syntax is very familiar like so:

It’s really incredible to see it all in action. When you run Cypress it opens a Chrome Browser and has your application running on the right with the Cypress test history on the left:


As you can see from the video, the Cypress test runner shows the execution steps of your tests. You can see what happened at each step, and even time travel back to what the app looked like at a specific point. You also can use the test runner to be able to select elements for tests (think xpath queries with Karma).

Additionally, with the Cypress test runner you get an output in the form of a report and video. You can store that output locally or send it to a Dashboard with your CI provider.

For the purposes of our post here, we’re just going to walkthrough setting up Cypress locally. For additional information, I recommend checking out my Angular-In-Depth post on Cypress here. I also recommend Michael Karén’s Angular-In-Depth post on Cypress here.

Installing Cypress

So before you can write Cypress tests, you’ll need to install it as a dev dependency of your application.

Go to your project root and do the following:

I should note that you can also do this same process in CI. Please consult the Cypress docs for more info here.

Once you’ve got it installed locally, you can run it directly from your node_modules directory with the following:

I usually make this a npm script so I can just run it like so:

You should also notice that Cypress right out of the box has several examples in the /cypress/integration/examples folder. These are really helpful when you’re first getting started. If you click “run all specs” you’ll see it run through the examples one file at a time.

Additionally, on your first run of Cypress notice several folders are created in your project:

  • fixtures are static data that you can call from within your tests. These could be mocks or stubbed responses. Check out the official docs on Cypress fixtures.

  • integration is where you place your actual test files by default.

  • plugins are where you can extend Cypress behavior.

  • screenshots are where screenshots of your test runs are stored. There are also videos that can be taken, but that must be done with the CI run of Cypress.

  • support is where you can define custom behavior of Cypress with your application.

With the cypress-open npm script I mentioned, you are working directly with the test runner. If you want to run it directly (as you would in CI) you’ll need to call cypress run. You can do this with another npm script like the following:

Go ahead and run the npm script with the following:

What you’ll find is that cypress will run the example tests right out of the box. This is nice because you can see what your CI output would look like. It also saves the videos (by default) in the “videos” directory.

Note that the videos created with Cypress are only done when using cypress run, and not when just using the test runner locally. You can see more on this in the Cypress configuration docs.

Also, Cypress can be configured with the cypress.json file in your project’s root directory. Please consult the Cypress Docs for more info.

In the next section we’ll write our first test!

Your First Cypress Test

So as I mentioned in the intro, I’m going to be writing Cypress tests with my project here. Please go ahead and do a git clone of that project if you haven’t already done so.

Before we proceed, we also need to make sure we can run Cypress alongside our application. If you just open cypress like we did before, it runs the test runner against the Cypress kitchen sink page. This is great, except we want to run Cypress against a locally running application instead of a hosted environment.

How do we do this? There are several npm packages that will achieve this for us. I recommend the following:

Since I’m focusing on local testing for this post, I’m just going to cover using concurrently.

First install concurrently in your project with:

Next I recommend creating an npm script that will call concurrently. You just have to supply concurrently two processes for it to run together. Here’s the script I created:

Once you’ve done that, run the following:

It should start the Cypress electron app and look like the following:


As you can see in the screenshot, Cypress is seeing the example files.

I recommend moving the examples from the /examples folder to a different directory outside of the /integration directory. This way the test runner only reads in the spec files you want to create and you don’t haver to be bothered with the default examples.

So now let’s go ahead and create a spec file for our first test.

In the sample app I’ve got pages that include:

  • forms (login)

  • lists

  • network requests

I’ve also already built out tests for each page:

  • forms = cypress/integration/form.spec.js

  • lists = cypress/integration/list.spec.js

  • network requests = cypress/integration/network.spec.js

I also created a file called first_test.spec.js that we can use to start. this file is found at /cypress/integration/first_test.spec.js. Let’s start there first.

The login form I’ve included with my sample app looks like the following:

The first_test.spec.js file already has a test that accesses the home page:

Here you see we’re using the cy.visit command to navigate to the home page.

To make things easier, lets add a base URL in the cypress.json file. This will prefix any URL paths we use to have the same base so we don’t have to type http://localhost:4200 for tests.

So open cypress.json and add:

Now lets change our test to just go to the /home-page path with:

Now when you run the test, you should see the same result.

Selector Playground

We’re going to find the start button on the home page, and then pass a click event to it. If you notice in the screenshot here, the “Cypress Selector Playground” tooltip is highlighted. We’ll need to click on that to turn that on. Once it’s on, you can select anything on the page and Cypress will generate the “cy.get” code for whatever element you’re trying to interact with.

Go back to the first_test.spec.js file from before. Run the test, and when it finishes click on the Playground Selector. Next click on the “start” button.


The Selector Playground detected that the “start button” had an ID of “startButton,” and created the line of code to get it as the following:

So lets go ahead and add that to a new test, where we go to the home page, and click the start button like so:

Here you notice that I also added a should to do an actual test. I’m verifying that the h1 element on the page has the text “Learn Cypress.” Since this all sits on top of mocha, chai, and sinon this is somewhat intuitive if you’ve used test runners before.

When you run the test again, you should see the following:

Now let’s wrap up the test by actually going to the page, entering a value and checking that the value is entered.

The finished test is in the file cypress/integration/form.spec.js as you see here:

List Pages

In most frontend applications you’ll utilize a list of some form. In my sample project I’ve included a list page that has a basic list that you can add and delete records from.

In my sample project if you look at the file /cypress/integration/list.spec.js you’ll see the list tests that I’ve written.

They’re very simple but basically just tests behavior for adding and removing a value from the list. If you notice, Cypress enables you to select items within a list with the “eq” syntax. This is really powerful, and also very intuitive.

In this case I found the fifth (counting starts at 0) element that I added, and did an assertion of its value.

Also in the delete test I check for the lists length with a “its” as you see here.

There are a lot more cool things you can do with lists. Check out the Cypress Docs on this type of selection here.

Network Requests

Finally, let’s briefly discuss network requests. Cypress has a lot of great support for async behavior and network requests.

If you navigate over to my sample project’s “Network Requests” page you’ll see that it asks you to pick a Star Wars movie. Once you’ve selected the movie, if you click “show details” it calls the Star Wars API and retrieves some details.


My project here is using the Star Wars API that can be viewed here. The project is open source and a fun API that you can use in projects.

To test this directly (an actual end to end test) looks like the following:

You can also verify the underlying payload from the API by intercepting the HTTP calls with Cypress. If you add a beforeEach that includes cy.server and cy.route:

There are a lot of really cool things you can do with the network request options with Cypress. Check out the docs for more info.

Tasks

In addition to the basic testing behavior we’ve covered you can also setup tasks in Cypress.

Tasks in Cypress are ways that you can get the runner to do some action alongside a test that is run. A typical example is read a file during testing. The code for this could look similar to the following:

This example was copied from the Cypress Tasks documentation.

There are a lot of cool things you can do with tasks. My friend Tim Deschryver wrote a really good post covering Cypress tasks here.

Commands

Commands in Cypress enable you to create routines that your tests can follow. This is particularly advantageous with a login or logout flow. It prevents you from having to add boilerplate code to walkthrough the login pages etc.

I’ve included an example of this in my GitHub project. If you go over to the file at cypress/support/commands.js file you’ll see the following:

Here you can see that the syntax almost is identical to how we were setting up our tests before. The difference here is that we are registering this behavior as a command. The really cool part about this is that you can use this to reduce boiler plate in your tests.

If you next go over to the file at cypress/integration/command_test.spec.js you’ll see the following:

Here you notice in the test’s before block I make reference to “start” which is just the command I built in the support directory. Before this test ran, Cypress read in the “start” command that I had created.

This is one of many really cool things you can do with commands. I recommend checking out the docs on this here.

Wrapping Up

So in this post you were introduced to Cypress. You were able to write some basic tests, and got the appropriate links to learn more. I highly recommend working with my sample project and building out additional tests. The Cypress documentation is really thorough, and they have a team of folks that are maintaining it.

One thing that I didn’t mention was that it currently only supports Chrome, but there is discussion of future browser expansion. However, when you consider the huge user base that Chrome supports, you realize that this really isn’t a problem for many applications.

In my honest opinion, the most powerful part of Cypress is that it makes testing fun. Once you’ve worked with Cypress for some time, you’ll notice that you enjoy the process of building tests in your project. It also greatly improves your code quality as the Cypress tests force you to see code you wouldn’t have noticed otherwise.

I hope my post has helped you to get started with Cypress. Feel free to leave comments and follow me on Twitter at @AndrewEvans0102!


Andrew Evans

@AndrewEvans

Engineer, husband, learner, and Star Wars fan.