## TL;DR

Every Cypress timeout is the same question: what was Cypress waiting for, and why did it never happen? Read the command log to see the last assertion state, fix the underlying wait (selector, network, or app state), and only then consider raising the timeout.

## Error

```text
AssertionError: Timed out retrying after 4000ms: expected '[div]' to have text 'Saved', but the text was 'Saving…'
```

## Steps

1. Click the failed command in the runner and read the snapshots: what did the app show at each retry? Expected: you see whether the app was stuck or just slow.
2. Check whether the app reached the expected state at all. If the text stayed `Saving…`, the bug is in the app or the API it calls, not the test. Expected: a decision between fixing the app and fixing the test.
3. If the app was merely slow, wait on the cause: `cy.intercept('POST', '/api/save').as('save')` then `cy.wait('@save')` before asserting. Expected: the test tracks the real completion signal.
4. If the state depends on polling, raise the timeout for that assertion only: `.should('have.text', 'Saved', { timeout: 15000 })`. Expected: slow-but-correct flows pass without slowing the whole suite.
5. Re-run the spec three times. Expected: three greens before calling it fixed.

## When to use

- Any `Timed out retrying` on assertions, gets, or actions.
- You need a systematic approach rather than guessing.

## When not to use

- `cy.visit()` timeouts (server never responded).
- Timeouts in Playwright, Jest, or Mocha (different retry semantics).

## Tool compatibility

- Cypress 10 through 14; per-command `{ timeout }` on queries and assertions.

## Variant phrasings

### Timed out retrying after 10000ms

Same pattern with a custom timeout; the diagnosis steps are identical.

### expected X but the value was Y at timeout

The assertion kept evaluating and never matched; read the last-seen value as the clue.

## Why it happens

Cypress retries until the timeout. A timeout means the condition never became true in the window: wrong expectation, slow dependency, or a genuinely broken app state.

## Edge cases

- Raising the global `defaultCommandTimeout` hides performance regressions; keep it at 4s and override per command.
- `.should()` with a callback retries the whole callback; side effects inside callbacks run multiple times.
- Timeouts on `cy.wait('@alias')` mean the request never fired; check the intercept pattern, not the timeout.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_v-RkCjYEt66LMhRoUKUlhw
