Skip to main content

Tutorial Videos

Best Practices

This video by the creator of Cypress Brian Mann shows what we consider the best practices for writing tests for a realistic application.

First we'll test our "Login Page", refactor, and then create a Custom Command. From there we'll use cy.request() to programmatically log in. Finally, we'll discuss approaches for taking shortcuts by controlling your application's state directly, and for writing your tests in isolation to prevent specs from being coupled together or having to share knowledge.

TutorialLengthRelease dateCypress version
Organizing Tests, Logging In, Controlling State 27:212.1.0

Video playlists

Learn how to use Cypress to solve specific testing problems from the videos in the playlists below.

You can also find free Cypress video tutorials on the Courses page.

Test a React Todo App

In this tutorial, we will walk through building a "Todo" application in React while testing it with Cypress. We will look at ways we can use Cypress to not only create a test suite for our application, but help us write our tests and guide feature implementation.

By the end of this tutorial, you will have a feel for what it is like to test your application with Cypress while implementing features. You will gain experience with many of the Cypress commands and see how Cypress can help you build your application while creating a great safety net of tests along the way.

We have a lot of ground to cover, so let's get started!


TutorialLengthRelease dateCypress version
1. Project setup 3:521.0.2
2. Testing inputs 7:171.0.2
3. Form submission and XHRs 10:211.0.2
4. Loading data with fixtures 9:001.0.2
5. Todo item behavior 8:191.0.2
6. Toggling and debugging 9:051.0.2
7. Filters and data-driven tests 11:391.0.2
8. Full end-to-end tests part 1 8:591.0.2
9. Full end-to-end tests part 2 7:041.0.2

1. Project setup

We will start by cloning a starter repository. This repo already has the build and server configuration handled. We will take a look at the project's npm dependencies and scripts, then jump right into getting Cypress up and running.

Get the completed code for this lesson on GitHub

2. Text inputs

We will work through creating our first real test and implementing the feature under test as we go. We will see how to find and interact with elements on the page and how to make assertions about their behavior. We will also look into some best practices like using beforeEach and defining our application's baseUrl to remove duplicated code.

Get the completed code for this lesson on GitHub

3. Form submission and XHRs

We will implement form submission for our todo app, leveraging cy.server() and cy.route() to stub calls to our API. We will iterate on our test and implementation, focusing on the application's "happy path" first. Once our form is working, we'll use another stubbed XHR call to setup a failure scenario and implement the code to properly display an error message.

Get the completed code for this lesson on GitHub

4. Loading data with fixtures

We will implement the initial data load for our todo app, leveraging cy.server() and cy.route() to stub the API call to load our data. We will use fixture data to seed our application state. As we iterate on our test and app code, we will create and use a custom command to avoid unnecessary code duplication and keep our tests clean and readable.

We will be using this list of todo objects to stub our XHR calls. For convenience, you can copy it from here and paste it in as you follow along.

"id": 1,
"name": "Buy Milk",
"isComplete": false
"id": 2,
"name": "Buy Eggs",
"isComplete": false
"id": 3,
"name": "Buy Bread",
"isComplete": false
"id": 4,
"name": "Make French Toast",
"isComplete": false
Get the completed code for this lesson on GitHub

5. Todo item behavior

We will update our app to properly display todo items based on their isComplete property, adding tests to verify the proper behavior as we go. From there, we'll test and implement the item deletion functionality. We will cover interacting with an element that is hidden unless hovered over and look at different ways of handling this situation. We'll also look at the appropriate way to hold onto references to previously queried DOM elements using .as() to create aliases.

Get the completed code for this lesson on GitHub

6. Toggling and debugging

We will create a test for todo item toggling. As we implement the toggle feature, we will encounter a problem with our code and look at how Cypress can help us debug our code. We will use the Cypress Command Log to narrow down our problem. Then, we can use the Developer Tools right in Cypress to step through the code to dig into the issue. We'll even see how we can update application state while debugging and let our test confirm our theory about the cause of the bug. Once the debugging is complete, we will refactor our code to be less error prone, relying on the test to help us get it right.

Get the completed code for this lesson on GitHub

7. Filters and data-driven tests

We will test the application's footer behavior. First, we will ensure that our footer properly displays singular or plural text, based on the number of remaining todos. From there, we will test and implement the list filtering feature. We will create a test for one of the filters and see how to wire up React Router to make our filter links work. We will then look at how we can use standard JavaScript data structures to drive multiple assertions in our test, allowing us to test multiple variations of the filter behavior in a single test.

Get the completed code for this lesson on GitHub

8. Full end-to-end tests part 1

We will connect our back end API to the front end we've been building. Once we have the back end API connected, then we will create our first true end-to-end test. Using the back end API, we will ensure a consistent starting state by deleting any existing data from the database. Then we will test that our application can create and save new todos without a stubbed back end. We will also see how we can listen to and cy.wait() for XHR responses in our tests to avoid flake caused by unpredictable response times.

Get the completed code for this lesson on GitHub

9. Full end-to-end tests part 2

We will continue building on our full end-to-end tests, this time seeding the database to test our application against a populated database. We will repeat the pattern of adding cy.wait() commands to our tests to ensure our back end has responded before moving on. Once we have tests for deleting and updating items against a real back end, we will see how to run our Cypress tests using cypress run, giving us an ideal setup for running our tests in a CI environment.

Get the completed code for this lesson on GitHub