End to End Testing React Apps With Cypress

A brief guide on how to run End-To-End testing on React apps with Cypress.

Rajat S
Bits and Pieces

--

When I was a junior dev I used to cringe at the thought of testing my apps. Testing is not easy. But with the help of right tools, writing tests can certainly be simpler and more fun.

Cypress is a JavaScript End-to-End Testing Framework that makes it really simple to setup, write, run, and debug tests.

If you have tried other End-to-End Testing Frameworks like Puppeteer, you will notice that these frameworks turn the browser into an air-gapped system. The more complex our app gets, the harder it will get to pass our tests. This is why most testers prefer to run there tests manually.

In this post, I will show you how Cypress can help you build tests that will run in a real browser. Cypress provides with an API for test automation that is really easy to use.

Instead of looking at a bland command terminal filled gibberish, Cypress comes with its own dashboard that will show us exactly what is happening during our tests. And, because Cypress works in the actual browser, we can also use the browser’s dev tools side-by-side with Cypress.

Tip: Using Bit (GitHub) you can virtually isolate, encapsulate and independently test your components with any framework or library. The isolated and tested components will become reusable across your apps 👍

Easily isolate, test and reuse components — Bit

Let’s dive in.

Setup

Instead of creating a whole new app, I am going to use a pre-existing project and run my Cypress tests on it.

Here, I have a simple ToDo app in React.

Clone this app into your system and run yarn install to install the dependencies.

$ git clone https://github.com/rajatgeekyants/ToDo-List.git
$ yarn install

Note: You can also checkout the app on Bit. Here you will be able to import any particular component of the app, without having to care about the rest.

With that out of the way, I can now get to the test phase of the app. Let’s install Cypress as a dev dependency to our app.

$ yarn add cypress -D

Now to open Cypress, all we have to do is run this command.

$ node_modules/.bin/cypress open

This will open the Cypress CLI (or dashboard) on your system and also create a cypress.json file and a cypress folder in your app’s root directory. The cypress folder is where we will be writing our tests.

If you feel that the command to open Cypress is too long or hard to remember, you can go to package.json and create a new script:

"cypress": "cypress open"

So if you run this script with NPM/Yarn, it should open the Cypress CLI. Inside the cypress folder, create a test file inside the integration folder. Unlike your normal test files where we name them something like App.test.js, in Cypress, the extension for the test file is .spec.js.

This is a very simple test that is only check it true is equal to true (which it obviously is). If you open the Cypress CLI, you will see that the new test file will be automatically listed there. Clicking on it will run the test and open the dashboard in the browser where you will be able to see the test result.

This test had nothing to do with the ToDo app. It just showed how tests are run using Cypress. Let’s start writing test for our actual app now.

Page Visits in Cypress

The first step in a Cypress test is to allow Cypress to visit the app in a browser. Let’s create a new test file and write the following code in it.

In the above code, I have an object named cy. This is a global object and gives us access to all the commands present in the Cypress API. I am using cy to access the visit command. Inside this command I am just going to pass '/'. Back in the root directory, go to the cypress.json file and write this in there:

{
"baseUrl": "http://localhost:3000"
}

Now, make sure that you are running the app using the start script. Next open the Cypress CLI and run this new test file. You will see the dashboard open in the browser, and inside the dashboard our app will run like this:

If you notice the command log on the left, you will see that Cypress is making an XHR call in order to get the app to open inside it.

Check For Focus

Here, I am going to run a test that will check if the browser is focused on the input field when it loads.

Before we do this, make sure that the input field in src/components/TodoList/index.js has a className property of new task alongwith the autoFocus property.

<input
autoFocus
className="new task"
ref={a => (this._inputElement = a)}
placeholder="enter task"
/>

Without these properties, our test will definitely fail. Create a new test file with the following code:

First, I visit the app inside the Cypress Dashboard. Once the app opens inside the dashboard, I am checking if the focused element has a class named new task.

Testing Controlled Input

In this test, I am going to check if the controlled input accepts text and has its value set appropriately.

In this test, I first visit the app inside the Cypress Dashboard. Now I want Cypress to type something inside the input field. In order to find the correct selector for input field, click on the Open Selector Playground button and click on the input field.

After getting the selector for the input field, I will make the cypress type some text inside it. To make sure Cypress has typed the correct text, I have used the should command.

Running Tests without any UI

The UI can make our app run slowly in case of large number of tests. The UI is anyway not going to be seen during Continuous Integration, so why load it at all?

To run our tests without launching Cypress UI, we first add a new script in package.json file.

"cypress:all": "cypress run"

By running this script, cypress will run all the tests and provide the results directly in the command terminal itself.

If you are worried that you did not actually get to see Cypress do the testing, Cypress will even record a video of the test that you can watch.

Create End-to-End Tests in Cypress

Cypress is most useful when we use it for integration tests. But an End-to-End test makes sure that nothing is missed in the entire app.

Here, I have created an end-to-end test. I first get Cypress to visit the app. Then Cypress will get the input using its selector .new. Cypress will then type the text New Todo. Finally I will get Cypress to mock an enter action, hence creating a new Todo.

What’s Next?

There are many other things that we can do with Cypress. For example, we can test variations of a feature, or we can access step-by-step logs of our tests. Plus, there is a whole lot of other things that Cypress can do with a Server-Side Rendered React App that I will try to cover in my next post.

--

--