cypresscypress-log

Call cy.log in a .then() callback throws "mixing up async and sync code" error


I am trying to log something in the middle of a Cypress chain of calls:

function geAccountElement() {
    return cy.get('div[ui-id=account]')
        .then(thing => {
            cy.log('Peek at thing: ' + thing);
            return thing;
        })
        .contains(testAccountName)
        .parents('div[ui-id=account-card]')
}

But I am getting this warning:

Command `contains` expects ["element", "cy"] as a previous subject, but "any" is passed from `then` command

How can I make this sort of chainable logging function work?


Update Saturday 23 March 2024, 06:20:04 PM

Turns out I was even more confused. I saw that warning in an IntelliJ tool tip but did not run the test. If I did, I would have seen:

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

In your callback function you invoked 1 or more cy commands but then returned a synchronous value.

What I am trying to do is log the thing in between chained calls. I see I can do this:

cy.get('div[ui-id=account]')
.invoke('val')
.then(thing => {
    cy.log('Peek at thing: ' + thing);
})  

But that's a terminal operation.. meaning the rest of the test stops there. I wanted to try and get some logging happening between get and the contains.


Solution

  • On my test, the error about mixed async and sync code was fixed by wrapping the return value like this:

    cy.visit('https://example.com');
    
    cy.get('h1')
      .then(thing => {
          cy.log('Peek at thing: ' + thing)   // this is an async command
          // return thing                     // this line is the "sync" value complained about
          return cy.wrap(thing)               // wrapping makes it async
      })
      .contains('Example Domain')
    

    enter image description here

    Cypress is not overly smart about this error message, since the cy.log() is just a side effect and has no bearing on the chain subject (i.e return thing is acceptable without the cy.log).

    You can instead swap in the synchronous Cypress.log() call

    cy.get('h1')
      .then(thing => {
          Cypress.log({
            message: 'Peek at thing: ' + thing
          })
          return thing
      })
      .contains('Example Domain')
    

    and make use of other properties for more informative log

    cy.get('h1')
      .then(thing => {
          Cypress.log({
            displayName: 'Peek at thing:',
            message: thing
          })
          return thing
      })
      .contains('Example Domain')
    

    enter image description here