Puppeteer — Advanced Patterns & Playbook
Page Object Pattern
class LoginPage {
constructor(page) { this.page = page; }
async navigate() { await this.page.goto('/login', { waitUntil: 'networkidle0' }); }
async login(email, password) {
await this.page.type('#email', email);
await this.page.type('#password', password);
await Promise.all([
this.page.waitForNavigation({ waitUntil: 'networkidle0' }),
this.page.click('#submit')
]);
}
async getError() {
await this.page.waitForSelector('.error', { visible: true });
return this.page.$eval('.error', el => el.textContent);
}
}
Network Interception
// Mock API responses
await page.setRequestInterception(true);
page.on('request', request => {
if (request.url().includes('/api/users')) {
request.respond({
status: 200,
contentType: 'application/json',
body: JSON.stringify([{ id: 1, name: 'Alice' }])
});
} else {
request.continue();
}
});
// Log network requests
const requests = [];
page.on('request', req => requests.push({ url: req.url(), method: req.method() }));
page.on('response', res => {
const match = requests.find(r => r.url === res.url());
if (match) match.status = res.status();
});
Performance & Tracing
// Performance metrics
await page.goto(url);
const metrics = await page.metrics();
console.log(`JS Heap: ${(metrics.JSHeapUsedSize / 1024 / 1024).toFixed(1)} MB`);
console.log(`DOM Nodes: ${metrics.Nodes}`);
// Chrome DevTools Protocol tracing
await page.tracing.start({ path: 'trace.json', categories: ['devtools.timeline'] });
await page.goto(url);
await page.tracing.stop();
// Coverage
await page.coverage.startJSCoverage();
await page.goto(url);
const coverage = await page.coverage.stopJSCoverage();
const usedBytes = coverage.reduce((acc, entry) => {
return acc + entry.ranges.reduce((sum, range) => sum + range.end - range.start, 0);
}, 0);
PDF & Screenshot Generation
// Full page screenshot
await page.screenshot({ path: 'full-page.png', fullPage: true });
// Element screenshot
const element = await page.$('.hero-section');
await element.screenshot({ path: 'hero.png' });
// PDF generation
await page.pdf({
path: 'report.pdf', format: 'A4',
margin: { top: '1cm', bottom: '1cm' },
printBackground: true
});
Anti-Patterns
- ❌
page.waitForTimeout(5000) — use waitForSelector, waitForNavigation, or waitForFunction
- ❌
page.click() without waiting for navigation — use Promise.all([waitForNav, click])
- ❌ Forgetting
await on async operations — leads to race conditions
- ❌ Not closing browser in
afterAll — memory leaks in test suites
- ❌
page.evaluate() for simple text checks — use page.$eval or page.textContent