I'm facing a seriously weird issue with puppeteer, running on Chrome.
I have an array of click actions I want to execute on a webpage, which has a pdf.js based slideshow. Each action consists of information on whether you are navigating to the next or previous slide, and what is the delay of said action in milliseconds. I'm also recording the whole thing.
The problem is that for some reason the first action is always immediately executed regardless of delay. Actions after the first behave as expected.
Things I have tried to no success:
- Awaiting a timeout between actions.
- Trying to click with vanilla JS using page.evaluate and waiting inside.
- Using the built-in delay arg of puppeteer click() function and awaiting the actions
- Firing random click event before the actual events
- Updating puppeteer to its latest version
- Putting random extra actions at the beginning of the actions array
- Putting a hardcoded delay value into the click
Now I'm wondering that could this be a bug with puppeteer or chromium itself?
Below the current code
export const makeSlideshowVideo = async (
output_file: string,
actions: slide_change[],
url: string,
webcamLength: number
) => {
try {
const executablePath = await chromium.executablePath(
"https://my-cdn.s3.eu-north-1.amazonaws.com/chromium-v132.0.0-pack.tar"
);
const browser = await puppeteer2.launch({
executablePath,
args: [
`--window-size=${VIDEO_WIDTH},${VIDEO_HEIGHT}`,
"--no-sandbox",
"--disable-setuid-sandbox",
"--disable-gpu", // Disable GPU hardware acceleration
"--disable-dev-shm-usage", // Use /tmp instead of /dev/shm
"--no-zygote", // Disable zygote process for sandboxing
// We have to disable security features, so that the browser can load pdf.js from CDN
// TODO: this is not a safe solution, but might be the fastest fix for now.
"--disable-web-security",
"--allow-running-insecure-content",
],
defaultViewport: { width: VIDEO_WIDTH, height: VIDEO_HEIGHT },
});
const page = await browser.newPage();
await page.goto(url);
// Wait for the slideshow to load
await sleep(2000);
const prevBtn = await page.$("#prev");
const nextBtn = await page.$("#next");
if (!prevBtn || !nextBtn) {
throw new Error("No buttons found on the page");
}
// Set up the screen recorder
const recorder = new PuppeteerScreenRecorder(page, recordConfig);
await recorder.start(output_file);
let prev = actions[0];
await sleep(prev.elapsed_millisec);
for (const next of actions) {
const delay = next.elapsed_millisec - prev.elapsed_millisec;
if (next.change_event === change_event.NEXT) {
await nextBtn.click({ delay: delay });
} else {
await prevBtn.click({ delay: delay });
}
prev = next;
}
await sleep(webcamLength - (prev?.elapsed_millisec ?? 0));
await recorder.stop();
return output_file;
} catch (error) {
console.error((error as Error).message);
}
};
Thank for the help!
EDIT
Another non-working version of the code, without sleeping:
export const makeSlideshowVideo = async (
output_file: string,
actions: slide_change[],
url: string,
webcamLength: number
) => {
try {
const executablePath = await chromium.executablePath(
"https://my-cdn.s3.eu-north-1.amazonaws.com/chromium-v132.0.0-pack.tar"
);
const browser = await puppeteer2.launch({
executablePath,
args: [
`--window-size=${VIDEO_WIDTH},${VIDEO_HEIGHT}`,
"--no-sandbox",
"--disable-setuid-sandbox",
"--disable-gpu", // Disable GPU hardware acceleration
"--disable-dev-shm-usage", // Use /tmp instead of /dev/shm
"--no-zygote", // Disable zygote process for sandboxing
// We have to disable security features, so that the browser can load pdf.js from CDN
// TODO: this is not a safe solution, but might be the fastest fix for now.
"--disable-web-security",
"--allow-running-insecure-content",
],
defaultViewport: { width: VIDEO_WIDTH, height: VIDEO_HEIGHT },
});
const page = await browser.newPage();
await page.goto(url);
// Wait for the slideshow to load
await sleep(2000);
const prevBtn = await page.$("#prev");
const nextBtn = await page.$("#next");
if (!prevBtn || !nextBtn) {
throw new Error("No buttons found on the page");
}
// Set up the screen recorder
const recorder = new PuppeteerScreenRecorder(page, recordConfig);
await recorder.start(output_file);
let prev = null;
for (const next of actions) {
const delay = next.elapsed_millisec - (prev?.elapsed_millisec ?? 0);
if (next.change_event === change_event.NEXT) {
await nextBtn.click({ delay: delay });
} else {
await prevBtn.click({ delay: delay });
}
prev = next;
}
await sleep(webcamLength - (prev?.elapsed_millisec ?? 0));
await recorder.stop();
return output_file;
} catch (error) {
console.error((error as Error).message);
}
};
next.elapsed_millisec - prev.elapsed_millisecthis is zero for the first iteration.next.elapsed_millisec.actions[0].elapsed_millisecis zero you could also get the problem you describe.