Nestor
Nestor

Reputation: 8384

How to return result from Cypress function after set

I have the following code:

function getValues(date)
{
  let totalValue=-10;
  cy.visit('http://localhost/page1');  
  cy.get(".total").then((span)=> 
  {
    console.log("Values: "+span.text())
    totalValue=span.text()        
  }
  )
  //.then(()=> totalValue);
  return totalValue;
}

I would like to get the value of the element so I use this:

it('Testing values',()=>
{
  var totalValues=getValues(startDate)
  console.log("Total values: "+ totalValues)
}

Unfortunately, it never waits for the variable to be set.

Either I get this -10 (when I use the return) or undefined (when I use then) as results and the order is incorrect:

Total values: -10

Values: 2.5

How could I force the execution to wait until the correct value is set?

Upvotes: 0

Views: 589

Answers (3)

You can use an alias to store the value, but as already mentioned you have to access with .then() in the test

function getValues(date) {
  let totalValue = -10;
  cy.visit('http://localhost/page1');  
  cy.get(".total")
    .then((span) => { 
      totalValue = span.text()
      cy.wrap(totalValue).as('totalValues')  // set alias value, 
                                             // must be inside .then()
    })  
}

it('Testing values', () => {
  getValues(startDate)
  cy.get('@totalValues').then(totalValues => {
    console.log("Total values: "+ totalValues)
  })
})

Exception to using .then()

You can use before() block in conjunction with alias to avoid using .then(), but it's a specific pattern.

function getValues(date) {
  let totalValue = -10;
  cy.visit('http://localhost/page1');  
  cy.get(".total")
    .then((span) => { 
      totalValue = span.text()

      // will put totalValue on the "this" scope
      cy.wrap(totalValue).as('totalValues')  
    })  
}

before(() => {
  getValues(startDate)  // calling in before hook resolves all asynchronous calls
})

it('Testing values', function() {           // must use a function() format 
   
  // your value is a property of "this"
  console.log("Total values: " + this.totalValues)  

})

Upvotes: 3

jjhelguero
jjhelguero

Reputation: 2555

The mixture of async(cypress) and sync code is the reason for the wrong order of logging.

In the scope of what you shared, here is what you can use to have the logging in the correct order. I'm not sure where the startDate or where else you plan on using or the html you'll use the getValues() function.

Here is the spec file.

<div class="total">2.5</div>
function getValues(date) {
  let totalValue = -10
  return cy
    .get(".total")
    .invoke("text")
    .then((value) => cy.log("Value: " + value))
}

getValues().then((totalValues) => {
  cy.log("Total values: " + totalValues)
})

Upvotes: 0

Fody
Fody

Reputation: 31974

With a plain JS function, return the last internal command and use .then() on the return value.

function getValues(date) {
  cy.visit('http://localhost/page1');  
  return cy.get(".total").then((span) => span.text())
}

it('Testing values', () => {
  getValues(startDate).then(totalValues => {
    console.log("Total values: "+ totalValues)
  })
})

Or create a custom command

Cypress.Commands.add('getValues', (date) => {
  cy.visit('http://localhost/page1');  
  cy.get(".total").then((span) => span.text())  // does not need an explicit return
})

it('Testing values', () => {
  cy.getValues(startDate).then(totalValues => {
    console.log("Total values: "+ totalValues)
  })
})

If you want var totalValues = ... in the test, there's no way to do it. You always need a .then() because the value is obtained asynchronously.

Upvotes: 2

Related Questions