In Cypress, where do you put { timeout: 10000 } so a chained .should() retries longer?
answer
- the option rides on the command
- one window for the whole chain
- should() has no options parameter
- defaultCommandTimeout is the 4000 ms floor
- timeout zero means no retrying
basics
~10 sPut it on the query, not the assertion: cy.get(selector, { timeout: 10000 }). That single window covers the lookup and every assertion chained after it, because .should() accepts no options object of its own.
solid answer
~40 sThe retry window belongs to the command, so the option goes on the query: `cy.get('[data-cy=availability-spinner]', { timeout: 20000 }).should('not.exist')`. Every assertion chained after that query — `.should()` and `.and()` alike — shares the same twenty-second budget rather than getting one each. `.should()` has no options parameter at all, so `.should('not.exist', { timeout: 20000 })` is read as an expected value and extends nothing. The floor for commands with no explicit option is `defaultCommandTimeout`, 4000 ms as of Cypress 16, settable in `cypress.config.js`, through `cypress run --config defaultCommandTimeout=10000`, or as a per-suite and per-test override in the block's config object. `{ timeout: 0 }` disables retrying entirely and makes the check a single synchronous look at the page.
code
javascript · 14 lines// cypress.config.js sets the floor: { e2e: { defaultCommandTimeout: 4000 } }
// per command - the 20s covers the query and every assertion after it
cy.get('[data-cy=availability-spinner]', { timeout: 20000 })
.should('not.exist')
// per test - defaultCommandTimeout is overridable in a block config object
it('lists rooms for a long date range', { defaultCommandTimeout: 15000 }, () => {
cy.get('[data-cy=room-card]').should('have.length', 8).and('be.visible')
})
// timeout: 0 disables retrying - one synchronous look at the page
cy.visit('/rooms')
cy.get('[data-cy=ssr-error]', { timeout: 0 }).should('not.exist')go deeper
Recall the syntax: the options object is a second argument to cy.get(), and the number is milliseconds.
An interviewer expects you to say the window belongs to the command, is shared by every chained assertion, and defaults to defaultCommandTimeout at 4000 ms.
Show that you narrow an override to the one genuinely slow step, and explain what a raised global value costs in how long a wrong selector takes to report.
Own where overrides are allowed to live so the suite's slow paths are documented in the specs rather than hidden in a single global number.
## The window belongs to the command, not the assertion `.should()` is registered in Cypress as an assertion that takes a previous subject, and its arguments are a chainer, that chainer's values, or a callback. There is no options parameter, so there is nowhere on `.should()` to put a timeout. What actually happens is that the assertion is attached to the command in front of it and inherits that command's window: ```javascript // the 20s belongs to cy.get(); the assertion simply lives inside it cy.get('[data-cy=availability-spinner]', { timeout: 20000 }).should('not.exist') ``` Write `.should('not.exist', { timeout: 20000 })` instead and `.should()` reads the object as the assertion's **expected value**, not as configuration. Nothing is extended, and the test still gives up after the default four seconds — which is why this mistake usually surfaces as "the timeout option does not work". ## Four places the retry budget can be set | Where | Syntax | Scope | | --- | --- | --- | | Config file | `defaultCommandTimeout: 4000` in `cypress.config.js` | every command in every spec | | CLI | `cypress run --config defaultCommandTimeout=10000` | the whole run | | Suite or test | `it('lists rooms', { defaultCommandTimeout: 15000 }, () => { /* ... */ })` | that block only | | One command | `cy.get('[data-cy=room-card]', { timeout: 20000 })` | that command and its chained assertions | `defaultCommandTimeout` is one of the configuration values Cypress allows you to override per suite and per test, so the third row needs no plugin. Its shipped default is **4000 ms** as of Cypress 16. ## What the per-command option actually covers The single window covers the whole group, not each piece of it: - The query keeps re-running inside the window until it produces a subject. - Every assertion chained after it — `.should()` and `.and()` alike — is evaluated inside the **same** window, not given a fresh one each. - A `.should(cb)` callback is retried inside that window as a unit; all of its expectations must pass together before it expires. - Once the window closes, whichever assertion was failing at that moment is the one reported. So `cy.get('[data-cy=room-card]', { timeout: 10000 }).should('have.length', 8).and('be.visible')` is a ten-second budget for the whole sentence, not ten seconds each. ## Which timeout is which Cypress has several timeouts and only one of them governs assertion retries. Reaching for the wrong knob is the usual reason a raise appears to do nothing. | Setting | Governs | Default | | --- | --- | --- | | `defaultCommandTimeout` | commands and the assertions chained to them | 4000 ms | | `pageLoadTimeout` | page transitions such as `cy.visit()` and `cy.reload()` | 60000 ms | | `requestTimeout` | waiting for a request to be made | 5000 ms | | `responseTimeout` | waiting for a response in `cy.request()`, `cy.wait()` and friends | 30000 ms | | `taskTimeout` | how long a `cy.task()` may run in Node | 60000 ms | ## `{ timeout: 0 }` and when you actually want it Setting the option to zero spends no time retrying, which turns the command into one synchronous look at the page. That is the tool for asserting something is genuinely absent **right now**, for instance immediately after a server-rendered page loads: ```javascript cy.visit('/rooms') cy.get('[data-cy=ssr-error]', { timeout: 0 }).should('not.exist') ``` Used anywhere the app renders asynchronously it produces exactly the flake it looks like it is preventing, because a zero-length window is a race against the first paint. ## Choosing the scope, and what each costs 1. **Per command** is the narrowest and the usual answer. Only the one genuinely slow step — a rate-limited availability search, a payment redirect — gets extra room, and every other command still fails fast. 2. **Per test or per suite** suits a whole spec that talks to a slow dependency, and keeps the override visible in the block header where a reader will see it. 3. **Global** is the blunt instrument: it also slows down how long a genuinely wrong selector takes to report, so a typo that used to fail in four seconds now costs the raised value on every affected command. ## Where candidates go wrong - Putting `{ timeout }` on `.should()` and concluding the option is broken. - Assuming each chained assertion gets its own copy of the window. - Confusing `defaultCommandTimeout` with `pageLoadTimeout` or `responseTimeout`. - Believing `{ timeout: 0 }` means "no limit". It means no retrying at all.
- If a chain has three assertions and a ten-second timeout, how much time does each one get?They share the ten seconds; they do not get ten seconds each. The query and its whole assertion group are retried inside one window, and whichever assertion is failing when the window closes is the one reported. That is why a long chain of checks behind a slow render can time out on the first assertion while the later ones never run at all.
- What is the difference between defaultCommandTimeout and responseTimeout in Cypress?`defaultCommandTimeout` is the retry budget for commands and the assertions attached to them, defaulting to 4000 ms. `responseTimeout` governs how long Cypress waits for a response in `cy.request()`, `cy.wait()` on an intercepted route, and similar network steps. Raising the wrong one is common: a slow availability API surfaces as a `cy.wait()` failure governed by `responseTimeout`, not as an assertion timeout.
saying these in an interview costs you the question
- Passes { timeout } as a second argument to .should()
- Thinks each chained assertion gets its own window
- Reads { timeout: 0 } as an unlimited wait
- Confuses defaultCommandTimeout with pageLoadTimeout
- Raises the global timeout to fix one slow command