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.
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.