October DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsWindows FixRecommendedWindows errors stealing your time? Find the fix fastScan stability, cleanup and performance issues.Fix NowOctober DealsAmazon USDeal season is back - check today's better picksAmazon US: current deals, useful picks and tech finds.See Picks×
Skip to content
World desk7 min

How to Find and Fix Flaky Cypress Tests Using Code Smells

A practical workflow for reproducing flaky Cypress failures, finding nondeterministic test smells, and validating fixes without relying on retries.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

A flaky Cypress test passes sometimes and fails other times without a meaningful change to the code. The fastest route to a durable fix is to reproduce the failure, classify its symptom, and inspect test code for nondeterministic assumptions: leaked state, brittle selectors, arbitrary waits, mutable-DOM branches, incomplete setup, or retries masking the problem. Replace timing guesses with assertions about the state the test needs, then rerun the test alone, in its suite, and under varied load.

Start with evidence from a specific failure

Before changing code, preserve the failure context: the assertion and command log, browser, test data, Cypress version, operating environment, and whether it occurred in cypress open or cypress run. These details make it easier to reproduce the same conditions and distinguish a test defect from an environment-sensitive assumption.

  1. Run the suspect test by itself. If it fails alone, inspect its setup, selector, and synchronization first.
  2. Run it in its spec and normal suite. A failure only after another test is a clue to investigate state leakage or ordering.
  3. Repeat it enough to try to expose intermittent behavior. Cypress recommends excessive repetition and varying network and CPU conditions; its documentation gives 100 executions as an example, not as a universal or statistically meaningful threshold. Cypress describes this approach to reproducing flaky tests.
  4. Vary network or CPU load to approximate the resource conditions under which the failure appears, especially if it occurs in CI but not locally.

Classify the symptom before choosing a fix. A timeout waiting for an element may indicate that the expected application state was never reached, a selector no longer matches, or an asynchronous dependency is unresolved. Failure only after another test suggests a shared-state problem. A CI-only failure may point to a timing or resource assumption worth reproducing under load. These are hypotheses to test, not definitive diagnoses: Cypress identifies animations, API calls, server or database availability, resource availability, and network issues among possible race-related causes. See Cypress’s discussion of test retries and flaky failures.

1. Remove hidden dependencies between tests

The smell

A test assumes another test already logged in, created a record, or left the application on a particular page. It may pass in the full suite but fail alone, after reordering, or on a retry.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The fix

Make each test establish its own preconditions and data. Cypress enables end-to-end test isolation by default, but browser isolation does not necessarily reset server-side records or other application data. Set up or reset that data deliberately when tests can affect one another. Cypress recommends independent tests, isolated specs, programmatic login, and control over application state. Its guidance states: “Best Practice: Tests should always be able to be run independently from one another and still pass.” Read Cypress’s test-isolation guidance.

Programmatic login can make setup faster, but it should not replace a separate test that verifies the user-facing login flow. Keep that flow covered while avoiding the cost and variability of repeating it as setup for unrelated tests.

2. Replace brittle selectors with stable test attributes

The smell

Selectors depend on long CSS paths, presentation classes, or IDs that exist for styling or implementation. A markup or styling refactor can then break a test even though the user-facing behavior is unchanged.

The fix

Add purposeful attributes such as data-cy, or the equivalent chosen by your project, and make each selector specific enough to identify the intended control.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
// Application markup
<button data-cy="save-profile">Save</button>

// Cypress test
cy.get('[data-cy="save-profile"]').click();
cy.get('[data-cy="save-profile"]').should('be.disabled');

Cypress recommends data-* attributes because they are decoupled from CSS styling and JavaScript behavior: “Best Practice: Use data-* attributes to provide context to your selectors and isolate them from CSS or JS changes.” See Cypress’s selector best practices.

3. Replace arbitrary delays with state-based synchronization

The smell

A test uses cy.wait(5000) to guess when rendering or a request will finish. That delay may be too short on a slow run and unnecessarily long on a fast one.

The fix

Assert the condition the test actually needs. Cypress retries linked queries and assertions until they pass or time out, so the test can wait for the UI state instead of sleeping for a guessed duration.

cy.get('[data-cy="profile-name"]').should('have.text', 'Ada Lovelace');

For a known network request, synchronize on the request and then verify the resulting UI. A request completing does not, by itself, prove the page has rendered the expected state.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
cy.intercept('GET', '/api/profile').as('getProfile');
cy.visit('/profile');
cy.wait('@getProfile');
cy.get('[data-cy="profile-name"]').should('be.visible');

A time-based cy.wait() and a wait tied to a specific intercepted request are not equivalent: the latter identifies a synchronization boundary, while a bare duration is a timing guess. Cypress’s query retry-ability applies to linked queries and assertions; commands that are not queries execute once. Read how Cypress query retry-ability works.

4. Do not branch on a DOM that is still changing

The smell

A test checks whether a transient element exists and takes different paths depending on the result while the client application may still be rendering or updating. The same check can see different states on different runs.

The fix

Make the behavior deterministic, or decide from a stable source of truth after it is ready. Depending on the application, that could be server-side state, a cookie, local storage, explicit test data, or a URL parameter that selects an experiment.

Cypress warns: “In any other circumstance you will have flaky tests if you try to rely on the state of the DOM for conditional testing.” Read Cypress’s conditional-testing guidance.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

5. Put required setup before each test

The smell

Necessary database or application cleanup exists only in after or afterEach. If the runner is refreshed or interrupted mid-test, that cleanup may not run, leaving stale data for later tests.

The fix

Put the reset or setup needed for a test before it runs, so the test establishes its own starting conditions. First identify what state Cypress’s automatic browser isolation already handles; add deliberate setup for any remaining shared server-side or application state.

6. Treat test retries as a diagnostic signal, not a repair

Cypress has two different retry mechanisms:

  • Query retry-ability retries linked queries and assertions while Cypress waits for expected application state. Use this as normal synchronization in place of arbitrary pauses.
  • Test retries rerun an entire failed test when configured. They are disabled by default. The configured count is the number of additional attempts, and beforeEach and afterEach run again for each attempt.

If a test fails and then passes on retry, that is evidence of nondeterminism to investigate, not proof the cause is gone. Retries can reveal intermittent failures and keep them visible in run output; increasing the count alone can make a suite appear greener without making it reliable. Cypress documents retry configuration and behavior.

Cypress documentation also describes experimental retry strategies for flake detection, including strategies that can preserve a failing result after a later passing retry or require a threshold of passing attempts. Because these strategies are marked experimental and can change, check the documentation for the Cypress version your project uses before configuring them. Check the current retry-strategy documentation.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Choose fixes by the cause they make deterministic

Change What it stabilizes Trade-off or check
Per-test setup and deliberate data reset Starting application and server-side state Setup can add work; preserve separate user-flow coverage when using programmatic login.
Purposeful data-* selectors Element identification across styling and markup changes Attributes must be maintained and specific enough to avoid ambiguous matches.
Assertions and request interception The actual UI or network condition needed to proceed A completed request is not a substitute for asserting the resulting UI.
Stable state for conditional behavior The decision that selects a test path Do not branch on a DOM that may still be rendering.
Test retries Visibility of intermittent failures in run output Retries do not identify or remove the underlying nondeterminism.

Verify the fix under the conditions that exposed the failure

  1. Run the modified test alone.
  2. Repeat it under varied network and CPU conditions, including the conditions that reproduced the problem.
  3. Run it in its normal spec and suite, then run relevant neighboring tests to check for state leakage.
  4. Confirm the user-visible state with an assertion rather than assuming a command completed instantly.
  5. Record the Cypress version, browser, operating environment, and whether the failure appeared in cypress open or cypress run.

A fix is convincing when the test reaches the same result consistently in isolation and in its usual suite under the conditions that previously exposed the failure—not merely when a retry turns one run green.

Or skip the browser setup

If reproducing the failure also requires capturing a page screenshot, a direct ScreenshotNeo request can return an image or PDF without setting up a browser capture script. The service accepts a URL in one GET request. See the ScreenshotNeo API documentation.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

ScreenshotNeo removes cookie banners, newsletter popups, and chat widgets before capture; each step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits cost nothing, and the response identifies the page verdict and billing status in headers. Its MCP server offers take_screenshot, get_page_info, and capture_pdf for AI agents and MCP clients. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 screenshots.

Sign up for 1,000 free screenshots a month with no card.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Frequently Asked Questions

Why does a Cypress test pass locally but fail in CI?

CI may expose timing, network, server, database, or resource assumptions that a local run does not. Reproduce under varied load and inspect whether the test waits for the required application state.

Should I remove every cy.wait() from a Cypress test?

No. Replace bare time-based waits with assertions or a wait for a specific intercepted request where appropriate. A request boundary can express meaningful synchronization; an arbitrary duration generally cannot.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

More from the Wire

  1. World desk4 min
    How to Spot an AI Voice Scam Before Sending MoneyDon’t rely on how a caller sounds. Pause, call back through a known number, and verify the emergency with another trusted person before sending money.
  2. Mountain View desk4 min
    Google’s SynthID Detector: How to Check AI-Generated Images, Video and AudioGoogle’s SynthID Detector looks for an embedded watermark in supported images, video and audio. Here is what its results do—and do not—show.
  3. Redmond desk20 min
    How to create a link to File or Folder in Windows 11Windows 11 gives you several ways to point to a file or folder without moving or duplicating it. You can create a desktop shortcut,…
Recommended PC Tool
Recommended PC Tool
Outdated Drivers Are Slowing You DownFree scan - exact matches
Windows Errors? Fix Them Before They SpreadFree repair scan

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.