| name | Puppeteer Browser Automation |
| description | Automate Chrome with Puppeteer for scraping, screenshots, PDF generation, and E2E checks — correct launch options, reliable waiting with locators and waitForSelector, request interception, and headless CI execution. |
| version | 1.0.0 |
| author | thetestingacademy |
| license | MIT |
| tags | ["puppeteer","browser-automation","headless-chrome","scraping","screenshots","pdf","e2e","devtools","ci"] |
| testingTypes | ["e2e"] |
| frameworks | ["puppeteer","jest"] |
| languages | ["typescript","javascript"] |
| domains | ["web"] |
| agents | ["claude-code","cursor","github-copilot","windsurf","codex","aider","continue","cline","zed","bolt","gemini-cli","amp"] |
Puppeteer Browser Automation
This skill makes an AI agent write reliable Puppeteer scripts: launching Chrome with the right flags, navigating and interacting without race conditions, capturing screenshots and PDFs, and intercepting network requests to mock or block traffic. Trigger it when a project uses puppeteer or puppeteer-core, or when the user asks to scrape a page, generate a PDF from HTML, screenshot a site, or automate Chrome without a full test framework.
Core Principles
- Every action must wait for its precondition.
page.click() immediately after page.goto() races against rendering. Use page.locator() (auto-waiting, Puppeteer 21+) or explicit waitForSelector before every interaction.
- Never use fixed sleeps.
await new Promise(r => setTimeout(r, 3000)) is either too short (flaky) or too long (slow). Wait on selectors, network idle, or response predicates instead.
- Always close the browser in
finally. A script that throws before browser.close() leaks a Chrome process. In CI those zombies accumulate until the runner dies.
- Set
waitUntil deliberately. load waits for every image and font; domcontentloaded is enough for interaction; networkidle2 is for SPAs that fetch after load. Pick per page, do not cargo-cult networkidle0.
- Combine navigation-triggering actions with
Promise.all. Clicking a link then awaiting waitForNavigation separately misses fast navigations. Start the wait before the click.
- Request interception is your mock layer. Block analytics and images for speed, stub API responses for determinism — no proxy server needed.
Setup
npm install --save-dev puppeteer typescript tsx
import puppeteer, { Browser } from 'puppeteer';
export async function launchBrowser(): <> {
puppeteer.({
: ,
: [
,
,
,
,
],
: { : , : },
});
}