Two patterns: waitForEvent (set up the promise BEFORE triggering the action, then await after) and page.on (listen to all occurrences continuously). The waitForEvent pattern is critical — get the order wrong and you miss the event.
waitForEvent — the setup-before-trigger pattern
Always register the waitForEvent promise BEFORE triggering the action — the event fires only once
Some actions trigger events that fire once: a new tab opens, a file downloads, a dialog appears. The pattern is always the same: set up the event listener BEFORE the action, then trigger the action, then await the result. If you reverse the order, the event may have already fired before you start listening.
page.on() is for ongoing listening — log all requests, collect all console errors, capture all responses. Unlike waitForEvent which resolves once, page.on fires for every matching event.
ts
// Збирати JS-помилки консолі під час тестуtest('dashboard has no console errors', async ({ page }) => {
const errors: string[] = []
page.on('console', msg => {
if (msg.type() === 'error') errors.push(msg.text())
})
await page.goto('/dashboard')
await page.waitForLoadState('networkidle')
expect(errors).toHaveLength(0)
})
// Логувати всі мережеві запити до певного ендпоїнтуtest('orders page makes correct API call', async ({ page }) => {
const apiCalls: string[] = []
page.on('request', request => {
if (request.url().includes('/api/orders')) {
apiCalls.push(request.url())
}
})
await page.goto('/orders')
await page.waitForLoadState('networkidle')
expect(apiCalls).toHaveLength(1)
expect(apiCalls[0]).toContain('/api/orders')
})
// Слідкувати за відповідями
page.on('response', response => {
if (!response.ok()) {
console.warn(`Failed: ${response.status()} ${response.url()}`)
}
})
page.once() and page.off() — one-shot and cleanup
page.once() registers a listener that fires only the next time the event occurs, then removes itself. Perfect for dialogs: handle the next alert, ignore any subsequent ones. page.off() removes a specific listener — useful for cleanup when the listening period ends.
ts
// page.once — обробити наступний dialog і більше нічого
page.once('dialog', dialog => dialog.accept())
await page.getByRole('button', { name: 'Delete order' }).click()
// Dialog accepted — подальші dialogs знову показуватимуться// page.off — прибирати listener після потрібного проміжкуconst logRequest = (request: Request) => {
console.log('Request:', request.url())
}
page.on('request', logRequest)
await page.goto('/orders') // логуємо запити тут
page.off('request', logRequest) // прибираємо слухачаawait page.goto('/dashboard') // ці запити не логуються
waitForRequest and waitForResponse
Specific helpers for network events. The same setup-before-trigger pattern applies — set up the waiter before the action that triggers the request.