2

I installed Puppeteer and want to query a selector to work on it. But I have encountered a TypeError: selector.startsWith is not a function error.

I tried to fix it by changing core code by adding toString() but it didn't work.

Here are the two expressions I've tried:

await page.$eval('#firstName', elem => elem.click());
await page.waitForSelector('#firstName');

Both did not work and created same error.

I also tried to install old puppeteer and node versions but its still same. How can I solve this problem?

All error log information is:

file:///C:/Users/User/Desktop/mail/node_modules/puppeteer-core/lib/esm/puppeteer/common/GetQueryHandler.js:51
                if (selector.startsWith(prefix)) {
                             ^

TypeError: selector.startsWith is not a function
    at getQueryHandlerAndSelector (file:///C:/Users/User/Desktop/mail/node_modules/puppeteer-core/lib/esm/puppeteer/common/GetQueryHandler.js:51:30)
    at CDPElementHandle.$ (file:///C:/Users/User/Desktop/mail/node_modules/puppeteer-core/lib/esm/puppeteer/common/ElementHandle.js:74:51)
    at IsolatedWorld.$ (file:///C:/Users/User/Desktop/mail/node_modules/puppeteer-core/lib/esm/puppeteer/common/IsolatedWorld.js:126:25)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async IsolatedWorld.focus (file:///C:/Users/User/Desktop/mail/node_modules/puppeteer-core/lib/esm/puppeteer/common/IsolatedWorld.js:186:24)
    at async file:///C:/Users/User/Desktop/mail/index.js:17:5

My full code example to produce same error is:

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch({headless: false});
  const context = await browser.createIncognitoBrowserContext();
  if (context) {
    const page = await browser.newPage();

    await page.goto('https://accounts.google.com/signup/v2/webcreateaccount?biz=false&cc=TR&dsh=S-519439412%3A1682412535258329&flowEntry=SignUp');
  
    // Set screen size
    await page.setViewport({width: 1080, height: 1024});
    //await page.$eval('#firstName', elem => elem.click());
    const username = await page.waitForSelector('#firstName');
    await page.focus(username)
    await page.keyboard.type('test54')
  }

})();
ggorlen
  • 44,755
  • 7
  • 76
  • 106
bugracetin
  • 107
  • 9
  • This looks fine to me. Can you share a runnable [mcve]? Thanks. Usually this is caused by passing a non-string to `page.$eval` or similar functions but that doesn't appear to be the case here. – ggorlen Apr 25 '23 at 16:24
  • I have added a runnable code to my question @ggorlen. Thanks in advance. – bugracetin Apr 26 '23 at 07:47
  • Thanks, that clarifies it. I've updated my answer. BTW, I'd remove or adjust the code after "Here are the two expressions I've tried: " which doesn't seem relevant, since those lines are totally fine. – ggorlen Apr 26 '23 at 15:36

2 Answers2

2

You need to pass a string for the first argument of any function like page.focus(selector). The argument selector is the CSS or Puppeteer selector you want to take action on.

In your code below, you're passing an ElementHandle rather than a string:

const username = await page.waitForSelector('#firstName');
await page.focus(username);

This throws because ElementHandles don't have .startsWith methods.

There are two possible solutions:

const username = await page.waitForSelector('#firstName');
await page.focus('#firstName'); // pass a string

Or, since you already have the element handle:

const username = await page.waitForSelector('#firstName');
await username.focus(); // call .focus() on the ElementHandle

For future vistors' sake, here are some common calls to Puppeteer selector functions that also cause the same error:

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

let browser;
(async () => {
  browser = await puppeteer.launch({headless: "new"});
  const [page] = await browser.pages();
  await page.setContent("<p>hi</p>");

  /* any of the following lines throws */

  // ElementHandle
  const handle = await page.$("p");
  await page.focus(handle)
    .catch(err => console.error(err.message, "(handle)"));

  // Promise
  await page.focus(new Promise((res, rej) => {}))
    .catch(err => console.error(err.message, "(promise)"));

  // number
  await page.waitForSelector(42)
    .catch(err => console.error(err.message, "(number)"));

  // func
  await page.$$eval(() => {})
    .catch(err => console.error(err.message, "(func)"));

  // object
  await page.$eval({})
    .catch(err => console.error(err.message, "(object)"));

  // array
  await page.$(["#first-name"])
    .catch(err => console.error(err.message, "(array)"));

  // boolean
  await page.$$(true)
    .catch(err => console.error(err.message, "(boolean)"));

  // null
  await page.click(null)
    .catch(err => console.error(err.message, "(null)"));

  // undefined
  await page.$()
    .catch(err => console.error(err.message, "(undefined)"));
})()
  .catch(err => console.error(err))
  .finally(() => browser?.close());

Output:

selector.startsWith is not a function (handle)
selector.startsWith is not a function (promise)
selector.startsWith is not a function (number)
selector.startsWith is not a function (func)
selector.startsWith is not a function (object)
selector.startsWith is not a function (array)
selector.startsWith is not a function (boolean)
Cannot read properties of null (reading 'startsWith') (null)
Cannot read properties of undefined (reading 'startsWith') (undefined)

Puppeteer offers custom query selectors like "text/foobar" and "pierce/p". The API at the current time starts by optimistically checking for the presence of one of these prefixes using .startsWith, which is a property that only exists on strings.

One way to avoid this error is to use TypeScript. Otherwise, check the Puppeteer docs for the method you're trying to call to make sure you're passing the appropriate type.


Unrelated, but await browser.newPage(); should be await context.newPage(); if you want to use the context you created.

ggorlen
  • 44,755
  • 7
  • 76
  • 106
1

You need to click the selector #firstName so just change

await page.focus(username);

to

await username.click();

that will solve the error, also if you want to use incognito, then

const page = await browser.newPage();

should be

const page = await context.newPage();
idchi
  • 761
  • 1
  • 5
  • 15