2

I am looping through a drop down list and I am trying to select individual options. If I try to use a template literal, the querySelector returns null.

Here are two different queries, one with a template literal and one without. I am using back ticks and everything is the same but the first query returns null while the second one returns the right value even though "i" = 2 in this case.

const value = await self.page.evaluate(() => {
              return document.querySelector(`select option:nth-child(${i})`);
});

const value1 = await self.page.evaluate(() => {
              return document.querySelector(`select option:nth-child(2)`);           
});

// Structure
for (let i = 2; i < options.length; i++){

    if (options[i]....){
        const value = await self.page.evaluate((i) => {
             return document.querySelector(`select option:nth-child(${i})`);
            });

    }
}

Why is this happening?

BillTaha
  • 95
  • 1
  • 9

3 Answers3

5

Linked: Puppeteer: pass variable in .evaluate()

You have to pass another argument to page.evaluate to ensure i is in the scope

const value = await self.page.evaluate((i) => {
    return document.querySelector(`select option:nth-child(${i})`);
}, i);
Ben
  • 3,160
  • 3
  • 17
  • 34
3

Since you are passing the function as an argument, the variable i will be out of scope when the function is called. You should pass the value when you are defining the function:

const value = await self.page.evaluate((i) => {
    return document.querySelector(`select option:nth-child(${i})`);
});
Ed Lucas
  • 5,955
  • 4
  • 30
  • 42
  • I tried that as well but i is undefined, I edited in the structure of my code but it is most likely a scope issue. Will look into it – BillTaha Apr 16 '20 at 21:13
  • It looks like you're doing that in the looping code that you added in your edit. – Ed Lucas Apr 16 '20 at 21:17
1

Just in case, it looks like you've chosen a long way around.

If your intention was to extract <option>'s text values into array, you could make use of Document.querySelectorAll():

const [,...options] = [...document.querySelectorAll('select option')].map(option => option.textContent)

console.log(options)
<select>
  <option disabled selected>Select</option>
  <option>first option</option>
  <option>second option</option>
  <option>last option</option>
</select>

p.s. if value of each option is needed, you may simply replace .textContent with .value, if DOM nodes themselves, just skip map()-part

Yevhen Horbunkov
  • 14,965
  • 3
  • 20
  • 42