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

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)

\

Piyasa Fırsatı
Threshold Logosu
Threshold Fiyatı(T)
$0.00939
$0.00939$0.00939
-0.63%
USD
Threshold (T) Canlı Fiyat Grafiği
Sorumluluk Reddi: Bu sitede yeniden yayınlanan makaleler, halka açık platformlardan alınmıştır ve yalnızca bilgilendirme amaçlıdır. MEXC'nin görüşlerini yansıtmayabilir. Tüm hakları telif sahiplerine aittir. Herhangi bir içeriğin üçüncü taraf haklarını ihlal ettiğini düşünüyorsanız, kaldırılması için lütfen service@support.mexc.com ile iletişime geçin. MEXC, içeriğin doğruluğu, eksiksizliği veya güncelliği konusunda hiçbir garanti vermez ve sağlanan bilgilere dayalı olarak alınan herhangi bir eylemden sorumlu değildir. İçerik, finansal, yasal veya diğer profesyonel tavsiye niteliğinde değildir ve MEXC tarafından bir tavsiye veya onay olarak değerlendirilmemelidir.

Ayrıca Şunları da Beğenebilirsiniz

What Does Coinbase’s New Move Mean for Crypto and Finance?

What Does Coinbase’s New Move Mean for Crypto and Finance?

The post What Does Coinbase’s New Move Mean for Crypto and Finance? appeared on BitcoinEthereumNews.com. The most prominent cryptocurrency exchange in the United States, Coinbase, revealed a significant step on October 3rd by applying for national trust company status with the Office of the Comptroller of the Currency (OCC). This initiative aims to consolidate oversight for new product developments under a centralized federal structure, streamlining the integration of cryptocurrencies with […] Continue Reading:What Does Coinbase’s New Move Mean for Crypto and Finance? Source: https://en.bitcoinhaber.net/what-does-coinbases-new-move-mean-for-crypto-and-finance
Paylaş
BitcoinEthereumNews2025/10/04 14:32
Tesla, Inc. (TSLA) Stock: Rises as Battery Cell Investment Expands at German Gigafactory

Tesla, Inc. (TSLA) Stock: Rises as Battery Cell Investment Expands at German Gigafactory

  TLDR TSLA trades near $485 after news of higher battery investment in Germany • Tesla targets up to 8 GWh of annual battery cell output by 2027 • Total cell factory
Paylaş
Coincentral2025/12/17 04:37
‘One Battle After Another’ Hits Peak Popularity With 97% Rotten Tomatoes Score

‘One Battle After Another’ Hits Peak Popularity With 97% Rotten Tomatoes Score

The post ‘One Battle After Another’ Hits Peak Popularity With 97% Rotten Tomatoes Score appeared on BitcoinEthereumNews.com. ‘One Battle After Another’ is already being tipped for Oscar success Warner Bros It tends to take time to build interest in movies, even ones which seem to be sure-fire successes. In the era of social media, many movie fans want to read reviews from their counterparts rather than mainstream outlets. As a result, all but the biggest franchises usually only gain traction once they have been released. There are however exceptions to this rule and one is on the verge of release. Called One Battle After Another, it stars Leonardo DiCaprio as a washed-up delusional revolutionary who lives off grid with his teenage daughter. When one of his old enemies resurfaces and his daughter is abducted, the movie turns into a game of cat and mouse with car chases aplenty as well as the involvement of militias and mysterious organizations. The plot has a hint of 80s action extravaganza Commando but is actually loosely based on a book written by American author Thomas Pynchon. The movie hits a timely note as Pynchon is famous for sending up nefarious quasi-government organisations in his novels and director Paul Thomas Anderson continues that theme on screen. It has been seen as a political commentary and DiCaprio was a natural fit. His role combines the paranoia he portrayed in Howard Hughes biopic The Aviator with the comedic chases from his crime comedy Catch Me If You Can. DiCaprio is supported by an equally heavyweight cast led by Benicio del Toro as his accomplice and Sean Penn as his nemesis. One Battle After Another premiered in Los Angeles on September 8 and was met with universal acclaim. It has a critics’ rating of 97% on review aggregator Rotten Tomatoes but doesn’t yet have a single score from audiences as the film won’t be released…
Paylaş
BitcoinEthereumNews2025/09/19 06:41