Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

Do not await Cypress commands or treat them as native Promises. Cypress queues commands and later yields their subjects through its own chain. Keep dependent work inside that chain: use .then() to consume a subject or wait for a Promise, and use cy.wrap() when you need Cypress to wait for an application Promise. The familiar “mixing up async and sync code” error usually means a .then() callback both queued Cypress commands and returned a separate synchronous value.

Why Cypress commands cannot be awaited

Cypress commands look like function calls, but they do not execute like ordinary JavaScript functions that immediately return a value. Cypress queues commands for later execution and passes their yielded subjects along a managed chain. The Cypress guide describes them as “serial commands passed into a central queue, to be executed asynchronously at a later date.” Cypress: Introduction to Cypress.

This distinction explains common mistakes such as const button = cy.get('button'), await cy.get('button'), or returning a Cypress command from an async test as if it were a native Promise. In each case, JavaScript code is trying to use the result before Cypress has yielded it. Keep the work in Cypress’s chain instead:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
cy.get('button').then(($button) => {
  // $button is available when this callback runs
  expect($button).to.be.visible
})

Use a Cypress alias when a value needs to be referenced later in a test, or pass it from one chained callback to the next. Avoid assigning the command itself to a variable as though that variable contained the eventual subject.

#1 Best Overall
Amazon Basics Wired QWERTY Keyboard, Works with Windows, Plug and Play, Easy to Use with Media Control, Full-Sized, Black
  • KEYBOARD: The keyboard works for Windows with hot keys that enable easy access to Media, My Computer, Mute, Volume up/down, and Calculator
  • EASY SETUP: Experience simple installation with the USB wired connection
  • VERSATILE COMPATIBILITY: This keyboard is designed to work with multiple Windows versions, including Vista, 7, 8, 10 offering broad compatibility across devices.
  • SLEEK DESIGN: The elegant black color of the wired keyboard complements your tech and decor, adding a stylish and cohesive look to any setup without sacrificing function.
  • FULL-SIZED CONVENIENCE: The standard QWERTY layout of this keyboard set offers a familiar typing experience, ideal for both professional tasks and personal use.

Fix “cy.then() failed because you are mixing up async and sync code”

A .then() callback receives the previous subject. It can return a Cypress chain or a Promise, and Cypress waits for that work before continuing. The error occurs when the callback enqueues Cypress commands but also returns a separate, non-null synchronous value. Cypress cannot treat that callback as both queued asynchronous work and a synchronous result. See the Cypress .then() reference.

When the callback returns a Promise

Return the Promise and do not also enqueue Cypress commands in that callback. Cypress waits for the Promise to resolve, and its resolved value becomes the next subject.

cy.get('[data-cy=save]').click().then(() => {
  return apiCall()
}).then((result) => {
  expect(result.status).to.equal('saved')
})

This assumes apiCall() returns a Promise. If it rejects, the test fails unless the rejection is handled deliberately.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

When the callback queues Cypress commands

If the callback’s purpose is to enqueue Cypress commands, do not return an unrelated value from it. For example:

Rank #2
Sale
Logitech MK270 Full Size Wireless Keyboard and Mouse Combo - Black
  • Reliable Plug and Play: The USB receiver provides a reliable wireless connection up to 33 ft (1), so you can forget about drop-outs and delays and you can take it wherever you use your computer
  • Type in Comfort: The design of this keyboard creates a comfortable typing experience thanks to the low-profile, quiet keys and standard layout with full-size F-keys, number pad, and arrow keys
  • Durable and Resilient: This full-size wireless keyboard features a spill-resistant design (2), durable keys and sturdy tilt legs with adjustable height
  • Long Battery Life: MK270 combo features a 36-month keyboard and 12-month mouse battery life (3), along with on/off switches allowing you to go months without the hassle of changing batteries
  • Easy to Use: This wireless keyboard and mouse combo features 8 multimedia hotkeys for instant access to the Internet, email, play/pause, and volume so you can easily check out your favorite sites
cy.get('.user').then(($user) => {
  cy.wrap($user).should('be.visible')
  // Do not return a separate synchronous value here.
})

When you need a value after Cypress commands

Make the value the subject of a Cypress command, or isolate its production in a nested .then() that does not enqueue other Cypress commands. Do not combine a queued command and a separate synchronous return in the same callback. Also note that .then() callbacks are not retried; if an assertion needs Cypress’s automatic retry behavior, put it in .should().

Wait for an application Promise with cy.wrap()

Use cy.wrap(promise) to make an application Promise part of the Cypress chain. Cypress waits for it to resolve, yields the resolved value, and fails the test if the Promise rejects. The Cypress .wrap() reference documents this behavior.

cy.wrap(loadUser()).then((user) => {
  expect(user.name).to.equal('Ada')
})

The call to loadUser() happens immediately while JavaScript evaluates the argument to cy.wrap(). Wrapping its Promise makes Cypress wait for that Promise; it does not postpone calling the function until earlier queued Cypress commands have run.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Defer a Promise-producing call until the chain reaches it

If an asynchronous function depends on UI actions earlier in the chain, invoke it from a callback reached after those actions, then return or wrap its Promise:

Rank #3
Sale
Logitech K120 Full Size Wired Keyboard USB Plug-and-Play Windows - Black
  • All-day Comfort: The design of this standard keyboard creates a comfortable typing experience thanks to the deep-profile keys and full-size standard layout with F-keys and number pad
  • Easy to Set-up and Use: Set-up couldn't be easier, you simply plug in this corded keyboard via USB on your desktop or laptop and start using right away without any software installation
  • Compatibility: This full-size keyboard is compatible with Windows 7, 8, 10 or later, plus it's a reliable and durable partner for your desk at home, or at work
  • Spill-proof: This durable keyboard features a spill-resistant design (1), anti-fade keys and sturdy tilt legs with adjustable height, meaning this keyboard is built to last
  • Plastic parts in K120 include 51% certified post-consumer recycled plastic*
cy.get('button').click()
cy.get('input').type('hello')
cy.get('form').submit().then(() => {
  return bar()
}).then((result) => {
  expect(result).to.equal('done')
})

Here bar() is called when Cypress reaches the callback after the submit command, rather than immediately while the test function is still queuing commands. An equivalent explicit wrapping pattern is cy.get('form').submit().then(() => cy.wrap(bar())).

By contrast, writing cy.wrap(bar()) on a line after a queued click does not make the invocation wait for that click. JavaScript calls bar() at once to produce the Promise; only Cypress’s waiting on the resulting Promise is managed by cy.wrap().

Return custom Promises from the chain

When custom asynchronous work must finish before the next Cypress command, return its Promise from .then(). Cypress also exposes Cypress.Promise, its bundled Bluebird implementation, for cases where you need to construct a Promise using Cypress’s bundled utility. The Cypress.Promise reference covers Promise handling and unhandled rejections.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
cy.get('[data-cy=refresh]').click().then(() => {
  return new Cypress.Promise((resolve) => {
    setTimeout(() => resolve('ready'), 100)
  })
}).then((status) => {
  expect(status).to.equal('ready')
})

For an unhandled rejected test Promise, Cypress documents handling it with Cypress.Promise.onPossiblyUnhandledRejection(...) or a test-window unhandledrejection listener. Prefer handling expected failures at the operation that can reject; do not silence an unexpected rejection merely to make a test pass.

Rank #4
Redragon K521 Upgrade Rainbow LED Gaming Keyboard, 104 Keys Wired Mechanical Feeling Keyboard with Multimedia Keys, One-Touch Backlit, Anti-Ghosting, Compatible with PC, Mac, PS4/5, Xbox
  • 【Dreamy Rainbow Gaming Keyboard】K521 Gaming Keyboard Adopts a Different LED Backlight Design, Upgraded on the Traditional LED Backlight Effect, Making the Light More Penetrating, Giving You a More Dazzling Visual Effect, Making Your Gaming Process More Enjoyable
  • 【One Touch Opens & Visual Feast】The K521 Red Dragon Keyboard has a One-Touch on/off Lighting Button for Added Convenience. It also has a Three-Position Adjustable Breathing Mode and a Four-Position Adjustable Brightness Lighting Mode
  • 【Mechanical Feeling & Fast Tapping】The PC Keyboard Keys are Designed for Mechanical Feeling, Giving You a Better Feel During Use and the Ability to Trigger Keys Quickly, Allowing You to Win All Your Games
  • 【19 Keys Anti-Ghosting Keyboard】Anti-Ghosting Ensures Every Button Can Be Triggered. This Allows You to Trigger Key Combinations In The Game Accurately, And Each Skill Can Be Accurately Released to Increase Your Winning Rate. Redragon K521 Will Be Your Perfect Partner
  • 【12 Multimedia Combination Keys】The K521 Wired Gaming Keyboard is Equipped with 12 Multimedia Keys That Can Greatly Enhance Your Gaming/Office Efficiency and Make It More Convenient to Use

Use .then(), not .invoke(), for Promise-returning methods

The current Cypress .invoke() reference says it throws if the invoked function returns a Promise and directs users to .then() instead. Wrap the service as a subject and call the method inside the callback so you can return its Promise:

cy.wrap(service)
  .then((svc) => svc.asyncMethod())
  .should((result) => {
    expect(result).to.equal('ready')
  })

The Promise returned by asyncMethod() is returned from .then(), so Cypress waits for it before passing its resolved value onward.

Keep Cypress commands out of .should() callbacks

Cypress retries a .should() callback while its assertions have not yet passed. It prohibits invoking Cypress commands inside that callback, because retried actions could be queued repeatedly. The Cypress .should() reference explains this boundary.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
// Keep the action in the chain; use should only for the assertion.
cy.get('[data-cy=save]').click()
cy.get('[data-cy=status]').should('have.text', 'Saved')

Use .then() for one-time processing or to enqueue follow-up Cypress commands; use .should() for assertions that benefit from retrying.

Best Value
Sale
Logitech K270 Full Size Wireless Keyboard for Windows - Black
  • All-day Comfort: This USB keyboard creates a comfortable and familiar typing experience thanks to the deep-profile keys and standard full-size layout with all F-keys, number pad and arrow keys
  • Built to Last: The spill-proof (2) design and durable print characters keep you on track for years to come despite any on-the-job mishaps; it’s a reliable partner for your desk at home, or at work
  • Long-lasting Battery Life: A 24-month battery life (4) means you can go for 2 years without the hassle of changing batteries of your wireless full-size keyboard
  • Simply plug the USB receiver into a USB port on your desktop, laptop or netbook computer and start using the keyboard right away without any software installation
  • Simply Wireless: Forget about drop-outs and delays thanks to a strong, reliable wireless connection with up to 33 ft range (5); K270 is compatible with Windows 7, 8, 10 or later
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Choose the right pattern for the value and timing

What you have or need Use Key rule
A Cypress subject such as an element .then() or an alias Consume the yielded subject in the chain; the command itself is not the subject.
An application Promise that can start now cy.wrap(promise) The function producing it is called immediately; Cypress waits for the Promise.
A Promise-producing function that depends on earlier UI work Call and return it in a later .then() That defers invocation until Cypress reaches that point in the queue.
A Promise-returning object method .then((object) => object.method()) Return the Promise; do not use .invoke() for that method.
An assertion that should be retried .should() Keep Cypress commands and actions outside its callback.
A one-time side effect or value transformation .then() Do not expect its callback to retry; avoid mixing queued commands with a separate synchronous return.

Troubleshoot the common failure modes

  • “I awaited cy.get() but got the wrong value.” Cypress commands are not native Promises. Remove await and move the dependent logic into .then(), or use an alias for a value needed later.
  • “The test throws the async/sync mixing error.” Inspect the specific .then() callback: if it queues Cypress commands, remove its separate synchronous return. If it returns a Promise, return that Promise rather than mixing in Cypress commands.
  • “The wrapped Promise ran before my click or typing.” The Promise-producing function was invoked while the test was enqueuing commands. Invoke it in a callback after the prerequisite Cypress commands, then return its Promise.
  • “.invoke() rejects my async method.” Replace it with .then((subject) => subject.method()), returning the method’s Promise.
  • “My assertion is intermittent or never retries.” A .then() callback runs once. Put retryable assertions in .should(); keep commands out of the .should() callback itself.
  • “The test proceeds before custom work completes.” Ensure the callback returns the Promise, including when creating it with Cypress.Promise. An unreturned Promise is not the work Cypress is being asked to await.

Or skip the browser setup

If your Cypress workflow also needs an external website screenshot—for example, a capture outside the test’s own browser session—you can request one from ScreenshotNeo with a single GET call. This is an optional screenshot service, not a fix for Cypress command/Promise mixing, and it does not replace Cypress’s chain for controlling your app.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

See the ScreenshotNeo API documentation for request options. ScreenshotNeo accepts cookie or consent banners before capture and removes 60+ known consent platforms, newsletter popups and chat widgets; each cleanup step can be turned off. Bot checks, blank pages, timeouts, failed loads and cache hits are not billed, and responses report page verdict and billing headers. It also provides an MCP server with take_screenshot, get_page_info and capture_pdf tools for AI agents. The Free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000. See ScreenshotNeo for product details, or sign up free.

Keep the mental model simple

Ask four questions when an async Cypress test misbehaves: Is this value a Cypress-yielded subject or a native Promise? Is the function being invoked now or later in the command queue? Does the assertion need retrying? What value should the next command receive? Answering those questions usually identifies whether the fix belongs in .then(), cy.wrap(), or .should().

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Frequently Asked Questions

Does Cypress support async test functions?

Cypress commands should not be awaited as native Promises. You can still use native asynchronous work when its Promise is returned from the Cypress chain, such as from a .then() callback.

What happens if a Promise passed to cy.wrap() rejects?

Cypress treats the rejection as a test failure unless the rejected Promise is handled.

Quick Recap

Bestseller No. 1
SaleBestseller No. 3
Logitech K120 Full Size Wired Keyboard USB Plug-and-Play Windows - Black
Logitech K120 Full Size Wired Keyboard USB Plug-and-Play Windows - Black
Plastic parts in K120 include 51% certified post-consumer recycled plastic*; Product carbon footprint: 4.02 kg CO2e
$12.34
SaleBestseller No. 5
Logitech K270 Full Size Wireless Keyboard for Windows - Black
Logitech K270 Full Size Wireless Keyboard for Windows - Black
Plastic parts in K270 include 38% certified post-consumer recycled plastic; Eight hot keys: For instant access to the Internet, e-mail, music volume and more
$23.99

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.