To make Cypress end-to-end tests more reliable, make each test independent, use stable selectors, synchronize on observable conditions instead of fixed delays, and be deliberate about whether a test uses a real backend or a stub. Retries can reveal instability, but they do not fix its cause. Choose the smallest test level that proves the behavior you need.
Start with independent tests and controlled state
Cypress’s guidance is direct: “Tests should always be able to be run independently from one another and still pass.” In end-to-end testing, test isolation is enabled by default. Before each test, Cypress clears the page and browser cookies, localStorage, and sessionStorage. That helps prevent one test’s browser state from silently becoming another test’s precondition.
As an Amazon Associate I earn from qualifying purchases.
Isolation is not a full system reset. IndexedDB is not cleared by this behavior, and browser cleanup does not reset a backend database or other server-side state. If your application uses those stores, seed or clean them explicitly through a supported setup path. Cypress describes isolation and its limits in its test isolation documentation.
Set up only what the scenario needs
- Use a controllable local development server where you can seed test data, reset state, or provide a test-only setup mechanism.
- For repeated authenticated scenarios, programmatic login can avoid replaying the UI login flow in every test. Keep a separate test of the user-facing authentication journey if that journey itself is important.
- Do not disable test isolation simply to make a suite faster unless you can show that tests still pass independently and have explicit state management.
A test that passes only after another test has run is relying on hidden state. Run it alone and in the full suite while investigating order-dependent failures.
#1 Best Overall
Use selectors that survive ordinary changes
Prefer selectors intended for tests, such as data-cy, rather than classes or IDs that may change during styling work, or visible copy that product teams may revise. Cypress’s best-practices documentation explains the rationale for dedicated test attributes.
cy.get('[data-cy="save-profile"]').click()
cy.get('[data-cy="save-status"]').should('have.text', 'Profile saved')
This example identifies the control by a test-specific attribute and verifies a user-visible result. Agree on a selector convention with the application team; the value is not the exact attribute name, but a selector that reflects test intent rather than incidental implementation.
Wait for conditions, not arbitrary time
Linked Cypress queries and assertions retry while waiting for the application to reach the asserted state, up to the applicable timeout. A fixed sleep such as cy.wait(2000) does not establish that the page is ready: it can waste time when the page is fast and still be too short when it is slow. Cypress documents query retry-ability and command behavior in its retry-ability guide.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Rank #2
Assert after an action
Commands that act on the page, such as .click(), are not retried like queries. Keep action chains clear, then query for the resulting state:
cy.get('[data-cy="submit-order"]').click()
cy.get('[data-cy="order-confirmation"]').should('be.visible')
This structure makes the test’s claim explicit: after the user submits, the confirmation becomes visible. Avoid packing several actions into a chain when a rerender could detach the element being acted on.
Wait for a specific request when that is the contract
Use cy.intercept() when the scenario needs to observe or control a particular request. Give the route an alias, trigger the behavior, and wait for that alias rather than guessing how long the response takes:
Rank #3
cy.intercept('GET', '/api/profile').as('getProfile')
cy.visit('/profile')
cy.wait('@getProfile').its('response.statusCode').should('eq', 200)
cy.get('[data-cy="profile-name"]').should('be.visible')
Adapt the route and assertion to the application’s actual API contract. Waiting for a request proves that the matching request completed; the DOM assertion separately proves the visible page state. Cypress’s intercept command reference covers observing, stubbing, and modifying requests.
Do these 3 things before closing this tab:
1Repair Windows errors before they cause bigger problems2Scan for outdated or missing drivers - takes under a minute3Clear out junk files and repair common Windows errorsChoose real backend requests or stubs deliberately
Neither a real backend nor a stub is universally best. The right choice depends on what the test must prove. A stub gives control and makes edge cases reproducible, but a stubbed response cannot prove that the live server returns the expected payload. Keep at least a meaningful real integration path where backend integration is part of the release risk, and use stubs to test UI behavior across controlled outcomes. Cypress’s local development guidance discusses controllable servers and testing practices.
| Approach | What it establishes | Trade-off |
|---|---|---|
| Real backend request | The tested browser flow can exercise the actual service response and its integration with the UI. | Requires suitable test data and a reachable, controlled environment; failures can originate outside the UI. |
| Stubbed request | The UI’s behavior for the controlled response supplied by the test, including reproducible edge cases. | Does not verify the live server’s payload or the complete browser-to-server integration. |
| Component test | Component behavior without requiring a full browser-to-backend journey. | Does not by itself prove routing and cross-system integration for a user journey. |
| API test | An endpoint or API contract without exercising the full browser journey. | Does not by itself prove that the browser UI presents the response correctly. |
Keep intercepts focused on requests relevant to the scenario. Broad wildcard interception can add overhead on pages with many assets and third-party calls; Cypress notes this in its performance guidance.
Rank #4
Pick the smallest test level that proves the behavior
- Use E2E tests for critical user journeys whose value depends on browser behavior, server responses, routing, or integration across systems.
- Use component tests when the behavior can be established in the UI without a full browser-to-backend journey.
- Use API tests when the question is whether an endpoint or contract behaves correctly, not whether a complete browser journey works.
A balanced suite reserves full end-to-end journeys for important integrated risks and verifies narrower behavior at the component or API level. Cypress also describes deployed smoke tests as an option some teams use; they are not a universal requirement.
Understand retries—and investigate the first failure
Query retry-ability and test retries solve different problems. Retry-ability is part of normal Cypress behavior: queries and assertions retry while waiting for the DOM condition. Test retries are optional and rerun a failed test; Cypress test retries are disabled by default.
Retries can help expose intermittent failures in CI, but a later passing attempt does not erase the initial failure. Treat the first failed attempt as evidence to investigate: check state setup, network conditions, timing assumptions, and whether the assertion reflects the intended contract. Configure retries intentionally and scope them rather than using them as a substitute for deterministic setup.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Account for Cypress 16 network changes
For Chrome, Chromium, and Edge, Cypress’s native network interception guide says that starting in Cypress 16, the application connects directly to the server on the browser’s native network path. That allows HTTP/2 or HTTP/3 to be negotiated when supported by the server, rather than being downgraded through the previous Cypress path. The change also affects observable behavior, including cases where browser-rejected responses are not observable. Teams upgrading should review assertions that depended on the legacy network path against the native network interception guide. This version-specific guidance should not be generalized to every browser or Cypress version.
Troubleshoot common flaky-test patterns
| Symptom | Likely cause | What to change |
|---|---|---|
| Passes alone, fails in the full suite | Leaked browser or server-side state, or a dependency on test order. | Run the test alone; make its setup explicit; check IndexedDB and backend data, which default browser isolation does not clear. |
| Fails intermittently around a page update | A fixed delay or an assertion made before the relevant UI condition is true. | Assert on the resulting DOM state or wait for the specific request that matters. |
| Selector breaks after a visual or copy change | The test used a class, styling detail, or mutable text as its locator. | Use a dedicated test attribute such as data-cy. |
| Stubbed test passes, but integration fails | The test established only the UI’s behavior for the stub, not the real server payload. | Add or retain a deliberate real integration path for that release risk. |
| Interception makes a page test slow or noisy | A broad wildcard route is intercepting unrelated traffic. | Intercept only the request needed by the scenario. |
| Network assertions change after upgrading to Cypress 16 | The browser-native network path may change what Cypress can observe. | Review the native network guide for the target browser and update assumptions that relied on the previous path. |
Or skip the browser setup
For capturing a rendered page as a screenshot or PDF—not for replacing Cypress assertions or end-to-end tests—ScreenshotNeo offers a website screenshot API and MCP server. One GET request returns an image or PDF. See the API documentation.
Quick Recap
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; bot checks, blank pages, and failed loads are never billed. Its MCP server lets AI agents take screenshots. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000.
Sign up free for ScreenshotNeo.
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.




