Cypress Interview Questions: Command Queues, Network Intercepts, and Test Isolation
Quick Overview
Diagnose three reproducible Cypress failures in one local application, then explain why each minimal repair preserves the intended assertion.
A Cypress test can fail before the browser has done anything. Another can display the correct profile while its network wait times out. A third can pass after a login test and fail when run alone. These failures look unrelated until you separate JavaScript execution, Cypress's command queue, and the state each test owns.
This guide uses one small profile application to diagnose all three. Original practice, locally executed: the examples were run with Cypress 16.0.0 in headless Electron 146. The deliberately broken suite produced three failures and one passing setup test; the repaired suite passed five tests. The session-dependent case also passed by itself after repair. These are our exercises, not reported employer questions.
For related interview practice, start with Contrast UI vs backend testing; design UI-change test cases. Explain which boundary a test covers before deciding what a green result means.

Establish the application contract before debugging
The local page requests GET /api/profile, receives {id: 7, name: "Ada"}, and renders the name plus a Ready status. A separate demo-session button writes demo-user=Ada to local storage. Its authentication label then changes from Guest to Signed in as Ada.
That button is a deliberate simplification. It does not contact an identity provider, issue a secure cookie, or prove authorization. The server returns Cache-Control: no-store, so our missed-request experiment isolates registration order rather than browser caching. The repaired delayed-response test substitutes a response through Cypress; the other profile-request checks observe the local server.
We configured testIsolation: true, disabled whole-test retries, and used a 1,200-millisecond command/request timeout to make intentional failures finish promptly. That timeout is a lab setting, not a suggested production default. Choose real project timeouts from expected application behavior and investigate repeated violations.
To reproduce the exercise, serve that contract on localhost port 4187, set it as Cypress's baseUrl, and put the shown tests in an end-to-end spec. Use data-cy attributes matching the examples. Run the broken cases separately from the repaired suite so expected failures cannot be mistaken for a failed repair. Record the Cypress version, browser, selected spec, and pass/fail count alongside the error. Keep the intentional short timeout explicit when sharing the result.
The important contract is visible: the page must show the returned name, and each test must arrange its own demo state. Avoid replacing either requirement with an assertion that an element merely exists. A permanent empty heading would satisfy existence while breaking the feature.
Why is the variable still undefined?
Predict this failure before running it:
it('reads before the queue runs', () => {
let name
cy.visit('/')
cy.get('[data-cy=name]').invoke('text').then(x => {
name = x
})
expect(name).to.equal('Ada')
})
The observed error was expected undefined to equal 'Ada'. The assignment looks earlier in the file, but it lives inside a callback that has not run when the synchronous expectation executes.
Official behavior: Cypress commands enqueue work and yield subjects during later execution. They do not synchronously return the eventual DOM value. Ordinary JavaScript outside that command flow continues immediately. This is why a local variable is not a synchronization mechanism. How Cypress works
The smallest useful repair is:
it('asserts on the yielded text', () => {
cy.visit('/')
cy.get('[data-cy=name]').should('have.text', 'Ada')
})
Now the expectation participates in Cypress's query/assertion behavior. The repaired test passed against the local page. It also expresses the requirement directly: the name should become Ada, regardless of precisely when the response arrives.
Moving the expectation into .then() can address an early variable read, but it does not make that callback a retrying assertion. If the element already exists with empty text, a one-time callback can inspect it too early. For eventual DOM state, keep the expectation on a retryable query chain. Use .then() when you deliberately need a yielded value for subsequent work after the required state has been established.
An interview explanation should name both defects separately: reading before the queue runs, and reading an unsettled value once. Fixing the first does not automatically fix the second. Avoid an async test full of await cy... as a substitute for understanding the framework's execution model.
What retries, and what runs once?
Official behavior: queries and their assertions can retry together; non-query commands execute once. An action such as a click waits for actionability, then performs the action. A later failing assertion does not mean Cypress continually repeats that click. Whole-test retries are a separate feature that reruns a test attempt. Retry-ability
Our delayed-response check makes that distinction observable:
cy.intercept('GET', '/api/profile', {
delay: 300,
body: { id: 7, name: 'Grace' },
}).as('profile')
cy.visit('/')
cy.get('[data-cy=name]').should('have.text', 'Grace')
cy.wait('@profile').its('response.statusCode').should('eq', 200)
This passed with whole-test retries disabled. The response delay is injected application latency; it is not a fixed sleep in the test. Cypress proceeds when the expected text is available instead of always waiting an arbitrary interval.
The name assertion also protects against a subtle false positive: the network response might say Grace while a broken render path leaves Ada on screen. Conversely, seeing a name alone would not establish that this particular intercepted response had the expected status. Keep both checks when both contracts matter.
Do not put repeated side effects inside a retrying assertion callback. If a check may run several times, it should inspect state rather than submit another form. After an action that can replace DOM nodes, start a fresh query for the resulting state instead of retaining a potentially detached element reference.
Why did the alias wait miss a request that succeeded?
This version intentionally waits until the profile is already rendered before registering the intercept:
cy.visit('/')
cy.get('[data-cy=status]').should('have.text', 'Ready')
cy.intercept('GET', '/api/profile').as('profile')
cy.wait('@profile')
The run timed out waiting for the first request associated with profile. The page had loaded successfully. That observation is not contradictory: the request completed before the route existed. The Ready assertion makes the ordering deterministic rather than relying on a lucky or unlucky race.
Repair the order and keep the UI contract:
cy.intercept('GET', '/api/profile').as('profile')
cy.visit('/')
cy.wait('@profile').its('response.body').should('deep.equal', {
id: 7,
name: 'Ada',
})
cy.get('[data-cy=name]').should('have.text', 'Ada')
This test passed while observing the real local response. Registering before the action that triggers traffic creates the observation window you actually need. Increasing the timeout after registering late would only wait longer for a request that will not happen again.
Official behavior: an intercept can observe or stub matching application traffic. Browser-cache responses may bypass the network layer and therefore bypass an intercept. Check the request method, URL matching, registration timing, and cache behavior before treating every missing alias as the same defect. Intercept reference

In our lab, no-store headers remove caching as the explanation. In an unfamiliar codebase, inspect the actual request before broadening the matcher to every URL. An overly broad alias can satisfy a wait with unrelated traffic and make the test misleadingly green. Likewise, waiting on an alias is evidence about the matched request; it is not a guarantee that the application has finished rendering its consequences.
Why does the second test become a guest?
The broken suite first visited the page, clicked the demo-session button, and verified Signed in as Ada. That setup test passed. The next test visited the page without arranging state and expected the same label. It failed with actual text Guest.
Official behavior: with end-to-end test isolation enabled, Cypress clears cookies, local storage, and session storage between tests and resets the page. This does not reset your server database or every browser storage mechanism; current documentation explicitly distinguishes IndexedDB. Test isolation
The failure exposed a hidden dependency, not a reason to disable isolation. Each test should declare the state it needs. For this toy application, clicking the button in beforeEach would be sufficient. To practice reusable setup, we verified this session-based alternative:
beforeEach(() => {
cy.session('demo-Ada', () => {
cy.visit('/')
cy.get('[data-cy=login]').click()
cy.get('[data-cy=auth]').should('have.text', 'Signed in as Ada')
}, {
validate() {
cy.getAllLocalStorage().should('deep.include', {
'http://127.0.0.1:4187': { 'demo-user': 'Ada' },
})
},
})
cy.visit('/')
})
Two independent tests then asserted the signed-in label. Both passed, and the second also passed when selected alone. That standalone run matters: a suite pass would not by itself disprove an ordering dependency.
Official behavior: cy.session() saves and restores supported browser session state for an identifier. Its setup and validation should establish the intended identity, and navigation remains an explicit part of the test arrangement. Session identifiers must distinguish setups whose saved state differs. Session reference
Our validation checks only the toy local-storage value. In a real authenticated application, a stored token could be expired or rejected by the server. Validate an appropriate authenticated contract rather than copying this demo check unchanged. Also reset or uniquely allocate server-side test data where necessary; browser isolation cannot remove records created by a previous test.
Explain the repair with evidence
Use the observed result to support a precise claim:
| Experiment | Observed result | What the repair establishes |
|---|---|---|
| Synchronous variable read | Undefined instead of Ada | The assertion now waits in the command flow. |
| Intercept after Ready | Alias request timeout | The route exists before the triggering visit. |
| Login inherited from previous test | Guest instead of signed-in text | Each test declares and validates its required demo state. |
| Delayed stub response | Grace rendered; response status 200 | The UI handles this controlled delayed response. |
| Repaired session test alone | Passed | This case does not require its preceding login test. |
These results do not certify a production authentication flow, every browser, or the reliability of a remote backend. They support the narrower claims tested here. The exact code, short timeouts, server contract, and disabled retries make the failures explainable rather than merely anecdotal.
During a practical interview, narrate one hypothesis at a time: “The UI is ready, but the route was registered afterward. I will move registration before navigation, then retain the response and rendered-name assertions.” That explanation connects observation, mechanism, change, and verification without hiding the original requirement.
Continue with these transferable PracHub exercises; they are not presented as a Cypress employer question bank:
| Practice question | Apply this article's reasoning |
|---|---|
| Contrast UI vs backend testing; design UI-change test cases | Separate a rendered-state check from backend integration confidence. |
| Debug an Asynchronous SDK Race Condition with a Customer | Explain an ordering failure using reproducible observations. |
| Validate Unit-Test Coverage and Identify Missing Scenarios | Look for delayed responses and missing-state cases. |
| Fix the Password Reset Workflow | Preserve the user-visible outcome while repairing the workflow. |
| Write good tests and define integration tests | State exactly which collaborators are real or substituted. |
Use Validate Unit-Test Coverage and Identify Missing Scenarios next, and defend one additional assertion that would catch a meaningful regression without adding a fixed wait.
Comments (0)