0

I have a function:

const tableData = await page.evaluate(() => {
 const tds = Array.from(document.querySelectorAll('table tbody tr td'))
 for (var i = 0; i < tds.length; i++) {
 ...
 ...
  availableDates.push([i,dateString,day])
 }
 return availableDates
}

and this function cycles all cells of a table and I filter based on some conditions some dates out of there.

So far so good. The cells contain a href which I want to click. The array holds the number of the cell which I want to click on the first array item and so I have tried:

await page.focus('table tbody tr td:nth-child('+tableData[0][0]+') a' )
    await page.keyboard.type('\n');

but without luck. I get the following error message:

(node:81325) UnhandledPromiseRejectionWarning: Error: No node found for selector: table tbody tr td:nth-child(109) a
.......

What must I change? Thanks.

Tino
  • 3,340
  • 5
  • 44
  • 74

2 Answers2

1

That's not how CSS selectors work. You can't do td:nth-child(109) and expect elements in different table rows to be picked. I'd try using .click(), either via page.click or page.evaluate(() => element.click);

Typing \n seems like a wrong directior, explicitly calling click - that'd be my advice.

Api for page.click: https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#pageclickselector-options

When it comes to actually finding the right cell, I'd go with helper array in a higher scope (closure), add everything there (single dimensional array) and then you can reference them via number, such as you tried with nth-child approach.

wopolow
  • 365
  • 4
  • 16
1

This will not work because, let my explain why:

You have 2 tables.

  • Table 1 has 3 tds.
  • Table 2 has 2 tds.

Now, if you do $('table td:nth-child(2)') which will mean Table 1s 2nd td, also Table 2s 2nd td.


You can probably do 2 things,

  1. While traversing the dom elements, add a data attribute to the elements and select it using that data attribute.

    const tableData = await page.evaluate(() => {
      const tds = Array.from(document.querySelectorAll('table tbody tr td'))
      for (var i = 0; i < tds.length; i++) {
        // ...
        tds[i].setAttribute('data-td-index', i);
        // ...
        availableDates.push([i, dateString, day])
      }
      return availableDates;
    }
    

    Then, use that data attribute.

    await page.focus('table tbody tr td[data-td-index='+tableData[0][0]+'] a' )
    
  2. Using one of the solutions here get thee unique selector of the DOM element and save it in the availableDates i.e availableDates.push(i, uniqPath, dateString, day). Then use it like:

    await page.focus(`${tableData[0][0]} a`)
    
Aritra Chakraborty
  • 12,123
  • 3
  • 26
  • 35
  • I like the idea of setting an attribute, but when calling the page.focus it throws this error: UnhandledPromiseRejectionWarning: Error: Evaluation failed: DOMException: Failed to execute 'querySelector' on 'Document': 'table tbody tr td:[data-td-index=29] a' is not a valid selector. – Tino Oct 26 '19 at 16:18
  • aha! sorry there shouldn't be any colon `:` between `td` and `[`. Edited the post – Aritra Chakraborty Oct 26 '19 at 16:54