2

I'm trying to click on a button by the href value, the problem is that the value is variable. See an example below:

<a data-v-1615fd2d data-v-7c46ae33
   href="/app/applications/2774009/applicants/3948813" 
   class="applicant-name btn btn-link obs-link">
</a>

The numbers in the href are different depending on which file I am trying to select. Currently, I am clicking buttons with href using the code below:

await page.click("a[href$='someValue']");

I would like to do something like this:

let applicationLink= "/app/applications/2774271/applicants/3949188";
await page.click("a[href$='${applicationLink}']");

Passing the variable into the page.click function.

But this doesn't seem to work.

I am new to this and don't have much experience. Would love some help. Feel free to ask any questions for clarification.

ggorlen
  • 44,755
  • 7
  • 76
  • 106

2 Answers2

2

If you need to interpolate a variable into a string, you need template literals.

Also, the $ sign before = seems unneeded.

let applicationLink = "/app/applications/2774271/applicants/3949188";

await page.click(`a[href='${applicationLink}']`);
vsemozhebuty
  • 12,992
  • 1
  • 26
  • 26
1

vsemozhebuty is correct that your template literal is missing backticks, but there's a bit more to it potentially so I'll add some minimal examples that might help your case. If they don't, please provide more information about the site you're manipulating.

Specifically, the <a> you show has only whitespace as text. That's not necessarily selectable by Puppeteer as the following snippet shows:

const puppeteer = require("puppeteer");

let browser;
(async () => {
  const html = `
    <a href="/app/applications/2774009/applicants/3948813">
    </a>
  `;
  const applicationLink = "/app/applications/2774009/applicants/3948813";

  browser = await puppeteer.launch();
  const [page] = await browser.pages();
  await page.setContent(html);
  await page.waitForSelector(`a[href$="${applicationLink}"]`, {visible: true});
  await page.click(`a[href$="${applicationLink}"]`);
})()
  .catch(err => console.error(err))
  .finally(async () => await browser.close())
;

The above code throws Error: Node is either not visible or not an HTMLElement on the page.click() call. The reason is that Puppeteer moves the virtual mouse over to the link, then clicks it, but the link is zero width so there's no target to click on.

In the example above, if you add some text content to the <a>, like <a href="...">foo</a>, or add CSS to give it a visible bounding box (minimally, style="width: 2px; height: 2px; position: absolute;"), then page.click() works.

If the element doesn't have text or size, you can still click it by using the browser's native .click() rather than page.click() as follows:

const puppeteer = require("puppeteer");

let browser;
(async () => {
  const html = `
    <a href="/app/applications/2774009/applicants/3948813">
    </a>
    <script>
      document.querySelector("a")
        .addEventListener("click", e => {
          e.preventDefault();
          e.target.innerText = "clicked!";
        })
      ;
    </script>
  `;
  const applicationLink = "/app/applications/2774009/applicants/3948813";

  browser = await puppeteer.launch();
  const [page] = await browser.pages();
  await page.setContent(html);
  await page.waitForSelector(`a[href$="${applicationLink}"]`, {visible: true});
  await page.evaluate(
    link => document.querySelector(`a[href$="${link}"]`).click(), 
    applicationLink
  );
  console.log(await page.$eval("a", el => el.innerText)); // => clicked!
})()
  .catch(err => console.error(err))
  .finally(async () => await browser.close())
;
ggorlen
  • 44,755
  • 7
  • 76
  • 106
  • There is text content in the selector, I forgot to include it. – Hillel Mermelstein Jul 09 '21 at 19:50
  • All right, thanks for clarifying. Did fixing the template literal get you moving? If not, maybe a [mcve] would be helpful or a live URL. – ggorlen Jul 09 '21 at 20:24
  • Yes, i found the issue. Thanks – Hillel Mermelstein Jul 10 '21 at 03:17
  • Great. What was the problem? Maybe post a [self answer](https://stackoverflow.com/help/self-answer) if it was something other than what has already been mentioned to help future visitors. If it was a template string, consider [accepting](https://stackoverflow.com/help/someone-answers) vsemozhebuty's answer. – ggorlen Jul 10 '21 at 03:24