Playwright API Testing

APIRequestContext โ€” HTTP Requests

import { test, expect } from '@playwright/test'; // Use built-in `request` fixture test('GET /api/users', async ({ request }) => { const response = await request.get('/api/users'); expect(response.status()).toBe(200); expect(response.ok()).toBeTruthy(); const body = await response.json(); expect(body).toHaveLength(3); expect(body[0]).toMatchObject({ id: expect.any(Number), name: expect.any(String) }); }); test('POST /api/users', async ({ request }) => { const response = await request.post('/api/users', { data: { name: 'Alice', email: '[email protected]' }, headers: { 'Content-Type': 'application/json' }, }); expect(response.status()).toBe(201); const user = await response.json(); expect(user.id).toBeDefined(); }); test('DELETE /api/users/:id', async ({ request }) => { const del = await request.delete('/api/users/1'); expect(del.status()).toBe(204); });

Standalone APIRequestContext

import { request } from '@playwright/test'; // Create context outside of test (e.g., global setup) const context = await request.newContext({ baseURL: 'https://api.example.com', extraHTTPHeaders: { 'Authorization': 'Bearer my-token', 'Accept': 'application/json', }, }); const response = await context.get('/users'); const users = await response.json(); console.log(users); await context.dispose(); // In playwright.config.ts export default defineConfig({ use: { baseURL: 'http://localhost:3000', extraHTTPHeaders: { 'x-api-key': process.env.API_KEY, }, }, });

Response Assertions

test('API response assertions', async ({ request }) => { const response = await request.get('/api/profile'); // Status expect(response.status()).toBe(200); expect(response.ok()).toBeTruthy(); // 200โ€“299 // Headers expect(response.headers()['content-type']).toContain('application/json'); // Body as JSON const json = await response.json(); expect(json).toMatchObject({ id: expect.any(Number), email: expect.stringContaining('@'), }); // Body as text const text = await response.text(); expect(text).toContain('"status":"ok"'); // Body as buffer (for binary) const buffer = await response.body(); expect(buffer.byteLength).toBeGreaterThan(0); // Playwright built-in API assertions await expect(response).toBeOK(); });

Auth Storage โ€” storageState

// global-setup.ts โ€” login once, reuse auth across all tests import { chromium } from '@playwright/test'; async function globalSetup() { const browser = await chromium.launch(); const page = await browser.newPage(); await page.goto('http://localhost:3000/login'); await page.fill('#email', '[email protected]'); await page.fill('#password', 'adminpass'); await page.click('[type="submit"]'); await page.waitForURL('**/dashboard'); // Save cookies + localStorage await page.context().storageState({ path: 'auth/admin.json' }); await browser.close(); } export default globalSetup; // playwright.config.ts export default defineConfig({ globalSetup: './global-setup.ts', use: { storageState: 'auth/admin.json', }, }); // API context with saved auth test('authenticated API call', async ({ request }) => { // cookies from storageState are automatically included const response = await request.get('/api/admin/stats'); expect(response.status()).toBe(200); });

Route Mocking โ€” page.route()

test('mock API responses', async ({ page }) => { // Intercept and mock await page.route('**/api/users', async route => { await route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify([{ id: 1, name: 'Alice' }]), }); }); // Intercept and modify await page.route('**/api/products', async route => { const response = await route.fetch(); const body = await response.json(); body.featured = true; // add field await route.fulfill({ response, body: JSON.stringify(body) }); }); // Abort a request await page.route('**/*.png', route => route.abort()); await page.goto('/'); await expect(page.getByText('Alice')).toBeVisible(); }); // Reuse route in multiple tests test.beforeEach(async ({ page }) => { await page.route('**/api/**', async route => { if (route.request().url().includes('/auth')) return route.continue(); await route.fulfill({ body: '{}', contentType: 'application/json' }); }); });

API Testing Quick Reference

MethodPurpose
request.get(url)HTTP GET request
request.post(url, {data})HTTP POST with JSON body
request.put(url, {data})HTTP PUT request
request.patch(url, {data})HTTP PATCH request
request.delete(url)HTTP DELETE request
response.json()Parse response as JSON
response.status()Get HTTP status code
response.ok()True if status 200-299
page.route(pattern, handler)Intercept/mock network
storageStateSave/restore auth cookies