Cypress: Revolutionizing Automated Web Testing

Shakya Madara Karunathilake
Women in Technology
8 min readApr 15, 2024

Introduction

In software development, testing quickly and accurately is crucial. Cypress has become a favourite tool for developers because it simplifies and speeds up testing for modern web applications. This blog explains why Cypress is so popular and how it stands out from other testing tools.

Why Cypress is Different

Cypress is built differently from most testing tools, which rely on Selenium. Selenium-based tools run commands over a network, which can be slow and unreliable. Cypress, on the other hand, runs right alongside your application in the browser. This means it can run tests faster and more reliably because it doesn’t have to deal with network delays.

Works with Any Website or App

Cypress is very flexible. It works well with any web application, whether it’s built with newer technologies like React, Angular, and Vue or older ones. This makes Cypress a great choice for testing all kinds of web projects.

JavaScript Only

Cypress uses only JavaScript for writing tests. This is simpler because you don’t need to use different programming languages or set up complex systems to run your tests. Since everything runs directly in the browser, it’s also faster and more stable.

All-in-One Tool

Usually, writing tests means combining many tools and libraries, which can be complicated and time-consuming. Cypress makes this easier by combining everything you need into one package. This saves time and lets you focus more on writing your tests than setting up your testing environment.

Faster Testing

The way Cypress is built helps you develop and test your applications faster. You can see your changes in real-time and use browser tools to debug directly. This speeds up your work and helps make sure your final code is well-tested and works smoothly.

Deep Integration for Better Testing

Cypress runs in the same cycle as your app and has a server process in the background. This setup lets Cypress respond immediately to what’s happening in your app and manage tasks that need more control outside the browser. Cypress can also handle network traffic to make sure it tests your app thoroughly.

Local Power

Because Cypress installs directly on your computer, it can do more, like taking screenshots, recording videos, and managing files and networks. This makes Cypress a powerful tool for all kinds of testing tasks.

Tutorial

In this guide, we’ll walk through setting up Cypress to test a React application. We’ll assume you have a basic understanding of React JS.

Step 1: Clone the Repository

Begin by cloning the GitHub repository from here. Let’s review the code:

The App component renders the following elements:

  1. A heading (<h1>) with the text "Cypress Demo" for the application title.
  2. A loop iterates through the todoList. For each todo item, it renders a TodoCard component and passes the corresponding todo object (including details like title and completion status) as a prop (todo). It also assigns a unique key (todo.id) to each card, which is essential for React's efficient rendering process.

This code defines a React component called TodoCard that displays a single todo item. It receives a todo object as a prop, containing details like title, completion status, and an optional note.

The component manages two internal states:

  • checked: Tracks the completion status of the todo (boolean).
  • note: Stores the user-added note for the todo (string).

The component displays the to-do title and a checkbox. Clicking the checkbox updates the checked state.

If the todo is marked complete (checked is true), a note section appears. This section includes a "Note" label and an input field. Typing in the input field updates the note state.

Notice the use of the data-testid attribute. This unique identifier helps Cypress target specific components for testing.

Step 2: Run the Project

To start the project, use the command:

npm run start

After running the project, you should see an interface similar to the image below.

Step 3: Install Cypress

Install Cypress with the following npm command:

npm install cypress

This will add cypress to your project. Let’s go through the cypress folder:

  • Fixtures: Contains mock responses for API calls, useful for testing without hitting the actual API.
  • e2e: The directory where you will write all your end-to-end test cases.
  • Support: Holds reusable code snippets for testing.

Step 4: Launch Cypress

To open the Cypress interface, run:

npx cypress open

A window will appear allowing you to select a browser (e.g., Chrome).

We will be moving forward with Chrome. Once the browser is selected Cypress GUI will then be displayed.

Step 5: Create a New Spec

Click on “Create new spec,” name your spec file, and then click on the “Create spec” button.

A spec file with a sample template will be created in your cypress/e2e folder.

cy.visit("https://example.cypress.io");

This code snippet visits the project that needs to be tested.

For example, in the sample template, you might see Cypress directed to https://example.cypress.io .

Let’s change this URL to www.google.com.

describe('My First Test', () => {
it('Visits Google', () => {
cy.visit('www.google.com')
});
});

You should then be able to see Cypress navigating to Google.

Step 6: Write Your Test Case

You can get the below shown code from the here.

First, let’s add some sample response to the fixtures folder.

{
"todo": [
{ "id": 1, "title": "Wash the dishes", "completed": false, "note": "" },
{
"id": 2,
"title": "Do laundry",
"completed": true,
"note": "Took about 1 hour and 30 minutes"
},
{ "id": 3, "title": "Cook dinner", "completed": false, "note": "" }
]
}
describe("cypress demo", () => {
beforeEach(() => {
cy.visit("http://localhost:3000");
cy.viewport("iphone-5");
});

it("renders the title: ", () => {
cy.get('[data-testid="title"]')
.should("exist")
.should("have.text", "Cypress Demo");
});

it("renders the to dos: ", () => {
cy.fixture("example.json").then((data) => {
data.todo.map(
(todo: {
id: number;
title: string;
completed: boolean;
note: string;
}) => {
cy.get(`[data-testid="span-${todo.id}"]`)
.should("exist")
.should("have.text", todo.title);
if (todo.completed) {
cy.get(`[data-testid="checkbox-${todo.id}"]`)
.should("exist")
.should("be.checked");
cy.get(`[data-testid="note-${todo.id}"]`).should("exist");
cy.get(`[data-testid="note-text-field-${todo.id}"]`)
.should("exist")
.should("have.value", todo.note);
} else {
cy.get(`[data-testid="checkbox-${todo.id}"]`)
.should("exist")
.should("not.be.checked");
cy.get(`[data-testid="note-${todo.id}"]`).should("not.exist");
}
}
);
});
});
});

In this Cypress test script (shown in the image), we begin by setting up a series of tests for a demo application:

1. Initial Setup: Each test starts by navigating to the local development server (`http://localhost:3000`) and setting the browser viewport to mimic an iPhone 5. This ensures that every test is performed under consistent conditions.

2. Testing the Title: The first test checks whether the page correctly renders the title. It searches for an element identified by `data-testid=”title”` and verifies two things:
— The element exists.
— The text within the element matches “Cypress Demo.”

3. Testing To-Dos: The second test involves checking a list of to-do items loaded from a fixture file (`example.json`). For each to-do item in the data:
— It confirms the presence of a span element for the to-do’s title and checks its text.
— Depending on whether the to-do is marked as completed, it checks if:
— The corresponding checkbox is checked and notes are visible for completed tasks.
— The checkbox is not checked and notes are not visible for pending tasks.

If you navigate to the Cypress GUI, you will see this,

As you can see, on the left hand side the status and information regarding the test cases are shown.

Let’s write another test case.

it("updating a todo: ", () => {
cy.fixture("example.json").then((data) => {
data.todo.map(
(todo: {
id: number;
title: string;
completed: boolean;
note: string;
}) => {
cy.get(`[data-testid="checkbox-${todo.id}"]`).should("exist").click();
if (todo.completed) {
cy.get(`[data-testid="note-${todo.id}"]`).should("not.exist");
} else {
cy.get(`[data-testid="note-${todo.id}"]`).should("exist");
cy.get(`[data-testid="note-text-field-${todo.id}"]`)
.should("exist")
.type("Took about 1 hour");
}
}
);
});
});

This test code snippet, titled “updating a todo:”, demonstrates how to interact with and verify changes to todo items using Cypress:

1. Load Data: The test begins by loading todo items from a file called `example.json`.
2. Iterate and Interact: For each todo item:
Check and Click: It ensures the checkbox exists for each todo (`data-testid=”checkbox-${todo.id}”`) and then clicks it, simulating a user changing the completion status.
— Conditional Checks: Depending on whether the todo was initially completed:
— If yes, it verifies that the note associated with that todo should no longer be visible.
— If no, it confirms the note is visible and types “Took about 1 hour” into the note field, simulating a user adding information about the task.

This script effectively checks that the application responds correctly to user interactions.

Running Cypress Tests Headlessly

For many development teams, especially those integrating continuous integration pipelines, running tests without the GUI (headlessly) is crucial for speeding up the deployment process. Cypress caters to this need with a straightforward command that allows you to execute your tests in headless mode.

To run your Cypress tests headlessly, use the following command in your terminal:

npx cypress run --headless

This command executes all the test suites without opening the graphical user interface, making it ideal for automated environments or instances where a visual interface is unnecessary. This method not only saves time but also system resources, enabling faster feedback loops during development phases.

Conclusion

Cypress doesn’t just make testing easier; it transforms how testing is done. By integrating all aspects of testing and allowing you to test in real time with your app, Cypress ensures your web applications are not only functional but also robust and error-free.

The research and content for this blog were provided by me, but the text was authored by ChatGPT and Gemini AI.

--

--