By clicking “Accept All Cookies”, you agree to the storing of cookies on your device to enhance site navigation, analyze site usage, and assist in our marketing efforts. View our Privacy Policy for more information.

Integration testing with Cypress

Sebastián Guzman
June 16, 2023

Introduction

Integration testing is the process of testing a group of modules as a whole, verifying that they work together as expected. In our field, the "modules" being tested in conjunction can be REST APIs, frontends, mobile apps, etc. In this case we are going to refer to testing apps as a user would do - including a UI/frontend and a backend. These kinds of tests are also called "interaction" tests.

There are many tools that can help us accomplish this objective and one of the most well known ones is Cypress. Cypress basically emulates a browser and executes anything that a user would be able to do, but in an automated way. It allows us to write E2E, Component, Integration and Unit tests and if integrated with a CI provider, Cypress Cloud can also record your test runs for further analysis.

Integrating Cypress into an existing project

If we already have a project and we want to start writing an integration test for it, the first thing we have to do is to include Cypress as a part of its (development) dependencies. We can do that just by running

BASH

or

Once you got the cypress application installed, it can be run from the root of your project with one of the following commands:


This will open the Cypress Launchpad

Another alternative, and also a good practice, is to add this command as a script inside our package.json file:

Now we can invoke this command from the root of our project using npm and accomplish the same result:

In this case we are going to write our first E2E test, where our whole application will be running and we will test that it behaves as intended. 

After selecting the E2E testing option, another screen will be displayed with the basic configuration files added by Cypress to run properly, for the moment leave them as they are and continue. Cypress will prompt you to choose one of the compatible browsers found in your system:

In our case we’ll choose Chrome and then click the “Start E2E Testing in Chrome” button to create our first test. The following screen will appear:

Select “Create new empty spec”, then click the “Create Spec” button, and in the following screen click the “Okay, run the spec” button to give it a try.

The new default test will be displayed and will click the “Okay, run the spec” button to give it a try.

In this opportunity we are going to test a register form, to do so, inside your preferred text editor let's open up the newly created test file “cypress/e2e/spec.cyjs” and start modifying it to fulfill our intended test case.

As we can see the test is made of three main enclosures:

  • describe: This block is used basically to group our test cases inside one group. For example if we have several Login scenarios that we want to try we can define a “describe(‘Login’, () => { })” block and nest inside all the individual login cases that we want
  • it: This block is used to define an individual test case, following the login test group idea, we can define for example “it(‘Successful login’, () => {})” to represent a test case where the login process should pass.
  • test body: This block of code contains all the needed steps and instructions that represent the steps that our user takes inside our application to fulfill the desired objective.

Now that we have an idea of how to structure our tests let’s take a look at our applications' home page and start building our first custom Cypress E2E test.

[ For this example, to work properly, remember to have the backend and frontend modules of our project running, otherwise the tests will fail ]

As this is a registered user which accesses only to application, the first thing a user should do in order to access, will be to register itself. So let’s start automating that case.

First to make our test definition more pristine, let's modify the description and the block’s first params and replace them with “Register new user” and “success registration”. Also replace the cy.visit(‘https://example.cypress.io’) with the url where the frontend instance of our application is running. In this case I will use ‘localhost:5173/’.

Now our test should look something like this:

If we save the changes made to the file until now, the only difference will be that the test now navigates to the home page of our application, but doesn’t perform any action or assertion afterwards. 

Let’s define  the following minimum steps that we have to perform, as a user, in order to get registered:

  1. locate the register button and click it
  2. confirm that we get redirected to the register page
  3. locate the register form inputs and fill them with the user information
  4. submit the registration form and assert the registration confirmation response from the API

With these steps in mind let's add the following instructions to our test for steps 1 and 2:

After saving the changes, the test will reload and relaunch itself introducing the new modifications:

cy.get(‘#register-btn’).click() will look up for a html element with an id matching ‘register-btn’ and then perform a click action with the chained command ‘.click()’;

cy.url().should(‘contain’, ‘/register’) will retrieve the current page url and then check that it contains the string ‘/register’ into it.

If no element with id ‘register-btn’ exists or the button redirects the user to a page that’s not under the /register routes, the test will fail.

Now that the user has successfully loaded the register page, let's fill out the form and  perform the registration. To do that let’s add the following lines to our file:

We have added some new commands now: 

  • The “.within(() => { .. })” command will narrow the scope of the nested instructions to be performed only inside the element it’s chined on. In this case it will limit the search for the inputs and submit button to the form element.
  • cy.type() will attempt to type the text received as a param to the element it’s chained from. In this case it will be filling in the inputs with the needed values.
  • cy.intercept() is used to listen for requests matching the method and url given, and can also be aliased with ‘.as(alias)’, enabling us to await for that request to be fulfilled, using the ‘.wait(@alias)’ command, before continuing with the rest of the tests.
  • And with the chained commands .its('response.statusCode').should('eq', 200) we verify that the response received has a Status code of 200 ( OK )

If we save the changes and run the test again. we could see how the user is now redirected to the Registration form, fills in all the required fields and submits the form. Finally it awaits for the API response before ending the test.

Summary

As we showed in this step-by-step guide, with the help of Cypress we can automate a desired user flow and its interactions: clicking elements, asserting redirections, fulfilling inputs with values, submitting forms and waiting for the API to respond before moving on. 

These were just a subset of the commands that can be used to set our use cases and perform an integration E2E test. At Ensolvers, we use Cypress and other frameworks as well to define automated tests that are daily run via CI pipelines with the aim of ensuring early bug detection and constant quality assurance of the software being built.

Interested in our services?
Please book a call now.