Type to generate custom UI components with AI

Type to generate UI components from text

OR

Browse thousands of MUI, Tailwind, React components that are fully customizable and responsive.

Explore Components

How to Set Up Your First Cypress E2E Test Suite

Software testing is an important aspect of software development. It is part of the software development life cycle(SDLC). Would you want to build an application that everyone wants to use, has great performance, high quality, and does not malfunction or behave unintendedly?

Then follow along as I introduce you to how to achieve this by thoroughly testing (end-to-end test) your application with Cypress. End to end testing, more specifically deals with testing the user flows, that are based on how the users interact with the application, and hence is crucial in the testing process.

This article will help you:

  • Understand what (end-to-end) E2E testing is and why it is important for testing your React app

  • Learn how Cypress enables effective E2E testing for React

  • See examples of basic and advanced E2E tests written in Cypress

  • Clone a sample project to practice writing E2E tests yourself

  • Discover how to create custom commands in Cypress to simplify test writing

  • Gain hands-on experience in setting up and running E2E tests with Cypress

Cypress logo

By the end, you will be prepared to start adding E2E testing to your own React projects right away! If you are excited as I am writing about this article, let’s dive right in ๐Ÿš€

Just before diving, I want to introduce you to our Purecode AI tool. PureCode is an AI-powered platform that’s built by developers for developers. It improves your workflow by allowing you to choose from over 10k AI-generated components.

Purecode AI

What is Software Testing

Software testing is the process of evaluating your software product’s quality, functionality, and performance before it is launched. Testers can use a variety of methods to perform software testing, including:

  • Manually interacting with the software

  • Executing test scripts:

  • Writing software as small functional units

  • Writing a unit test for each code unit

Benefits of Software Testing

Software testing is an integral part of software development. It helps ensure code quality and can help build customer confidence and improve your user experience.

There are many benefits of thorough software testing:

  • Improves consistency by reducing variation in the software’s behavior across different user scenarios. This results in more predictable software operations.

  • Improves performance by catching efficiency issues, memory leaks, and other bottlenecks early in the development cycle of your application. Timely discovery of these issues is critical and fixing these improves the overall speed and stability.

  • Helps teams understand expected outcomes for each user story or requirement. Comparing these to actual testing outcomes highlights where expectations are not being met.

  • Reduces the risk of failure by catching a high percentage of defects before software reaches end-users. Finding issues earlier is exponentially cheaper than finding them in production.

  • Helps developers deliver high-quality software by validating that requirements are met consistently across user workflows.

  • Helps ensure that software conforms to specifications and requirements outlined in the planning stages. Deviations can be identified early.

  • Helps ensure that software meets business and user needs and delivers the expected value.

What is End-to-End Testing

End-to-end (E2E) testing is a software testing technique that verifies the functionality of an entire application from start to finish. It is a methodology used in the software development lifecycle (SDLC) that checks the entire application. It uses a test environment and data to simulate real-world functionality. However, it is the most expensive to maintain and has the slowest operating pace.

E2E testing verifies that all components of a system can run under real-world scenarios. It involves all the systems, components, and integrations involved in the application’s workflow.

Example of E2E Testing

An example of E2E testing is verifying that the entire purchasing process functions as expected. For example, a customer purchases a product from a website, pays for it, and receives a confirmation email.

If you want to fully grasp the nitty-gritty of E2E testing with Cypress, I encourage you to check out this complete beginner-friendly course on YouTube on End-to-End Testing with Cypress

Why is End-to-End Testing Necessary?

While unit testing is essential for verifying the functionality of individual modules and components, it has some limitations when testing complex systems. Unit tests are isolated from each other and test modules in an idealized environment. However, in the real world, various modules need to work together seamlessly. This is where integration testing and end-to-end testing become necessary.

Integration testing verifies that different modules and services in an application interact correctly when combined. But even with comprehensive integration testing, some issues may slip through. End-to-end (E2E) testing replicates real user workflows from start to finish. It provides confidence that the entire integrated system meets requirements when deployed to production environments.

E2E testing catches issues that unit and integration testing may miss. For example, E2E tests may reveal workflows with inconsistent user experiences, compatibility issues across browsers or devices, SQL injection vulnerabilities, and various real-world performance problems. E2E testing is the final check to ensure the software works as expected before releasing it to end-users.

Cypress is a test automation framework purpose-built for E2E testing. It allows you to write and run E2E tests that run directly inside the real browser. Cypress is fast, reliable, and provides excellent debugging capabilities. Using Cypress for E2E testing helps ensure thorough testing of critical user workflows in your application.

Understanding the Testing Pyramid

The test automation pyramid is a concept pioneered by Mike Cohn that serves as a guide for teams on how to balance different types of tests. The pyramid has three layers – unit tests, integration tests, and end-to-end tests.

The Testing Pyramid: Simplified

Image credit – HeadSpin

  1. At the bottom layer of the pyramid are unit tests. Unit tests exercise individual classes, functions, or modules in complete isolation. A well-tested codebase will have more unit tests than any other kind of test. Unit tests build confidence in the stability of individual components.

  2. The middle layer represents integration tests. Integration tests verify that different modules or services work in conjunction with each other correctly. They test integrations between components and catch issues that unit tests would miss.

  3. At the top of the pyramid are end-to-end (E2E) tests. E2E tests replicate real user workflows against the completed system. They catch hard-to-find bugs and ensure the entire integrated system meets requirements.

Each layer of the pyramid builds on the previous layer and provides unique value. Unit tests enable safe refactoring of code. Integration tests catch component interaction bugs. E2E tests provide overall confidence in the system.

The pyramid recommends having far more lower-level unit tests, fewer integration tests, and still fewer higher-level E2E tests. This proportional mix ensures comprehensive testing coverage at an optimized cost.

Here is a sample text based on the provided headings:

Frameworks for End-to-End Testing

There are several popular open-source frameworks available for automating end-to-end testing:

  • Cypress is a JavaScript-based framework built specifically for E2E testing. It runs tests inside the browser and provides a great debugging experience.

    According to GitHub, Cypress has 45.7k stars, and 3.1k forks, and is used by 1.2m repositories as of February 2024.

  • WebdriverIO (WDIO) is an open-source test automation framework for Node.js that provides a high-level API for automating web applications across multiple browsers, such as Chrome, Firefox, Internet Explorer, and Safari. Its main objective is to make online automation testing easier to use, even for developers with little prior browser automation experience, avoiding harder and slower manual testing. WebdriverIO has 8.5k stars, 2.4k forks, and 56.7k usage as of February 2024.

    Check out my previous article on End-To-End Testing: Unleash The Power Of WebDriverIO to learn how to carry out E2E tests with WDIO.

  • Nightwatch.js is a Node.js framework that provides an easy API for writing E2E tests and interacting with browsers. It includes built-in assertions. Nightwatch.js has 11.5k stars and 1.2k forks as of February 2024.

  • Protractor: Protractor is an open-source testing framework that can be used to perform end-to-end testing on Angular apps. It is an automation testing tool that combines technologies like Jasmine, Selenium Webdriver, and Node.js. Protractor focuses specifically on E2E testing for Angular applications. It is built on WebDriverJS and uses Jasmine syntax. Protractor has 8.8k stars and 2.4k forks as of February 2024.

  • TestCafe is a framework that allows testing without using browser plugins. It has a simple API and runs on Node.js. TestCafe has 9.7k stars and 699 forks as of February 2024.

Cypress for E2E Testing

Cypress works with all modern JavaScript frameworks. It is one of the most popular E2E testing frameworks due to its many benefits:

  • Easy Setup: Can get started just by installing the npm module

  • Automatic Waiting: Waits for elements before acting on them

  • Real-time Reloads: Tests reload instantly as code changes

  • Interactive Debugging: Pause, step through, and inspect tests easily

  • Time Travel: Go back or forward in time within tests

  • Cross-browser Testing: Supports testing in multiple browsers

  • Network Traffic Control: Stub and mock network requests

  • Automatic Screenshots and Videos: Of test runs for debugging

These features make Cypress E2E test extremely developer-friendly and optimal for E2E testing.

Tabular Comparison of Some Testing Frameworks

FrameworkLanguageSetupLearning CurveDebuggingCI Integration
CypressJavaScriptSimple npm installLowBuilt-in interactive debuggerSeamless
SeleniumJava, Python, C#, etcRequires WebDriver setupHighExternal tools neededRequires configuration
TestCafeJavaScriptnpm installModerateScreenshots and videosStraightforward
Nightwatch.jsJavaScriptnpm installLowExternal tools neededDirect support
ProtractorJavaScriptnpm installModerateScreenshots and logsNeeds configuration

The above table is summarized with these key points:

  • Cypress has the simplest setup with just an npm install needed to get started. Other JS frameworks like TestCafe and Nightwatch.js also have easy npm-based setups.

  • Cypress has a very low learning curve compared to Selenium which requires knowledge of multiple languages and frameworks.

  • Cypress and TestCafe have great built-in debugging capabilities, while others need external tools.

  • CI integration tends to be more seamless with JavaScript-based frameworks like Cypress. Selenium requires more configuration.

  • Cypress stands out with its easy and quick setup, debugging features, and CI support.

Set up Cypress for End-to-End Testing

First, you will start with the installation of Cypress. This section will walk you through installing Cypress in your project.

Start by cloning this repository on GitHub. This is what our application looks like when you run the application:

Sample applcation

After cloning it, install the necessary dependencies and start the application by running:

npm i -f && npm start

Installing Cypress

First, let us start by installing Cypress. Run the following command in the terminal:

npm install --save-dev cypress

Running this command will install Cypress and save it as a developer dependency in our project. The next step is to create a configuration file called cypress.config.js at the root of the project. This file is used to customize Cypress settings and will contain information like the base URL of the application under test.

Within this file, we need to add code that specifies configuration options like:

const { defineConfig } = require('cypress')
module.exports = defineConfig({})

To launch Cypress, we need to add a command in the “scripts” section of our package.json file. Specifically, we’ll include the following line that will run Cypress when executed:

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

To launch the Cypress test runner, we can now execute the command:

npm run cypress
cypress open

This should launch Cypress on your browser (head mode) like so:

Cypress launch

At this point, we will select the E2E testing option since that is the focus of this tutorial. Cypress will then display its Test Runner interface and show us the various files and folders it will generate in our project.

Cypress Test Runner interface

After clicking Continue, Cypress will prompt us to select a browser to use for testing. In my case, Chrome is set as the default browser, so I will choose that option.

Cypress browser

Clicking “Start E2E Testing in Chrome” will open a window displaying our spec files. In Cypress, a spec file contains one or more test cases. Cypress utilizes the Mocha testing framework, so spec files typically have multiple describe and it blocks.

The describe blocks group related tests together and describe their purpose. The it blocks define each test case, using Cypress commands like cy.visit(), cy.get(), and cy.click() to interact with the application under test. Assertion methods like should() are used to make assertions about the application’s state.

How to Write Your Tests with Cypress

Now that we have Cypress installed and configured, let’s look at how to create some basic tests. When the Cypress test runner launches, it will display the spec files that contain our tests.

Start E2E Testing in Chrome with Cypress

We currently do not have any specs, so letโ€™s create one. Click on Create new spec, and weโ€™ll be prompted to enter the path to our specs.

Create new Cypress spec

Cypress Folder Structure

The Cypress test development folder structure typically includes these core folders:

  • cypress – The main folder containing the installed Cypress files

  • fixtures – Houses data files used in tests

  • integration – Contains test files organized by feature or page under test

  • support – Has Cypress commands and helper files

It is recommended to keep the Cypress folder at the root level for easy access when running and debugging tests.

Folder Example

For this example, we will name our new test spec should_show_terms.cy.js. This test will check if the terms and conditions banner is displayed.

If you run the app, you will notice that the terms and conditions banner is displayed and only hidden when we accept the terms and conditions of the app. So, I will be writing my test to verify that the terms and conditions banner is actually displayed.

Clicking “Okay, run the spec” will execute the test and display the results:

describe("template spec", () => {
  it("passes", () => {
    cy.visit("https://example.cypress.io");
  });
});

This test visits the Cypress example URL, as we can see in our test runner.

We will modify the spec to carry out our own test:

In the should_show_terms.cy.js file, we will write our tests. For example, we can test that the terms and conditions banner is displayed in the application when the page loads:

/* eslint-disable no-undef */

describe("Yellow GirlFriend App", () => {
  it("display the terms and conditions banner when the page loads", () => {
    cy.visit("/");
    cy.get('[data-testid="accept-terms"]').should("be.visible");
  });
});

NOTE ๐Ÿ“

data-testid is an attribute that can be added to HTML elements in order to make them more easily selectable in Cypress tests. This attribute is not used by the application itself but rather is used solely for the purpose of testing.

Data-testid Attribute

Cypress can use an element’s data-testid attribute to uniquely identify and select it during testing. This is helpful when an element lacks a unique class or id, or when those attributes may change. Knowing this, we can add a data-testid=”accept-terms” to the h2 tag for quotes in App.js:

By adding this attribute, Cypress tests can now consistently locate the quote element using cy.get(‘[data-testid=”accept-terms”]’) without worrying about changing class or id values.

<h2 data-testid="accept-terms">This website or its third-party tools use cookies, which are necessary for its functioning and required to achieve the purposes illustrated in the cookie policy. You accept the use of cookies by closing or dismissing this notice, by scrolling this page, by clicking a link or button, or by continuing to browse otherwise.</h2>

When we save and run this spec, there is an error because the front-end route is incorrect. We can fix this by setting a base URL in cypress.config.js. Adding a line to specify the base URL will resolve the issue:

Your cypress.config.js file should then look like this:

const { defineConfig } = require("cypress");

module.exports = defineConfig({
  e2e: {
    baseUrl: "<http://localhost:3000>", //line here
    setupNodeEvents(on, config) {
      // implement node event listeners here
    },
  },
});

Now, if we save the should_show_terms.cy.js file, we see all our tests running in the test runner:

Running the app

The hosted application can be found here: https://yellow-girlfriend.netlify.app/

One important tip to avoid flaky tests is to never use fixed wait times like cy.wait(500). Specifying fixed durations can lead to brittle tests that pass or fail inconsistently.

Instead of hard coding wait times, leverage Cypress’s intelligent built-in waiting and assertions. These will automatically retry and wait for elements and conditions to be met before proceeding. Relying on Cypress’s retry logic creates reliable tests that account for timing variances and network delays.

FAQs

What Is E2E Testing In Cypress?

E2E (end-to-end) testing in Cypress refers to testing the entire workflow of an application from start to finish.

Is Cypress Used For E2E Or Integration Testing?

Cypress is primarily used for E2E testing. It can also do integration testing.

What Is The Difference Between Component And E2e Testing In Cypress?

Component tests target isolated parts of an app. E2E tests target the app from end to end like a real user.

Is Cypress Good For E2e Testing Compared To Selenium?

Yes, Cypress is often superior to Selenium for E2E testing due to its speed, reliability, debugging capabilities, and running directly inside the browser.

How Do I Run E2e Tests In Cypress?

E2E tests in Cypress can be run headlessly with cypress run or interactively with cypress open.

What Types Of Testing Can Cypress Do?

Cypress specializes in E2E testing but can also do unit, integration, and component testing.

Why Is Cypress Better Than Selenium?

Cypress is faster, easier to use, has better debugging, runs in the browser natively, and doesn’t require drivers like Selenium.

How Easy Is It To Write Tests In Cypress?

Cypress has a simple and intuitive syntax. The interactive debugger makes test creation and debugging very easy.

What Is The Recommended Way To Run Tests In Cypress?

Use cypress open to run tests in the interactive runner. Use cypress run to run headlessly.

How Do I Set Up Cypress In My Project?

Run npm install cypress –save-dev to install it locally. Cypress will generate a default folder structure.

Where Do I Put My Test Files?

The E2E test files belong in the /integration folder and are named .spec.js.

What You Have Learned

In light of this, visit Purecode AI to explore our library of UI components. Our library includes components that can be integrated into web applications built using Bootstrap, Tailwind CSS, and Material UI.

Get Started With PureCode AI today ๐Ÿš€

Further Readings and Resources

End to End testing helps us to test the entire application, both at the API and UI layers, from start to finish. Using automated UI testing and manual testing practices aids in maximizing test coverage. In other words, based on the commands and the events happening, Cypress automatically alters its expected timeouts to match web application behavior. These various timeouts are defined in the Configuration document.

If you enjoyed reading this piece, be sure to check out other great articles from our blog and others:

  • Check out this YouTube tutorial video on Cypress End to End(E2E) Testing:

Emmanuel Uchenna

Emmanuel Uchenna

Emmanuel is an experienced and enthusiastic software developer and technical writer with 4+ proven years of professional experience. He focuses on full-stack web development. He is fluent in React, TypeScript, VueJS, and NodeJS and familiar with industry-standard technologies such as version control, headless CMS, and JAMstack. He is passionate about knowledge sharing.