1. Why is cy.wait(2000) considered a bad way to wait for a save to finish?
Answer
It is a fixed guess: too short and it fails on a slow run, too long and every run wastes that time
Correct. A number is a guess about timing. Waiting on the condition instead is both faster and more reliable.
cy.wait(number) is a fixed sleep. Prefer asserting the result (retry-ability) or waiting on a named route.
Why the other answers are wrong
- cy.wait does not exist. cy.wait exists. Waiting on a number is the part that is a bad idea.
- It waits for the wrong page. It waits on the current page for a fixed time. The problem is the fixed time itself.
- It only works in headless mode. cy.wait works in all modes. The issue is guessing a duration.
2. What are the two different things cy.wait can do?
Answer
cy.wait(number) waits a fixed time; cy.wait('@alias') waits for a specific network request to finish
Correct. The alias form waits for a real event and is good practice. The number form is a fixed sleep and is usually a smell.
cy.wait('@saveContact') waits for a real request and is fine. cy.wait(700) is a guess and is the one to avoid.
Why the other answers are wrong
- Both forms wait a fixed number of milliseconds. Only the number form is fixed. The alias form waits for a named request, however long it takes.
- cy.wait always waits for the page to reload. cy.wait does not reload the page. It waits on a duration or on a named request.
- The alias form pauses the test forever. The alias form waits until the named request completes, then continues.
3. What does cy.intercept('POST', '/api/contacts').as('saveContact') set up?
Answer
It watches for that POST request and gives it the alias 'saveContact' so you can wait on or assert it
Correct. cy.intercept observes (or stubs) a request. The alias lets you cy.wait('@saveContact') later.
cy.intercept watches or stubs a request; .as() names it. Then cy.wait('@saveContact') waits for exactly that request.
Why the other answers are wrong
- It sends a POST request immediately. It does not send a request. It sets up a watch for one the app makes.
- It blocks all network requests. It watches the matching request. It does not block everything.
- It renames the API endpoint. The endpoint is unchanged. The alias is only a name for use inside the test.
4. Saving takes about 700ms. What is the cleanest way to wait before asserting the new row?
Answer
Assert the row or toast directly and let .should retry until it appears
Correct. The retrying assertion waits exactly as long as the save needs, with no fixed delay and no extra setup.
For a UI result, assert it and let Cypress retry. Reach for cy.wait('@alias') when you specifically need the request to finish.
Why the other answers are wrong
- cy.wait(700) after clicking Save. A fixed wait is a guess. It can be too short on a slow run and wastes time on a fast one.
- A while loop that keeps calling cy.get until it finds the row. Cypress already retries cy.get. A manual loop fights the command queue and is unnecessary.
- Reload the page and check again. Reloading hides the timing question instead of waiting for the update correctly.
5. When is waiting on cy.wait('@saveContact') the better choice over asserting a UI element?
Answer
When you need to assert on the request or response itself, or nothing visible changes yet
Correct. If the check is about the network call (its body, status) or there is no visible result to retry on, wait on the route.
Assert the visible result when there is one; wait on the aliased route when the request itself is what you need to check.
Why the other answers are wrong
- Always, never assert on UI. UI assertions are the common, clean choice. Route waiting is for when you care about the request itself.
- Only when the app has no backend. With no backend there is no request to wait on. Route waiting needs a real request.
- Never, cy.wait('@alias') is a bad practice. Waiting on a named route is good practice. It is the number form that is the smell.
6. A test runs cy.get('[data-testid="save"]').click(), then cy.wait(500), then asserts the toast. What is the professional rewrite?
Answer
Remove cy.wait(500) and assert the toast directly. The assertion retries until it appears
Correct. The toast assertion already waits. The fixed 500ms adds nothing but fragility and delay.
Delete the fixed wait; the retrying assertion on the toast is the wait. Fast when the app is fast, patient when it is slow.
Why the other answers are wrong
- Change it to cy.wait(1500) to be safe. A larger fixed wait is still a guess and slows every run.
- Wrap the assertion in a try/catch. Catching and ignoring failures makes the test unable to fail meaningfully.
- Add a second cy.wait after the assertion. More fixed waits make the test slower and no more reliable.
7. What does cy.intercept let you do besides watch a request?
Answer
Stub the response, return fixed data so the test does not depend on a live backend
Correct. cy.intercept can reply with your own data, which makes tests fast and independent of server state.
cy.intercept can watch a request or stub its response. Stubbing gives fast, deterministic tests that do not need real server data.
Why the other answers are wrong
- Speed up the user's internet. It does not change real network speed. It can watch or stub requests.
- Delete the backend route. It does not change the server. It intercepts requests in the browser.
- Turn a POST into a GET automatically. It matches by method and URL; it does not silently change the method.
8. Why can stubbing a response with cy.intercept make a test more stable?
Answer
The test no longer depends on real server data or timing, so it behaves the same every run
Correct. Fixed response data removes a source of change and delay, so the test is deterministic.
A stubbed response is the same every run, so the test does not flake on slow or changing server data. Trade-off: you are no longer testing the real backend.
Why the other answers are wrong
- Because stubbed requests are encrypted. Encryption is unrelated to stability. Determinism comes from fixed, predictable data.
- Because it disables retry-ability. Retry-ability stays on. Stability comes from predictable responses, not from turning retries off.
- Because the browser caches the stub forever. Stability here is about controlled data per test, not caching.
9. A test runs cy.get('[data-testid="add"]').click(); cy.wait(300); cy.get('[data-testid="toast"]').should('contain', 'Added'). Why does it sometimes fail?
Answer
The 300ms guess is sometimes shorter than the real delay, so the toast is not there yet
Correct. On a slow run the toast has not appeared at 300ms and the test fails. The assertion alone would have waited correctly.
Remove cy.wait(300). The toast assertion retries and waits exactly long enough, no guess, no flake.
Why the other answers are wrong
- should('contain') is unreliable. should('contain') is reliable and retries. The fixed 300ms wait is the flaky part.
- You cannot click a data-testid element. You can. The flakiness comes from the fixed wait, not the click.
- The toast selector is wrong. The selector is fine in this example. The fixed wait is the cause of flakiness.
10. What should replace the pattern 'click, then sleep, then assert'?
Answer
click, then assert, and let the retrying assertion wait for the result
Correct. The assertion is the wait. This is the core Cypress pattern for stable tests.
Wait for what you expect, not for a number. In Cypress that means: act, then assert, and let retry-ability do the waiting.
Why the other answers are wrong
- click, then sleep longer, then assert. A longer sleep is still a guess and slows every run.
- click, then reload, then assert. Reloading avoids the timing question instead of waiting for the result correctly.
- click, then assert twice. Repeating the assertion does not fix timing. One retrying assertion already waits.