Consistent Results

Find out how Cypress fights against flaky tests and how it makes our tests deterministic.

If you have ever worked with end-to-end tests before, you will know that they are prone to produce false negatives. This means your tests will fail because of external forces that are outside of your control.


Common causes of flaky tests

In this section, we will look at the top five causes of flaky tests, and how Cypress battles these to make our test suite more deterministic.

Half-loaded pages

One of the most common causes of flaky tests is a half-loaded application state. Your app is still waiting to be fully ready to be interactive, but your test suite already tries to verify test cases without waiting for the load event to finish.

In the case of dynamic content, things are even more pronounced. This can cause the test suite to interact with non-existent elements and result in a failed test. Even though the element is working properly, it only needs more time to load.

Animations

Animations provide great visual feedback for users about what is happening on the page. They guide the user’s vision to key elements and can make your overall user experience better. On the other hand, they can often cause test cases to fail.

Cypress tries to get around this by waiting for elements to stop animating. To calculate whether the element is animated, Cypress checks the current and previous positions of the element. If the distance exceeds a threshold, the element is considered to be animated.

You can increase or decrease this threshold using the configuration file, or you can turn it off entirely if you don’t need it.

// Configuring animations in cypress.json
// The default values for threshold and wait for animations
{
    "animationDistanceThreshold": 5,
    "waitForAnimations": true
}

Since Cypress handles everything automatically for us, we don’t have to manually deal with animations inside the test cases.

Invisible elements

Invisible or even non-existent elements are another cause of flaky tests. Cypress does a lot of calculations to determine whether an element is visible or not. For example, it checks various CSS properties, such as the elements (or the ancestors) width and height, whether their display is set to none, or visibility is set to hidden. There are other factors that go into the calculation as well, but the basic idea is around looking at CSS properties.

Disabled elements

Interacting with disabled elements can also cause issues. Cypress verifies whether an element is disabled by checking if its disabled property is set to true.

Covered inputs

Lastly, covered inputs can also cause headaches. Imagine all of your tests are green. But in reality, the whole page is covered by a popup that cannot be closed. Real users will have a hard time interacting with your page, and you want to know about that.

As with animations, we don’t have to do anything special to cater to invisible, disabled, or covered elements. All of this is handled automatically and internally by Cypress.


Other ways to address flakes

Apart from the previously mentioned points, we can also manually troubleshoot flaky tests or even speed up our test cases by forcing interactions. To force an event to happen, we have to pass force: true to an event:

// Pass force: true if you want to force a command
cy.get('button').click({ force: true });

This will tell Cypress not to perform the above-mentioned steps such as:

  • Scrolling the element into the viewport
  • Checking if the element is animated
  • Checking if the element is visible
  • Checking if the element is not disabled
  • Checking if the element is covered

And so on.

Get hands-on with 1200+ tech skills courses.