javascriptnode.jspuppeteerpuppeteer-extra-plugin-stealth

Puppeteer-extra, TimeoutError doesn't seem to exist


This is a followup question to this one, which resolves a missing definition of TimeoutError in my puppeteer code. Thing is, I want to use puppeteer-extra, and despite being a lightweight wrapper for puppeteer it seems to be causing a difficulty in getting hold of TimeoutError. Here's an SSCCE that should demonstrate the problem; I get TypeError: Right-hand side of 'instanceof' is not an object. My package.json states version 23.7.1 (I have no idea what version of puppeteer-extra I'm running as I don't know where to look).

const puppeteer = require("puppeteer-extra");

let browser;
(async () => {
  const stealthPlugin = require('puppeteer-extra-plugin-stealth');
  puppeteer.use(stealthPlugin());

  browser = await puppeteer.launch();
  const [page] = await browser.pages();

  try {
    await page.goto("https://www.example.com", {timeout: 1}); // short timeout to force a throw
  }
  catch (err) {
    if (err instanceof puppeteer.TimeoutError) {
      console.log("caught timeout error", err);
    }
    else {
      console.log("caught non-timeout error", err);
    }
  }
})()
  .catch(err => console.log(err))
  .finally(() => browser?.close());
  

(I'm using console.log() instead of console.error() because my client code can't get hold of anything in the error stream)

Edit: in response to a comment, here is the entire content of my package.json file -- I regret that it says nothing about puppeteer-extra :(

{
  "name": "puppeteer-project",
  "version": "1.0.0",
  "description": "Puppeteer Project",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "puppeteer": "^23.7.1"
  }
}

Edit 2: have found what seems to be the version numbers for various puppeteer-extra components:

puppeteer-extra: 3.3.6
puppeteer-extra-plugin: 3.2.3
puppeteer-extra-plugin-stealth: 2.11.2
puppeteer-extra-plugin-user-data-dir: 2.4.1
puppeteer-extra-plugin-user-preferences: also 2.4.1

Edit 3: in an attempt to solve this have modified the code in answer 1 below so that instead of only importing TimeoutError we import all of puppeteer (note, the puppeteer version number is different from that in answer 1):

const pupbasic = require("puppeteer"); // ^23.7.1
const puppeteer = require("puppeteer-extra"); // ^3.3.6
const stealthPlugin = require("puppeteer-extra-plugin-stealth"); // ^2.11.2
puppeteer.use(stealthPlugin());

let browser;
(async () => {

  browser = await puppeteer.launch();
  const [page] = await browser.pages();

  try {
    await page.goto("https://www.example.com", {timeout: 1}); // short timeout to force a throw
  }
  catch (err) {
    if (err instanceof pupbasic.errors.TimeoutError) {
      console.log("caught timeout error", err);
    }
    else {
      console.log("caught non-timeout error", err);
    }
  }
})()
  .catch(err => console.log(err))
  .finally(() => browser?.close());

...and once again I get the TypeError: Cannot read properties of undefined (reading 'TimeoutError') error. I may be completely lacking in javascript experience (and unable to find the relevant source files to actually start grubbing through them) but it really escapes me why I can import TimeoutError and have it be recognised by the system (setting aside for a moment the issue that it's not working correctly -- see comment below answer 1), but can't import standard puppeteer and then successfully get inside it. Is there some syntax that I'm missing here?

In case it makes a difference, I actually seem to have two versions of puppeteer on my system. The package.json inside my project's folder says 23.7.1, but the one inside node-modules/puppeteer, in my home folder, says 23.9.0. I assume I'm running the latter, despite what the project's package.json says??? Does this possibly make a difference?

Grateful thanks for any help resolving this! I really am stumbling around in the dark here.


Solution

  • I don't see offhand that puppeteer-extra 3.3.6 exports TimeoutError, but you can import it from vanilla Puppeteer, installed alongside puppeteer-extra:

    const {TimeoutError} = require("puppeteer"); // ^24.11.1
    const puppeteer = require("puppeteer-extra"); // ^3.3.6
    const stealthPlugin = require("puppeteer-extra-plugin-stealth"); // ^2.11.2
    puppeteer.use(stealthPlugin());
    
    let browser;
    (async () => {
      browser = await puppeteer.launch();
      const [page] = await browser.pages();
    
      try {
        await page.goto("https://www.example.com", {timeout: 1}); // short timeout to force a throw
      }
      catch (err) {
        if (err instanceof TimeoutError) {
          console.error("caught timeout error", err);
        }
        else {
          console.error("caught non-timeout error", err);
        }
      }
    })()
      .catch(err => console.error(err))
      .finally(() => browser?.close());
    

    Or use the following if you want a namespace:

    const vanillaPuppeteer = require("puppeteer");
    
    console.log(vanillaPuppeteer.TimeoutError);
    

    A workaround that doesn't involve adding an import is to use if (error.name === "TimeoutError"), but this isn't type safe. This may be suitable for a small script though.