Cypress.io: A hands-on overview

shaban.rahman
9 min readMar 3, 2019

--

Introduction

Developers often neglect sufficient end-to-end testing — probably because, as it should be done, it can be slow, cumbersome and expensive. However, I believe that such comprehensive testing is the most important phase of software development, and will show you herein a better and faster way to accomplish it.

Writing and fully implementing an end-to-end test comes with many benefits, the most important one being able to determine whether or not a web application works as intended for the user. Additionally, end-to-end tests ensure that new functionality does not break previously developed features. These concerns are crucial to every enterprise web application and shouldn’t be overlooked.

In this article, I’m going to introduce you to an awesome library called Cypress. Though JavaScript is not my language of choice, this tool stands out to me among the numerous tools for end-to-end testing. We’ll use Cypress to test a simple web application I built with React.js. We’ll ensure that, for example, a user can fill out input fields, assert that the values are correct, post these details to a backend server and redirect back to the homepage as shown below:

We’ll take a test driven development approach by writing an automated test that defines a particular feature, then we will write the required code to pass the test. This will demonstrate what makes Cypress impressive and introduce you to some of the basic knowledge that you can use for your web applications.

What is Cypress and why use it?

Cypress is a free and open source, MIT-licensed, testing tool written in JavaScript. As of this writing, it has over 9,400 Stars on Github and is used by organizations such as NASA and DHL. Cypress makes quality E2E, integration and unit tests easy to write and debug. With it, you can drive the browser like a human would.

Aside from the script runner, Cypress provides you with a visual interface to indicate which tests and which commands are running. It allows you to test highly interactive applications and carry out actions such as manipulating the DOM, asserting that some element is available within the UI, inputting data into fields, submitting forms and even redirecting to a different page without actually making direct modifications to your code. Sounds interesting, right?

Cypress is built and optimized as a tool for local development. In fact, after using Cypress for awhile, you may be tempted to do all of your development within it.

If you’re familiar with tools like Mocha and Chai, you’ve already got a head start. Cypress makes use of these tools under the hood but packs on many more features. With Cypress, you get to test a web application from the perspective of your end users. This will no doubt help many of you build more robust applications with more confidence.

What we want to achieve

The demo we’ll build is a simple CRUD application from which a user can submit a post then retrieve it from the server for display. To adequately implement the process, let’s start by setting our testing goals just so we can focus on what’s important and within the scope of this article.

The first step should always be to clearly write the project requirements document. From that, we can reason about and write the test cases for the application.

For this demo we want to:

  • Show a message as a placeholder, if there are no posts.
  • Navigate to the ‘/create’ page, in order to create a new post
  • Display a form for creating a post
  • Create and save the new post

Note: To keep this simple, we won’t be using any authentication mechanism. You’ll simply route to a page to create a post, and confirm that we can actually post to a backend API.

Clone the React application starter project

For the purpose of this post, you’ll be starting off with a pre-configured React project (a simple blog tool). The project will be separated into two sections, namely the backend and frontend. While the frontend is the main focus, the backend exists to ensure that we have a connection to the server. The purpose of this is to show you that you can build your application, connect to a server and everything will still function as expected even during test execution with Cypress.

To begin, clone the frontend starter project from GitHub and install all of its dependencies:

git clone https://github.com/klmlfl/cypress-react-demo.git## Change directorycd cypress-react-demo## Install dependenciesyarn install

Once the installation process is complete, start the application with npm run start. This will open the project in your default browser http://localhost:3000.

Next, you’ll need to download the backend project.

Note: You will need mongoDB installed on your machine. Follow the instructions here to install it.

Open another terminal and clone the backend project with:

git clone https://github.com/klmlfl/cypress-react-demo-backend.gitcd cypress-react-demo-backend## Install dependenciesnpm install

Before you start the application, run mongoDB from another terminal withsudo mongodand leave it open. Next, go back to the cypress-react-demo-backend project and start the application:

npm run start

The preceding command will start the backend server on http://localhost:5000. The necessary code to connect with the backend server has already been implemented within the sample project.

You are now fully set up. You can start having fun.

Setting up tests using Cypress

Setting up Cypress for your application is fairly easy. Make sure that you are within the frontend project and run the following command to install Cypress:

## Navigate to the frontend projectcd cypress-react-demo## Install cypressyarn add cypress --save-dev

This will install Cypress locally as a dev dependency for your project. Although Cypress is now installed as a dependency, we need to actually run it. As stated in the official documentation, we could run it directly from the node_modules bin directory using the full path like this

./node_modules/.bin/cypress open

But I think it’s more convenient to add an npm script to run Cypress. To do so, open the package.json file within the cypress-react-demo project and add the following:

"scripts": {..."cypress":"cypress open"},

Save the file. Then, open another terminal within the cypress-react-demo project and run cypress

npm run cypress

Because this is the first time you’re running cypress, it will create its own folder with few sample files.

Navigate to the ./cypress folder to view the files. The sample spec files contains a lot of sample commands to help you get started. But for the sake of learning, go ahead and create a new spec file for this post. To do that, create a new file within ./cypress/integration and name it posts.spec.js. Give it a couple of seconds and you’ll see the new file added to the list of integrations tests.

Writing tests

Next, open the newly created file and let us start writing some tests.

Paste the following code to begin:

describe("A sample mini blog using React", () => {it("Shows a content as a placeholder", () => {cy.visit("http://localhost:3000");cy.get('.post-placeholder').contains('p', 'No post found at the moment')})})

From the code snippet above, the first line simply defines our test suite as “A sample mini blog using React” — feel free to make it descriptive as you deem fit. After that, we describe what we want to do, which is to show content as a placeholder.

The cy.visit() method was used to specify the URL that we want Cypress to visit. Afterwards, we targeted the HTML paragraph element that it is supposed to hold the expected content. This test is expected to fail as we don’t have such content on our page yet. This showcases the beauty of test driven development — you first write code to an expected outcome and then later write the code to actually pass the test.

Running tests

Note: Ensure that the cypress-react-demo is still running.

To run a particular test from the list, all you have to do is to click on it and allow Cypress to do its magic.

This will open your project in a new browser, a visual interface to view the progress of your test.

Obviously, the tests failed. To correct this, navigate to ./src/components/Home.js and update it with the following:

// ./src/components/Home.jsimport React, { Component } from 'react';import axios from 'axios';class Home extends Component {...render() {const posts = this.state.posts;return (<div className="App"><div className="">{/* Add this content */}{posts.length === 0 && (<div><p className={'post-placeholder'}>No post found at the moment</p></div>)}...</div ></div >);}}export default Home;

Save your file and go back to the Cypress interface to run the test again. This time, the test will pass. Test driven development: lovely.

Write more tests

Back in the posts.spec.js file paste the following:

describe("A sample mini blog using React", () => {...it("Clicks and route to Create Post page", () => {cy.contains('Create Post').click()})it("Verify the endpoint", () => {cy.url().should('include', '/create')})})

We have added two more tests:

  • We used the built in assertion method to check if the page contains a text “Create Post” and then clicked on it
  • After being routed to a new page, we checked the URL to be sure that the endpoint is what we were expecting.

Our program has passed all the test so far. One of the neat features of Cypress is that you can actually hover over the commands and you will see a snapshot of when that command ran.

Next, add another test to actually create and save a post:

describe("A sample mini blog using React", () => {...context('Form submission', () => {it("Add a new blog post", () => {const titleText = "Sample title",descriptionText = "This is a very simple description",bodyText = "This is the sample body of the blog post";cy.get('input[name="title"]').type(titleText, { delay: 100 }).should("have.value", titleText)cy.get('input[name="description"]').type(descriptionText, { delay: 100 }).should("have.value", descriptionText)cy.get('input[name="body"]').type(bodyText, { delay: 100 }).should("have.value", bodyText)cy.get('form').submit();cy.location('pathname').should("eq", "/")})})})

What we’ve done here is chained commands together to target an input field using the name attribute and typed some content into it. After that, we used an assertion for the value entered into each input field before actually submitting the form. Finally, we used an assertion for the location being redirected to after form submission.

Conclusion

Testing is crucial to the long-term success of an application, and end-to-end tests help us achieve that by ensuring our application works as expected from the beginning. The more quality tests you have, the better your software will be.

In this tutorial we demonstrated some key aspects of Cypress, however, we only scratched the surface of its complete feature set. I encourage you to check out the official documentation to learn more about it. Hopefully you and your team will consider using it.

If you’re interested in using my demo to try out Cypress, the source code can be found here.

--

--