Home > Software design >  Problems with element.click() in puppeteer
Problems with element.click() in puppeteer

Time:05-11

I got following Problem. If I run this code I get this error message and I cant seem to fix it.

Uncaught Error Error: Evaluation failed: TypeError: Cannot read properties of undefined (reading 'click') at _evaluateInternal (c:\Users\Name\node_modules\puppeteer\lib\cjs\puppeteer\common\ExecutionContext.js:221:19) at processTicksAndRejections (node:internal/process/task_queues:96:5)

const puppeteer = require('puppeteer');
const url = "https://www.zalando.de/nike-sportswear-blazer-mid-77-sneaker-high-ni115n001-a13.html";

async function initBrowser() {
    const browser = await puppeteer.launch({ headless: false });
    const page = await browser.newPage();
    await page.goto(url);
    await page.screenshot({ path: 'example.png' });
    return page;
}
async function addToCart(page) {
    await page.$eval('span[]', element => element.click());
    await page.$$eval('.example', elements => {
        const element = elements.find(element => element.innerHTML === '39');
        element.click();
    });
    await page.$eval('button[]', element => element.click());
}

async function checkout() {
    const page = await initBrowser();
    await addToCart(page);
}


checkout();

CodePudding user response:

You are doing

await page.$$eval('.example')

Not sure if there is any element example and .find is not guaranteed to return any value. Always do if check

const element = elements.find(element => element.innerHTML === '39');

if (element){
 element.click();
}

MDN on find - The find() method returns the first element in the provided array that satisfies the provided testing function. If no values satisfy the testing function, undefined is returned.

CodePudding user response:

This one was pretty tricky. I'm not sure why, but there are some strange visibility and event handling characteristics on the page, so I basically "brute forced" it by trying both trusted and untrusted events for clicks and selection.

For the picker trigger (size select dropdown), I used an untrusted event. Selecting the size worked best with a trusted event, and adding to cart worked with a trusted event. These might not be hard-and-fast rules, so I might have missed something, but the code below should capture a screenshot of the item in the cart.

I was also finding that the cookie banner seems to throw off the dropdown. Waiting and dismissing it improved the reliability of the script, but I eventually commented it out for speed and because it might not be necessary. I didn't do enough runs to say for sure, though, so it's left in the code below.

Here's the code:

const puppeteer = require("puppeteer"); // ^13.5.1

let browser;
(async () => {
  browser = await puppeteer.launch({headless: true});
  const [page] = await browser.pages();
  const ua = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36";
  await page.setExtraHTTPHeaders({"Accept-Language": "en-US,en;q=0.9"});
  await page.setUserAgent(ua);
  const url = "https://www.zalando.de/nike-sportswear-blazer-mid-77-sneaker-high-ni115n001-a13.html";
  await page.goto(url, {waitUntil: "domcontentloaded"});

  // optionally accept the cookie banner
  //const cookie = await page.waitForSelector("#uc-btn-accept-banner");
  //await cookie.evaluate(el => el.click());

  const picker = await page.waitForSelector("#picker-trigger");
  await picker.evaluate(el => el.click());
  await page.waitForFunction(() =>
    [...document.querySelectorAll(".fOd40J._0xLoFW.JT3_zV.FCIprz.LyRfpJ")]
      .find(el => el.innerText === "39")
  );
  const size = await page.evaluateHandle(() =>
    [...document.querySelectorAll(".fOd40J._0xLoFW.JT3_zV.FCIprz.LyRfpJ")]
      .find(el => el.innerText === "39")
  );
  await size.click();
  await page.click(".U4aOaA > .DJxzzA");
  await page.evaluate(() => window.scrollTo(0, 0));
  await page.waitForFunction(() => 
    document.querySelector('a[title="Your bag"]')?.textContent.startsWith("1")
  );
  await page.goto("https://en.zalando.de/cart/");
  await page.screenshot({path: "testing-in-bag.png"});
})()
  .catch(err => console.error(err))
  .finally(() => browser?.close())
;
  • Related