Adrian Szymański
Adrian Szymański

Reputation: 27

Cypress.io how to get length of a array in a before hook, and reuse it later?

  1. My task is to enter the page, get the array length (of the "a" tags) and store it so I can use in in the next step. I need it once, so I do this firstly in before hook.
  2. Forward, I need to get the "a" tags and check if they have a "title" attribute. This case will be looped so many times, as many "a" tags are places on the web-page. Thast why I need the array length.

This is my code, according to the docs this isnt a good practice, docs call this "code doing backflips" but it should work:

    let sizeVar;

before(() => {
    cy.visit("https://web-page");
    cy.get("a").not("[href='']").not("[href='#']").its("length").then((size) => {
        sizeVar = Cypress.$(size);
        return sizeVar;
    });
})

for (let i = 0; i < sizeVar; i++) {
    it(`tag <a> index ${i}`, () => {
        cy.get("a").not("[href='']").not("[href='#']").eq(i).should("have.attr", "title");
    })
}

Unfortunately, it doesnt :( after runing above test in Cypress I have "No tests found in your file. We could not detect any tests in the above file. Write some tests and re-run." What the hell?! The funny fact is that when I will change in the loop the sizeVar for some static number, for example 100, it will work and move smoothly.

for (let i = 0; i < 100; i++)

But I dont need the static number, I need it done in the right way... According to the docs the best way is to use aliases. So I did, this is the code:

before(() => {
    cy.visit("https://web-page");
    cy.get("a").not("[href='']").not("[href='#']").its("length").as("size");
})

for (let i = 0; i < this.size; i++) {
    it(`tag <a> index ${i}`, () => {
        cy.get("a").not("[href='']").not("[href='#']").eq(i).should("have.attr", "title");
    })
}

And again I doesnt work, this time I get "Cannot read property 'size' of undefined". Where am I doing mistake? Please help.

=======================UPDATE===============================

I was thinking about to use pure JS but this not work either... I dont see any wrong logic in my code... But Cypress dont want to pass this variable :(

describe("test", () => {

let links = document.querySelectorAll("a");
let linksLength = links.length;

before(() => {
    cy.visit("https://web-page");
})

for (let i = 0; i < linksLength; i++) {
    it(`tag <a> index ${i}`, () => {
        cy.get("a").not("[href='']").not("[href='#']").eq(i).should("have.attr", "title");
    })
}
})

Upvotes: 1

Views: 3308

Answers (1)

user9161752
user9161752

Reputation:

The problem is the for loop is getting evaluated before any testing starts. You can think of it as a two-pass process, the first pass loads the command queue and the second runs the commands.

Best I can find is to split the logging and the testing by using two sequential .then() clauses.

Test

it('finds external links', () => {

  cy.visit("https://web-page");

  cy.get("a").not("[href='']").not("[href='#']") 
    .then($list => {

      // Get the titles 
      const titles = [...$list].map((el) => Cypress.$(el).attr('title') )

      // Log all their values
      titles.forEach((value, index) => {
        cy.log(`tag <a> index ${index} - title is ${value}`)
      })

      // Pass on to next then()
      return cy.wrap(titles)
    })
    .then(titles => {

      // Test the titles
      expect(titles.every(title => title)).to.equal(true, 'All titles are defined')

    })
})

Result

log tag <a> index 0 - title is 1
log tag <a> index 1 - title is undefined
log tag <a> index 2 - title is 3

AssertionError  All titles are defined: expected false to equal true

HTML fragment tested

<div>
  <a href="link1" title="1">1</a>   // ok
  <a href="link2">2</a>             // fails
  <a href="link4" title="3">3</a>   // ok
  <a href="">4</a>                  // ignored
  <a href="#">5</a>                 // ignored
</div>

Upvotes: 2

Related Questions