Testing Nested Components Reliably with Cypress

Cypress is a brilliant program for testing user interface elements. It offers flexibility for testing different types of components, and it handles changing pages fairly well. One of the quirks of Cypress shows up when working with nested components. As a page loads, some elements will load before others. This can cause problems with Cypress commands, but that can be solved by structuring selector statements differently.

How Cypress Determines What to Retry and What May Not Work

Cypress has built-in retries that help support changing pages. When a get command fails to find a page element, then it will try again up to a given timeout value. By default, this is four seconds. This is normally plenty of time for the page’s actions to execute, but factors such as when Cypress queries the page and what makes up the selector will make a difference in how Cypress sees the page. Cypress will only retry the command before the one that failed.

I will use the following command as an example:

get('#table').get('#row').should('contain', '1')

This Cypress command will select a “table,” then a “row” and then check that the row contains 1. If the row does not contain 1, Cypress will rerun .get('row') . The problem is that Cypress will only check the version of the DOM that it found in the get('table') statement.

Flakey Reason: Cypress Queries Page Before It’s Fully Loaded

When Cypress calls get(), it creates a snapshot of the DOM. Any commands chained off of this get will use the same snapshot. This helps to keep the webpage static during assertions. In the example above, a snapshot is made of the element “table” and then the selector for “row” looks inside table to find row. This snapshot will not update, even if the webpage is actively loading as get(table) is called. It would be nice if Cypress would refresh the entire table as it’s loading.

The Counter: Merging Selector Statements

Let’s say we merge the two get() statements like so:

get('#table #row').should('contain', '1')

This forces Cypress to refresh the entire table. This selector will grab the element “table,” look inside it for element “row,” and then check that the element “row” contains 1. Cypress will retry the command directly before our assertion that Cypress refreshes the table until the table fully loads.

Increasing the Reliability of Cypress Tests with Nested Elements

This will help to increase the reliability of Cypress tests when there are nested components. What are some other Cypress test cases that need special consideration?