46 / 80 · 12 Programming for QA · Async/Await Patterns← prev⊞ allnext →☰ Read as one page
6.3TypeScript/JavaScript Async Patterns
Basic Async/Await
// Every Playwright interaction is async
test('user can add item to cart', async ({ page }) => {
await page.goto('/products');
await page.click('[data-testid="add-to-cart"]');
await expect(page.locator('.cart-count')).toHaveText('1');
});
The await keyword pauses execution until the operation completes. Without it, the code continues immediately — often before the operation finishes.
The Forgotten Await Bug
// BUG: missing await — test passes incorrectly
test('should have correct title', async ({ page }) => {
await page.goto('/dashboard');
// This returns a Promise, which is truthy — so the assert passes regardless!
expect(page.title()).toBe('Dashboard');
// FIX: await the title() call
expect(await page.title()).toBe('Dashboard');
});
This is the most common async bug in test automation. The test asserts against a Promise object (which is truthy), not the actual value. The test passes even when the title is wrong.
Concurrent API Requests
// Sequential: each request waits for the previous one (slow)
const user = await fetch('/api/users/1');
const orders = await fetch('/api/orders?user=1');
const payments = await fetch('/api/payments?user=1');
// Total time: user + orders + payments
// Concurrent: all requests run in parallel (fast)
const [user, orders, payments] = await Promise.all([
fetch('/api/users/1'),
fetch('/api/orders?user=1'),
fetch('/api/payments?user=1'),
]);
// Total time: max(user, orders, payments)
Promise.allSettled for Resilient Tests
// Promise.all fails fast — if one request fails, all fail
// Promise.allSettled waits for all to complete, regardless of success/failure
const results = await Promise.allSettled([
fetch('/api/endpoint-a'),
fetch('/api/endpoint-b'),
fetch('/api/endpoint-c'),
]);
const failures = results.filter(r => r.status === 'rejected');
const successes = results.filter(r => r.status === 'fulfilled');
expect(failures).toHaveLength(0);