This tutorial helps getting started with React end to end testing using popular tools like Cypress and Jest.
OVERVIEW
Your application will fail if you only perform unit testing.
The statement above holds when your team relies only on unit testing and ignores the importance of end-to-end testing in software applications.
In frontend engineering, end-to-end testing is vital as it simulates the user's action and discovers errors, bugs, and defects even before your real users use the application.
In this React end to end testing tutorial, we will explore how to get started with React end to end testing using popular tools like Cypress and Jest. We will also elucidate the best practices and industry-standard principles in writing and executing enterprise-level and scalable end-to-end testing for React applications.
React is one of the most popular JavaScript libraries for building complex and dynamic web applications. As your application grows in size and complexity, testing becomes an essential part of the development process. End-to-end testing is a valuable way to ensure that your application works as intended from the user's perspective.
End-to-end (E2E) testing is a type of software testing that ensures the application behaves as expected from the user's perspective. It involves testing the entire software stack from the front end to the back end, including all the external systems and integrations. E2E testing can help identify broken links, missing elements, and incorrect functionality.
As a software engineer, it is important to understand the various testing approaches and when to use them. One testing approach that is becoming increasingly popular in the software development industry is end-to-end testing. Below are some reasons why end-to-end testing is essential for ensuring software quality.
One of the primary benefits of end-to-end testing is that it helps detect integration issues. When multiple components of an application or system are developed separately, there is a risk of integration problems when they are brought together. End-to-end testing helps identify these issues before they reach production, reducing the risk of application failure.
End-to-end testing also mimics real user scenarios, providing a more accurate representation of how the application or system will function in the real world. It tests the entire system, including the user interface, backend processes, and third-party integrations, ensuring that all components work together seamlessly.
By testing the entire system, end-to-end testing helps ensure user satisfaction. It identifies any issues that may cause frustration or dissatisfaction among users, such as slow response times or incorrect data display. By detecting these issues early, developers can make necessary changes to improve user experience.
End-to-end testing enhances software quality by ensuring that all components of the application or system work together as intended. It identifies issues that may be missed by other testing approaches, such as unit testing, and helps ensure that the final product is of high quality.
End-to-end testing reduces the risk of bugs in production by identifying issues before they reach the end user. This helps reduce the cost and effort required to fix issues post-release, minimizing user impact.
In addition, end-to-end testing is an essential approach for ensuring software quality. By incorporating end-to-end testing into the testing process, software development teams can improve the overall quality of the final product and ensure a positive user experience.
It's essential to ensure that the code we produce is of the highest quality and is free from any bugs or issues. To achieve this, we need to have a robust testing strategy, including testing our React components thoroughly. React testing is necessary for the following reasons:
Note: You can learn more about it through this React testing tutorial.
React testing ensures that the components we develop to function as intended. By testing each component thoroughly, we can ensure that all features and functionality are working correctly.
Testing helps us prevent bugs and errors from occurring in our code. We can catch issues early in the development process, which helps reduce the time and effort required to fix them later on.
By testing our code, we can ensure that it meets the required quality standards. This includes ensuring that it is maintainable, scalable, and follows industry best practices.
Testing can help us enhance the user experience by ensuring that the components are easy to use, intuitive, and provide a seamless experience for the end-users.
Testing can help us with code refactoring. We can modify code confidently, knowing that we have tests to ensure we haven't broken anything.
As a software engineer, when testing a React application, it's essential to consider what to test to ensure the code is robust and reliable. Here are the critical components to consider when testing a React application:
Testing component rendering and functionality are essential to ensure that the application's user interface (UI) is working correctly. This testing ensures that the components render as expected and the user interactions function correctly.
Testing user interaction and behavior is crucial for ensuring the application responds to user input as expected. Testing user interactions involves simulating user input and verifying that the application responds as intended. It is essential to ensure that the user's interaction with the application is smooth and without any issues.
Testing state management is essential to ensure that the application's state is being managed correctly. Testing the application state involves verifying the application updates the state as expected and that the user interface updates accordingly. Libraries like Redux and MobX can be used to manage the application state and test it.
Testing network requests is essential to ensure the application communicates with the server as expected. Testing network requests involves simulating network requests and verifying that the application sends and receives data correctly. Libraries like Axios and Mock Service Worker can be used to test network requests.
Testing integration involves verifying that different components of the application work together seamlessly. This testing ensures that the application is functioning as intended and that all components are interacting correctly. Integration testing can be done using libraries like Cypress and Enzyme.
Furthermore, by testing all of these components, we can ensure that the application is robust, reliable, and provides an excellent user experience.
Note : Perform React end to end testing across 3000+ browsers and operating systems. Try LambdaTest Now!
Performing React end to end testing requires different software and tools such as Cypress, Playwright, TestCafe, etc.
Performing React end to end testing requires different software and tools such as Cypress, Playwright, TestCafe, etc.
However, these tools are already developed and tested for efficiency and effectiveness when it comes to E2E testing large and enterprise-ready applications, so there's no need to reinvent the wheel.
Below are some of the categories of tools needed to aid your React testing.
To perform React end to end testing, you need to use a mocking library to aid in focusing only on testing the most important thing while mocking or using fake data for the less important aspect of the component. Mocking libraries can also help accelerate the speed of your application by introducing mocked data instead of simulating real user action, which may result in slow testing.
A test runner is a software that helps run and execute your React end to end test suits. You can run your test suites by selecting individual tests or groups of test cases. The test runner library generates reports after running the test to indicate the success or failure state of the test.
When performing any software testing, it is required to test the outcome of a conducted test, such as checking if the button is clickable when a page is loading or if the length of a square is equal to the breadth. This is where assertion libraries come to play.
Below are the top three React end to end testing tools based on their popularity, usage, and GitHub statistics:
In short, Cypress, Jest, and Puppeteer are three of the most popular React end to end testing tools based on their popularity, usage, and GitHub stats. Developers can choose any of these frameworks depending on their needs and preferences.
We will create a simple React Task Tracker project for this demo. This React project allows users to add tasks, mark them as done, and delete tasks.
Follow these steps to create a new React project:
npm create vite@latest react-task-tracker -- --template react
cd react-task-tracker
code .
npm install
npm run start
import { useState } from "react";
import AddTask from "./components/AddTask";
import Header from "./components/Header";
import Tasks from "./components/Tasks";
function App() {
const [tasks, setTasks] = useState([
{
id: 1,
text: "Doctors Appointment",
day: "Feb 5th at 2:30pm",
reminder: true,
},
{
id: 2,
text: "Meeting at school",
day: "Feb 5th at 1:30pm",
reminder: true,
},
{
id: 3,
text: "Food Shopping",
day: "Feb 5th at 2:30pm",
reminder: false,
},
]);
const [showAddTask, setShowAddTask] = useState(false);
// Delete a task
const deleteTask = (id) => {
setTasks(tasks.filter((task) => task.id !== id));
};
// Add task
const addTask = (task) => {
const id = Math.floor(Math.random() * 10000) + 1;
setTasks([...tasks, { ...task, id }]);
};
// Toggle reminder
const toggleReminder = (id) => {
setTasks(
tasks.map((task) =>
task.id === id ? { ...task, reminder: !task.reminder } : task
)
);
};
return (
<div className="container">
<Header onShowAddTask={() => setShowAddTask(!showAddTask)} />
{showAddTask && <AddTask onAddTask={addTask} />}
{tasks.length > 0 ? (
<Tasks tasks={tasks} onDelete={deleteTask} onToggle={toggleReminder} />
) : (
"No tasks found"
)}
</div>
);
}
export default App;
Code Walkthrough
Let's walk through the nitty-gritty of this code snippet.
Step 1 – Importing and initializing React.
In this step, we imported all the required packages and initialized the tasks array for default tasks to be displayed.
We created a Tasks array and showAddTask boolean using React useState to store all our tasks and toggle between Add task windows.
Step 2 – Creating the delete task functionality.
We created the delete task functionality that takes the ID of a particular task and filters through the array to remove it.
Step 3 – Creating the add task functionality.
We created the add task functionality that takes a task object and pushes it to the array of tasks created above.
Step 4 – Creating the marked functionality.
This is the marked functionality that marks a task as completed or not completed when the "set reminder" checkbox is toggled.
Step 5 – Rendering the components.
This code snippet renders all the components that use all the functionalities discussed above:
In addition, each of the components in the code snippet above can be found inside the GitHub repository for this project, which you can clone directly from here:
If everything is properly set up, you should be presented with a demo react task tracker application as shown below:
Cypress is a JavaScript testing framework that allows you to write end-to-end tests that run in the browser.
To set up Cypress, you need to install it using npm, a package manager for Node.js. Open a terminal window and run the following command:
npm install cypress --save-dev
Once you have successfully installed Cypress, use this command to open and configure it.
npx cypress open
You can follow the instructions from the Cypress official website and select E2E testing for this project. Next, create a new folder called tests/e2e inside the test src folder.
Lastly, open the newly created cypress.config.js configuration file in the root directory and replace it with the following code snippet.
const { defineConfig } = require("cypress");
module.exports = defineConfig({
component: {},
env: {
// HINT: here we read these keys from .env file, feel free to remove the items that you don't need
baseUrl: process.env.FE_URL ?? "http://localhost:3000",
},
e2e: {
supportFolder: false,
supportFile: false,
specPattern: "src/tests/e2e/**/*.spec.js",
// eslint-disable-next-line no-unused-vars
setupNodeEvents(on, config) {
// implement node event listeners here
},
baseUrl: process.env.FE_URL ?? "http://localhost:3000",
},
});
The most important configuration here is setting the default location for Cypress to locate the E2E test files using specPattern and the baseURL to run the test.
Next, create a new file inside the src/tests/e2e folder called tasks.spec.js and paste in the following test codes:
/* eslint-disable jest/valid-expect */
/* eslint-disable testing-library/await-async-utils */
/* eslint-disable no-undef */
const afterLoginFunction = () => {
cy.visit('${Cypress.env("baseUrl")}');
};
describe("Tasks tests", () => {
beforeEach(() => {
afterLoginFunction();
cy.wait(5000);
});
// Add task
it("can add a new task", () => {
cy.get("header .btn").click();
cy.wait(1000);
cy.get('.add-form input[placeholder="Add Task"]').type("Cypress Task 1");
cy.get('.add-form input[placeholder="Add Day & Time"]').type(
"March 18 at 4:00pm"
);
cy.get(".add-form").then(() => {
cy.get('.add-form input[type="submit"]').click();
cy.wait(1000);
cy.get(".task h3").each(($el) => {
return cy.contains("Cypress Task 1");
});
});
});
// Delete task
it("can delete a task", () => {
cy.get(".task h3").then(() => {
cy.get(".task h3 svg").first().click();
cy.wait(1000);
cy.get(".task")
.each(($el) => {
return $el;
})
.then(($el) => expect($el).to.have.length(2));
});
});
// Mark task
it("can mark a task", () => {
cy.get(".task:first ").then(() => {
cy.get(".task").last().dblclick();
cy.wait(1000);
cy.get(".reminder")
.each(($el) => {
return $el;
})
.then(($el) => expect($el).to.have.length(3));
});
});
});
Code Walkthrough
Let's walk through the nitty-gritty of this task file.
Step 1 – Visiting the URL.
In this step, we ask Cypress to visit the base URL and set everything up for testing the user's action on the page.
Step 2 – Testing the Add Task action.
Next, we test out the Add Task functionality of our application since it is crucial and a way for users to create new tasks they want to perform.
The code snippet above uses Cypress get function from the global cy object to retrieve page elements based on the queries provided. For instance, we ask Cypress to locate a button inside the header element with a class of button and click it.
Using the get function in combination with other Cypress functions, we can retrieve and perform actions on any HTML element just as your users would.
Step 3 – Testing the Delete Task action.
Next, we test out the Delete Task functionality of our application to see if we can delete tasks from the list of available tasks.
Step 4 – Testing the Marked Task action.
Next, we test out the Marked Task functionality of our application to see if we can mark tasks as completed or not.
Finally, we have everything set up and all our test cases written. Let's run the test to make sure everything is passing as expected.
To run your test, open your package.json file and add the following code to the scripts section:
"test:e2e": "cypress open --e2e",
"test:e2e:ci": "cypress run --e2e",
The first line opens a new Cypress window and asks you to choose a browser to run your test, choose Electron and watch your test case running one after the other.
However, if you want to run the test with the terminal or using any automated pipeline like LambdaTest, use the second line, which will run your test using the CLI.
LambdaTest is a digital experience testing platform that lets you perform automation testing with popular testing frameworks, including Cypress and Jest, on an online browser farm of 3,000+ different browsers and operating systems.
Subscribe to the LambdaTest YouTube Channel and stay updated with the latest tutorial around Selenium testing, Cypress testing, and more.
Now enter the following command in your terminal to run your test:
npm run test:e2e
If everything works as intended, you should be greeted with a successful test, as shown in the short video.
If your test cases are not passing, you can revisit your code or check the repository for the correct code base.
This React end to end testing tutorial provides a detailed guide to beginners on how to get started with React end to end testing using popular testing frameworks such as Cypress and Jest. The guide is demonstrated with a simple Task Tracker app example, and the blog provides detailed code snippets for building and testing the app.
Reviewer's Profile
Himanshu Sheth
Himanshu Sheth is a seasoned technologist and blogger with more than 15+ years of diverse working experience. He currently works as the 'Lead Developer Evangelist' and 'Director, Technical Content Marketing' at LambdaTest. He is very active with the startup community in Bengaluru (and down South) and loves interacting with passionate founders on his personal blog (which he has been maintaining since last 15+ years).
Get 100 minutes of automation test minutes FREE!!