Q11 of 48 · Cypress

How does Cypress handle async behaviour without async/await?

CypressJuniorcypressasynccommand-queuefundamentals

Short answer

Short answer: Cypress queues commands synchronously into an internal command queue, then executes them asynchronously in order. `cy.get(...).click()` doesn't return a promise — it enqueues two commands. You never `await` Cypress commands; the framework manages the queue for you.

Detail

In normal JS, async behaviour requires async/await or .then chains. Cypress avoids this with a queue model. Each Cypress command (cy.get, cy.click, cy.intercept) doesn't do anything immediately — it adds an entry to a queue. After your test function returns, Cypress drains the queue, executing each command in order, waiting for the previous one to complete.

This is why your tests look synchronous despite the runtime being async:

cy.visit('/login');
cy.get('input[name=email]').type('alice@x.com');
cy.get('button').click();
// All three are queued instantly; Cypress runs them in sequence.

The implication for getting values out of Cypress: you can't const text = cy.get('h1').text(). Use .then(($el) => { ... }) to access the resolved value:

cy.get('h1').then(($el) => {
  const text = $el.text();
  expect(text).to.include('Welcome');
});

Mixing real async (e.g., fetch from your test) with Cypress commands is risky — they run on different timelines. Wrap genuine promises with cy.wrap(promise) to fold them into Cypress's queue.

Don't add async to your it callback. Cypress recognises the queue model and ignores returned promises in a way that surprises most people.

// WHAT INTERVIEWERS LOOK FOR

Knowing the command queue exists, that commands are enqueued not executed, and the consequence: never `await` Cypress and use `.then` to read values.

// COMMON PITFALL

Adding `async` to `it` callbacks or trying to `await cy.get(...)` — both fight the framework instead of using it.