neart.ai
EcosystemStoryHow We BuildPricingBlog
Try Inspected →
neart.ai
EcosystemStoryHow We BuildBlog

Ní neart go cur le chéile

A SaltCore Group Limited company

© 2026 neart.ai · SaltCore Group Limited. All rights reserved.

Software Quality

Why Are My End-to-End Tests Flaky, and How Do I Fix Them?

18 January 20264 min read

## The short answer


End-to-end tests flake — pass and fail without code changes — almost always because of timing issues, unreliable test data, shared state between tests, or dependence on unstable external services. The fix is rarely "add a longer wait". It's to make your tests deterministic: wait for real conditions rather than fixed delays, isolate each test's data, and control or stub the things you don't own. Flakiness is a defect in the test, not a quirk to tolerate.


A flaky suite is worse than no suite, because teams quickly learn to ignore red builds.


## Why flakiness is so damaging


When tests fail randomly, developers stop trusting them. They re-run the build until it goes green, which means a genuine regression can slip through disguised as "just a flake". The whole point of E2E tests — confidence — evaporates. Treating flakiness as a first-class bug, with the same urgency as a production defect, is the only sustainable posture.


## Root cause 1: timing and race conditions


The most common culprit. The test clicks a button and immediately checks for a result, but the application hasn't finished rendering or the network call hasn't returned.


Fixes:


- **Replace fixed sleeps with explicit waits.** Wait for an element to be visible, for text to appear, or for a network request to complete — not for an arbitrary number of seconds.

- **Use your test framework's auto-waiting features.** Modern tools retry assertions until they pass or time out, which removes most manual waits.

- **Wait for the right signal.** Waiting for a spinner to disappear is more reliable than waiting for a guessed duration.


## Root cause 2: test data and ordering


Tests that share data interfere with each other. If test A creates a record that test B assumes is absent, the result depends on run order.


Fixes:


- **Make each test create its own data** and clean up after itself, or use unique identifiers (timestamps, random suffixes) so tests never collide.

- **Never depend on test execution order.** Each test should pass in isolation.

- **Reset state between runs.** Seed a known baseline, or use transactions that roll back.


## Root cause 3: shared and leaked state


Global state — a logged-in session, a feature flag, a cached value — can leak from one test into the next.


Fixes:


- **Start each test from a known, clean state.** Fresh browser context, fresh session.

- **Avoid relying on state set up by a previous test**, even when it's convenient.

- **Isolate parallel workers** so concurrent tests don't write to the same data.


## Root cause 4: unstable external dependencies


If your test hits a real third-party API, payment sandbox, or email provider, their downtime becomes your flakiness.


Fixes:


- **Stub or mock external services** at the boundary for most tests, so you're testing your code, not theirs.

- **Keep a small number of true end-to-end smoke tests** against real services if you genuinely need that coverage, and accept they'll occasionally fail.

- **Add sensible retries only at the integration boundary**, never to mask logic bugs.


## Root cause 5: the environment itself


Underpowered CI runners, network contention, and resource limits cause timeouts that look like flakes.


Fixes:


- **Give CI enough resources** to run the browser smoothly.

- **Run tests in parallel deliberately**, with proper isolation, rather than accidentally.

- **Monitor test duration** — a test that's creeping towards its timeout is a flake waiting to happen.


## How to find and fix flakes systematically


1. **Quarantine, don't delete.** Move a flaky test out of the blocking suite so it stops poisoning the build, then fix it promptly.

2. **Track flake rates.** Record how often each test fails on retry. The worst offenders reveal themselves.

3. **Reproduce locally** by running the test many times in a loop. Flakes that only appear under repetition are the timing kind.

4. **Fix the root cause, not the symptom.** Adding a retry around a racy assertion hides the problem; fixing the wait condition solves it.


At neart.ai, building enterprise-grade products means our E2E suites have to be trusted gates, not noise — which is why we treat every flake as a defect to be eliminated rather than re-run away.


## Takeaway


Flakiness is not random; it's caused by timing, data, shared state, and unstable dependencies — all fixable. Replace fixed waits with condition-based waits, isolate each test's data and state, stub what you don't control, and treat every flaky test as a bug to fix or quarantine. A deterministic suite is the only kind worth keeping green.

Related posts

Software Quality

How Do You Ship Software Without Regressions?

Software Quality

What Is End-to-End Testing, and When Should You Use It?

Software Quality

What Does WCAG 2.2 Mean for Your Testing Strategy?