Cypress tests often become flaky when developers assume cy.wait('@alias') waits for every new request. It doesn’t. Aliases capture only the first match, so later waits may resolve instantly. The fix: re-intercept before each occurrence or use times: 1 to create one-shot intercepts that “consume” themselves. But the real solution is avoiding network waits altogether. Instead, rely on user-visible, accessible UI states (spinners, aria-busy, disabled buttons, status messages). This makes tests stable, realistic, and far more reliable than waiting on network events.Cypress tests often become flaky when developers assume cy.wait('@alias') waits for every new request. It doesn’t. Aliases capture only the first match, so later waits may resolve instantly. The fix: re-intercept before each occurrence or use times: 1 to create one-shot intercepts that “consume” themselves. But the real solution is avoiding network waits altogether. Instead, rely on user-visible, accessible UI states (spinners, aria-busy, disabled buttons, status messages). This makes tests stable, realistic, and far more reliable than waiting on network events.

Achieving Reliable E2E Tests in Cypress: Overcome cy.wait Pitfalls

2025/11/26 13:14

Cypress gives frontend engineers a superpower: the ability to write E2E tests that watch our app behave just like a real user would. But with great power comes… well, a lot of subtle flakiness if you’re not careful.

The cy.wait Illusion: What's Really Happening

The scenario is simple: you have a component that loads data, and after a user action, it loads new data using the same API endpoint. To ensure the new data has arrived, you intercept the request and then use cy.wait('@requestAlias') multiple times.

// A common, flawed approach: cy.intercept('GET', '/api/items/*', { fixture: 'item-1' }).as('getItems'); cy.visit('/items'); // 1. Wait for the initial load cy.wait('@getItems'); // ... User performs an action that triggers the SAME request ... // 2. Wait for the second load cy.wait('@getItems'); // <-- THIS IS THE PROBLEM

The Flaw

Cypress's cy.intercept logic is designed to capture a single match for an alias. When you call cy.wait('@getItems') for the first time, it finds the initial request, waits for its resolution, and then the alias is fulfilled.

When you call cy.wait('@getItems') a second time, Cypress does not reset the listener. Instead, it checks if a request has already been resolved with that alias. Because the first request has resolved, the second cy.wait command resolves immediately, without waiting for the new network call to finish. Your test is now racing against the network, not waiting for it.

Fix #1: Re-intercept before each expected request

(Works, explicit, but verbose)

cy.intercept('GET', '/api/items').as('getItems_1') cy.get('[data-testid=refresh]').click() cy.wait('@getItems_1') cy.intercept('GET', '/api/items').as('getItems_2') cy.get('[data-testid=load-more]').click() cy.wait('@getItems_2')

Clear, deterministic, but repetitive.

Fix #2: Use times: 1 to force Cypress to “consume” intercepts

(Cleaner: Cypress forgets the intercept after one match)

This is the missing tool many engineers don’t realize exists.

cy.intercept({ method: 'GET', pathname: '/api/items', times: 1 }).as('getItems') // trigger request 1 cy.get('[data-testid=refresh]').click() cy.wait('@getItems') cy.intercept({ method: 'GET', pathname: '/api/items', times: 1 }).as('getItems') // trigger request 2 cy.get('[data-testid=load-more]').click() cy.wait('@getItems')

Why this works:

  • times: 1 means Cypress removes the intercept after a single matching request
  • Re-declaring the intercept creates a fresh listener
  • Each cy.wait('@getItems') now truly waits for the next occurrence

This technique gives you explicit, occurrence-specific intercepts without alias clutter. For tests that must assert network behavior (payloads, headers, error flows), it’s a clean and robust pattern.

Fix #3: Stop waiting for requests altogether

(The best fix. UI > network.)

Here’s the golden rule:

That means the most stable tests assert what the user sees:

  • A loading spinner appears → disappears
  • A button becomes disabled → enabled
  • A success message appears when an action is complete.
  • The newly loaded element is now visible in the DOM.

Example with user-visible cues:

cy.get('[data-testid=refresh]').click() cy.get('[data-testid=spinner]').should('exist') cy.get('[data-testid=spinner]').should('not.exist') cy.get('[data-testid=item-list]') .children() .should('have.length.at.least', 1)

No reliance on internal network timing. No alias lifecycle. Zero flake.

Accessibility makes this even more robust

Accessible UI patterns make great Cypress hooks:

aria-busy attribute

<ul data-testid="item-list" aria-busy="true">

Test:

cy.get('[data-testid=item-list]').should('have.attr', 'aria-busy', 'false')

role="status" with live regions

<div role="status" aria-live="polite" data-testid="status"> Loading… </div>

Test:

cy.get('[data-testid=status]').should('contain', 'Loaded 10 items')

Disabled states for actions

cy.get('[data-testid=submit]').should('be.disabled') cy.get('[data-testid=submit]').should('not.be.disabled')

These patterns aid screen reader users and produce stable, deterministic E2E tests.

When waiting for requests is appropriate

There ARE valid scenarios:

  • Asserting payloads or query params
  • Mocking backend responses
  • Validating request ordering
  • Verifying retry logic
  • Testing error handling flows

For those cases: Combine times: 1 with explicit, fresh intercepts defined right before triggers.

For other cases: the test should rely on the UI state.

A combined real-world example

(Network + UI, the best of both worlds)

// UI-driven loading signal cy.get('[data-testid=create]').click() cy.get('[data-testid=spinner]').should('exist') // Network contract check cy.intercept({ method: 'POST', pathname: '/api/items', times: 1 }).as('postItem') cy.get('[data-testid=create]').click() cy.wait('@postItem') .its('request.body') .should('deep.include', { title: 'New item' }) // Final user-visible assertion cy.get('[data-testid=status]').should('contain', 'Item created')

The network part is accurate. The UI part is resilient. The test is rock-solid.

Final checklist

For accessible, deterministic, non-flaky Cypress tests

  • Prefer user-visible UI state, not network events
  • Use aria-busy, role="status", aria-live, and disabled states
  • When waiting for requests:
  • Re-intercept before each occurrence, OR
  • Use times: 1 to auto-expire the intercept
  • Avoid global, long-lived intercepts
  • Never assume cy.wait('@alias') waits “for the next request”
  • Make loading and completion states accessible (good for tests, good for users)

\

Disclaimer: The articles reposted on this site are sourced from public platforms and are provided for informational purposes only. They do not necessarily reflect the views of MEXC. All rights remain with the original authors. If you believe any content infringes on third-party rights, please contact service@support.mexc.com for removal. MEXC makes no guarantees regarding the accuracy, completeness, or timeliness of the content and is not responsible for any actions taken based on the information provided. The content does not constitute financial, legal, or other professional advice, nor should it be considered a recommendation or endorsement by MEXC.

You May Also Like

This Exclusive Cayman Getaway Tastes As Good As It Feels

This Exclusive Cayman Getaway Tastes As Good As It Feels

The post This Exclusive Cayman Getaway Tastes As Good As It Feels appeared on BitcoinEthereumNews.com. 1OAK’s Sand Soleil sits on Grand Cayman’s iconic Seven Mile Beach 1OAK Exhausted and professionally burnt out, I arrived at 1OAK’s Sand Soleil in search of the type of restoration that could still my mind and get me writing again. The seven-day culinary experience was a no-brainer for me as a food writer. The integration of an epicurean getaway with pure Cayman luxury seemed to be the perfect spark for my creativity—private chef dinners, deep dives into Caribbean flavors, and hands-on masterclasses, all located within a serene, oceanfront villa. I had finally arrived. With the last rays of the sun setting behind Grand Cayman’s famous Seven Mile Beach, casting a warm golden glow across the water, I tasted Chef Joe Hughes’ ceviche for the first time—cubes of wahoo cured in lime, with charred pineapple and a subtle, nutty crunch. Chef Joe Hughes’ love for bright, Asian-inspired flavours came through in this wahoo tataki layered with Vietnamese herbs, ripe papaya and mango, cashew and cilantro, all brought together with a nuoc cham. Jamie Fortune Something softened. For the first time in months, I began to feel present. Sophia List, the brainchild of the 1OAK experience, heard me well. With an intuition honed by years of curating luxury, she matched me with what she called “a vision realized.” List told me Sand Soleil—like the other 1OAK homes on Seven Mile Beach and in West Bay—was created to feel like a real sanctuary. For her, it’s the laid-back alternative to a busy hotel, a place where you get privacy and elegance without any fuss. “We wanted to introduce the Cayman Islands to something truly special—an ultra-luxury experience that combines exquisite design, maximum privacy, and a sense of calm,” she shared as she guided me through the four-bedroom villa. “We are so excited to…
Share
BitcoinEthereumNews2025/12/06 14:01
How Pros Buy Bitcoin Dips With DCA Like Institutions

How Pros Buy Bitcoin Dips With DCA Like Institutions

The post How Pros Buy Bitcoin Dips With DCA Like Institutions appeared on BitcoinEthereumNews.com. “Buy every dip.” That’s the advice from Strike CEO Jack Mallers. According to Mallers, with quantitative tightening over and rate cuts and stimulus on the horizon, the great print is coming. The US can’t afford falling asset prices, he argues, which translates into a giant wall of liquidity ready to muscle in and prop prices up. While retail has latched onto terms like “buy the dip” and “dollar-cost averaging” (DCA) for buying at market lows or making regular purchases, these are really concepts borrowed from the pros like Samar Sen, the senior vice president and head of APAC at Talos, an institutional digital asset trading platform. He says that institutional traders have used these terms for decades to manage their entry points into the market and build exposure gradually, while avoiding emotional decision-making in volatile markets. Source: Jack Mallers Related: Cryptocurrency investment: The ultimate indicators for crypto trading How institutions buy the dip Treasury companies like Strategy and BitMine have become poster children for institutions buying the dip and dollar-cost averaging (DCA) at scale, steadfastly vacuuming up coins every chance they get. Strategy stacked another 130 Bitcoin (BTC) on Monday, while the insatiable Tom Lee scooped up $150 million of Ether (ETH) on Thursday, prompting Arkham to post, “Tom Lee is DCAing ETH.” But while it may look like the smart money is glued to the screen reacting to every market downturn, the reality is quite different. Institutions don’t use the retail vocabulary, Samar explains, but the underlying ideas of disciplined accumulation, opportunistic rebalancing and staying insulated from short-term noise are very much present in how they engage with assets like Bitcoin. The core difference, he points out, is in how they execute those ideas. While retail investors are prone to react to headlines and price charts, institutional desks rely…
Share
BitcoinEthereumNews2025/12/06 13:53