Yield value

Sometimes you might get an error that your test is "mixing up async and sync code". This happens when inside a Cypress chain of commands callback you have a Cypress command and a separate return X statement. Cypress is unsure if you want to yield the value X or the result of the last command.

Let's say you want to find the last name of the person in the DIV below.

<div id="person">Joe Smith</div>

The following code block will cause an error "mixing up async and sync code"

cy.get('#person')
  .invoke('text')
  .then((text) => {
    // INCORRECT: mixing a Cypress command
    // and a return value
    cy.log('text', text)
    return text.split(' ')[1]
  })
  .should('equal', 'Smith')

Async and sync code error

Cypress is unsure which value do you want to yield to the assertion .should('equal', 'Smith') - the result of the Cypress command cy.log? Or the result returned using the return ... statement?

Printing using cy.log can unexpectedly cause an error, because you do not assume it yields a value. But it is a Cypress command, just like cy.wrap. In the test below (which also causes the same error as above), do you expect to yield "Anna" or "Smith"?

cy.get('#person')
  .invoke('text')
  .then((text) => {
    // INCORRECT: mixing a Cypress command
    // and a return value
    cy.wrap('Anna')
    return text.split(' ')[1]
  })
  .should('equal', 'Smith')

Solutions

  1. Move the return statement into its own .then callback
cy.get('#person')
  .invoke('text')
  .then((text) => {
    cy.wrap('Anna').then(() => {
      return text.split(' ')[1]
    })
  })
  .should('equal', 'Smith')
  1. Wrap the value to return using the cy.wrapopen in new window command
cy.get('#person')
  .invoke('text')
  .then((text) => {
    cy.log('text', text)
    cy.wrap(text.split(' ')[1])
  })
  .should('equal', 'Smith')
  1. Print the text using a separate .then callback. If the .then callback returns undefined, then its original value is yielded to the next command by Cypress.
cy.get('#person')
  .invoke('text')
  .should('be.a', 'string')
  .then((text) => {
    return text.split(' ')[1]
  })
  .should('equal', 'Smith')

Tip: you can perform data manipulation steps using cy.invokeopen in new window and cy.itsopen in new window commands

cy.get('#person')
  .invoke('text')
  .should('be.a', 'string')
  .invoke('split', ' ')
  .its(1)
  .should('equal', 'Smith')

To see the same explanation, you can watch the video Fix The Cypress Error "You are mixing async and sync code"open in new window