4

I need to run a loop through multiple elements having the same CSS selector and return true if the element.text() matches with the string. If there is no match then return false at the end.
I tried something like below but it didn't work:

getProfilePresentOrNot(profileName) {
  var flag = 0;
  cy.get('li>div>div>span').each(($el,index,$list) => {
    if ($el.text().includes(profileName)) {
      flag=1;
    }
  });
  return flag;
}

This function always returns 0 even though I can confirm that the condition in the if block satisfies.

Richard Matsen
  • 20,671
  • 3
  • 43
  • 77
Akash Jain
  • 53
  • 4
  • 1
    see https://stackoverflow.com/questions/37576685/using-async-await-with-a-foreach-loop – Jeremy Kahan Jun 16 '21 at 06:25
  • @JeremyKahan Yes, Iw ent through it. But since I am a beginner at it, I was not able to understand it and implement it for my use case. Any help to implement it in the code above would really be appreciated. – Akash Jain Jun 16 '21 at 06:41
  • I'm working on it. I have had the same issue in protractor. – Jeremy Kahan Jun 16 '21 at 06:44

1 Answers1

5

@JeremyKahan is correct, it's like mixing synchronous and asynchronous code. The synchronous code always executes first.

Basically, you can see it by adding a couple of console.log()

function getProfilePresentOrNot(profileName) {
  var flag = 0;
  cy.get("li>div>div>span").each(($el, index, $list) => {
    if ($el.text().includes(profileName)) {
      console.log('Setting flag')
      flag = 1;
    }
  });
  console.log('Returning flag')
  return flag;
}

This will print in the devtools

Returning flag
Setting flag                // because cy.get(...).each(...) ran later

You could use a custom command

Cypress.Commands.add('getProfilePresentOrNot', (profileName) => {
  cy.get("li>div>div>span")
    .invoke('text')                                  // all text from all spans
    .then(allText => allText.includes(profileName))  // returns the result of .includes(...)
})

which must be used like this

cy.getProfilePresentOrNot('someprofilename')
  .then(isPresent => {  // true or false
    if (isPresent) {
      ...
    }
  })

or if you are absolutely sure that all li>div>div>span are present in the page, you can still use a function but switch to synchronous Cypress code (i.e jQuery).

function getProfilePresentOrNot(profileName) {
  const allText = Cypress.$("li>div>div>span").text()
  return allText.includes(profileName);
}

which can be called like this

const isPresent = getProfilePresentOrNot('someprofilename')

The custom command is safest because on a production web page there are lots of things that can fail your test because the element can't be found immediately, and Cypress asynchronous commands have built-in mechanisms to avoid the problems.

Richard Matsen
  • 20,671
  • 3
  • 43
  • 77
  • I like your use of the console logs to illustrate the issue. – Jeremy Kahan Jun 16 '21 at 09:48
  • So I am trying to use the second method. After calling the function using const isPresent = getProfilePresentOrNot('someprofilename') how can I ascertain that the value of "isPresent" is "true". I tried using "expect" but I noticed that this line always executes before the "getProfilePresentOrNot" function gets called. – Akash Jain Aug 09 '21 at 07:01