API Testing in Playwright
Verifying backend behaviour by sending HTTP requests with Playwright's request fixture.
API testing verifies backend functionality by sending HTTP requests directly to API endpoints without interacting with the browser UI.
1. Key Concepts
Direct Requests
Use Playwright's request fixture to send HTTP requests such as GET, POST, PUT, PATCH, and DELETE.
import { test, expect } from '@playwright/test';
test('should fetch users', async ({ request }) => {
const response = await request.get('/api/users');
expect(response.status()).toBe(200);
});
Response Verification
Validate status codes, response bodies, data structures, and specific field values.
test('should return user data', async ({ request }) => {
const response = await request.get('/api/users/1');
expect(response.ok()).toBeTruthy();
const data = await response.json();
expect(data.id).toBe(1);
expect(data.name).toBe('John');
});
CRUD Operations
API testing can verify the complete lifecycle of data:
// Create
const createResponse = await request.post('/api/users', {
data: { name: 'Parth', email: '[email protected]' }
});
// Read
const readResponse = await request.get('/api/users');
// Update
const updateResponse = await request.put('/api/users/1', {
data: { name: 'Updated Name' }
});
// Delete
const deleteResponse = await request.delete('/api/users/1');
These operations should be tested against the API's actual contract and expected status codes. The example assumes the endpoints support these operations.
2. Common Assertions
expect(response.status()).toBe(200);
expect(response.ok()).toBeTruthy();
const data = await response.json();
expect(data).toHaveProperty('id');
expect(data.name).toBe('Parth');
expect(Array.isArray(data)).toBeTruthy();
expect(data.length).toBe(3);
response.status()— Returns the HTTP status code.response.ok()— Returnstruefor status codes in the 200–299 range.response.json()— Parses the response body as JSON.response.headers()— Returns the response headers.
3. Authentication Testing
Test protected endpoints by including the required authentication credentials.
test('should access a protected endpoint', async ({ request }) => {
const response = await request.get('/api/profile', {
headers: {
Authorization: 'Bearer YOUR_TEST_TOKEN'
}
});
expect(response.status()).toBe(200);
});
Also test unauthenticated requests and invalid credentials, typically expecting 401 Unauthorized or 403 Forbidden, depending on the API contract.
4. Advantages of API Testing
- Faster execution: Avoids browser rendering and UI interactions.
- Backend validation: Tests business logic and data handling directly.
- CRUD coverage: Verifies creating, reading, updating, and deleting records.
- Authentication testing: Checks access control and authorization.
- Less brittle: Avoids dependence on UI layouts, CSS selectors, and page structure.
- Integration coverage: Complements UI tests to validate more of the application stack.
5. API Testing vs. UI Testing
| API Testing | UI Testing |
|---|---|
| Sends requests directly to endpoints | Interacts with the application through a browser |
| Validates backend responses and logic | Validates visible behavior and user interactions |
| Generally faster | Generally slower |
| Less dependent on UI changes | Can break when UI elements change |
| Tests API contracts and data handling | Tests complete user workflows |
6. Running API Tests
# Run all tests
npx playwright test
# Run a specific API test file
npx playwright test tests/api.spec.ts
# Run API tests with visible test-runner output
npx playwright test tests/api.spec.ts --reporter=list
# Debug API tests
npx playwright test tests/api.spec.ts --debug
Best Practices
- Configure
baseURLinplaywright.config.tsto avoid repeating the API host. - Verify both successful and unsuccessful responses.
- Validate response bodies, not just status codes.
- Use isolated test data and clean up records created during tests.
- Never hardcode real credentials or production secrets.
- Keep API tests separate from UI tests when it improves organization.
Key takeaway: API testing verifies backend behavior directly, while UI testing verifies how users interact with the application. Using both provides more comprehensive test coverage.