0
# API Testing
1
2
HTTP API testing capabilities with request/response handling, authentication, context management, and comprehensive testing utilities for REST and GraphQL APIs.
3
4
## Capabilities
5
6
### API Request Context
7
8
Create isolated contexts for API testing with session management, authentication, and configuration.
9
10
```typescript { .api }
11
/**
12
* HTTP API testing interface
13
*/
14
interface APIRequest {
15
/** Create new API request context */
16
newContext(options?: APIRequestNewContextOptions): Promise<APIRequestContext>;
17
/** Send GET request */
18
get(url: string, options?: APIRequestGetOptions): Promise<APIResponse>;
19
/** Send POST request */
20
post(url: string, options?: APIRequestPostOptions): Promise<APIResponse>;
21
/** Send PUT request */
22
put(url: string, options?: APIRequestPutOptions): Promise<APIResponse>;
23
/** Send PATCH request */
24
patch(url: string, options?: APIRequestPatchOptions): Promise<APIResponse>;
25
/** Send DELETE request */
26
delete(url: string, options?: APIRequestDeleteOptions): Promise<APIResponse>;
27
/** Send HEAD request */
28
head(url: string, options?: APIRequestHeadOptions): Promise<APIResponse>;
29
}
30
31
/**
32
* API request context with session management and authentication
33
*/
34
interface APIRequestContext {
35
/** Send GET request */
36
get(url: string, options?: APIRequestGetOptions): Promise<APIResponse>;
37
/** Send POST request */
38
post(url: string, options?: APIRequestPostOptions): Promise<APIResponse>;
39
/** Send PUT request */
40
put(url: string, options?: APIRequestPutOptions): Promise<APIResponse>;
41
/** Send PATCH request */
42
patch(url: string, options?: APIRequestPatchOptions): Promise<APIResponse>;
43
/** Send DELETE request */
44
delete(url: string, options?: APIRequestDeleteOptions): Promise<APIResponse>;
45
/** Send HEAD request */
46
head(url: string, options?: APIRequestHeadOptions): Promise<APIResponse>;
47
/** Send custom HTTP request */
48
fetch(urlOrRequest: string | APIRequest, options?: APIRequestFetchOptions): Promise<APIResponse>;
49
/** Get or set storage state for authentication */
50
storageState(options?: StorageStateOptions): Promise<StorageState>;
51
/** Clean up context resources */
52
dispose(): Promise<void>;
53
}
54
```
55
56
**Usage Examples:**
57
58
```typescript
59
// Create API context with authentication
60
const apiContext = await request.newContext({
61
baseURL: 'https://api.example.com',
62
extraHTTPHeaders: {
63
'Authorization': 'Bearer your-token-here',
64
'Content-Type': 'application/json'
65
}
66
});
67
68
// Simple API requests
69
const response = await apiContext.get('/users');
70
const users = await response.json();
71
72
const createResponse = await apiContext.post('/users', {
73
data: {
74
name: 'John Doe',
75
email: 'john@example.com'
76
}
77
});
78
79
// Context with session management
80
const authContext = await request.newContext();
81
82
// Login and save session
83
const loginResponse = await authContext.post('/auth/login', {
84
data: { username: 'user', password: 'pass' }
85
});
86
87
// Session is automatically maintained for subsequent requests
88
const profileResponse = await authContext.get('/profile');
89
90
// Save authentication state
91
const state = await authContext.storageState();
92
```
93
94
### API Response Handling
95
96
Comprehensive response handling with JSON parsing, status checking, and data extraction.
97
98
```typescript { .api }
99
/**
100
* API response interface with testing-focused methods
101
*/
102
interface APIResponse {
103
/** Get response URL */
104
url(): string;
105
/** Get HTTP status code */
106
status(): number;
107
/** Get status text */
108
statusText(): string;
109
/** Get response headers */
110
headers(): { [key: string]: string; };
111
/** Get all headers (including multiple values) */
112
allHeaders(): Promise<{ [key: string]: string; }>;
113
/** Get headers as array */
114
headersArray(): Promise<{ name: string; value: string; }[]>;
115
/** Get single header value */
116
headerValue(name: string): Promise<string | null>;
117
/** Get multiple header values */
118
headerValues(name: string): Promise<string[]>;
119
/** Parse response as JSON */
120
json(): Promise<any>;
121
/** Get response as text */
122
text(): Promise<string>;
123
/** Get response as buffer */
124
body(): Promise<Buffer>;
125
/** Check if status indicates success (200-299) */
126
ok(): boolean;
127
/** Get response sizes */
128
sizes(): Promise<ResponseSizes>;
129
}
130
```
131
132
**Usage Examples:**
133
134
```typescript
135
// Basic response handling
136
const response = await apiContext.get('/api/data');
137
138
console.log(`Status: ${response.status()}`);
139
console.log(`Success: ${response.ok()}`);
140
141
if (response.ok()) {
142
const data = await response.json();
143
console.log('Data:', data);
144
} else {
145
const error = await response.text();
146
console.log('Error:', error);
147
}
148
149
// Header inspection
150
const headers = response.headers();
151
const contentType = headers['content-type'];
152
const rateLimit = await response.headerValue('x-rate-limit-remaining');
153
154
// Response validation
155
const apiResponse = await apiContext.post('/api/users', {
156
data: { name: 'Test User', email: 'test@example.com' }
157
});
158
159
if (apiResponse.status() === 201) {
160
const createdUser = await apiResponse.json();
161
console.log('Created user:', createdUser);
162
} else {
163
console.log('Failed to create user:', apiResponse.statusText());
164
}
165
```
166
167
### Authentication Patterns
168
169
Common authentication patterns including basic auth, bearer tokens, and session management.
170
171
**Usage Examples:**
172
173
```typescript
174
// Basic Authentication
175
const basicAuthContext = await request.newContext({
176
httpCredentials: {
177
username: 'admin',
178
password: 'secret'
179
}
180
});
181
182
// Bearer Token Authentication
183
const tokenContext = await request.newContext({
184
extraHTTPHeaders: {
185
'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
186
}
187
});
188
189
// API Key Authentication
190
const apiKeyContext = await request.newContext({
191
extraHTTPHeaders: {
192
'X-API-Key': 'your-api-key-here'
193
}
194
});
195
196
// Session-based Authentication
197
const sessionContext = await request.newContext();
198
199
// Login to get session cookie
200
await sessionContext.post('/auth/login', {
201
form: {
202
username: 'user@example.com',
203
password: 'password123'
204
}
205
});
206
207
// Session cookie is automatically included in subsequent requests
208
const userData = await sessionContext.get('/user/profile');
209
210
// OAuth2 Flow Simulation
211
const oauthContext = await request.newContext();
212
213
// Step 1: Get authorization code
214
const authResponse = await oauthContext.post('/oauth/authorize', {
215
form: {
216
client_id: 'your-client-id',
217
redirect_uri: 'http://localhost:3000/callback',
218
response_type: 'code',
219
scope: 'read write'
220
}
221
});
222
223
// Step 2: Exchange code for token
224
const tokenResponse = await oauthContext.post('/oauth/token', {
225
form: {
226
client_id: 'your-client-id',
227
client_secret: 'your-client-secret',
228
code: 'authorization-code',
229
grant_type: 'authorization_code'
230
}
231
});
232
233
const { access_token } = await tokenResponse.json();
234
235
// Step 3: Use token for API requests
236
const protectedContext = await request.newContext({
237
extraHTTPHeaders: {
238
'Authorization': `Bearer ${access_token}`
239
}
240
});
241
```
242
243
### Request Data Formats
244
245
Support for various request data formats including JSON, form data, and multipart uploads.
246
247
**Usage Examples:**
248
249
```typescript
250
// JSON Data
251
const jsonResponse = await apiContext.post('/api/users', {
252
data: {
253
name: 'John Doe',
254
email: 'john@example.com',
255
settings: {
256
theme: 'dark',
257
notifications: true
258
}
259
}
260
});
261
262
// Form Data (application/x-www-form-urlencoded)
263
const formResponse = await apiContext.post('/api/login', {
264
form: {
265
username: 'user@example.com',
266
password: 'secretpassword',
267
remember_me: 'true'
268
}
269
});
270
271
// Multipart Form Data (multipart/form-data)
272
const multipartResponse = await apiContext.post('/api/upload', {
273
multipart: {
274
title: 'Document Title',
275
description: 'File description',
276
file: fs.readFileSync('document.pdf')
277
}
278
});
279
280
// Raw Data
281
const rawResponse = await apiContext.post('/api/webhook', {
282
data: Buffer.from('raw binary data'),
283
headers: {
284
'Content-Type': 'application/octet-stream'
285
}
286
});
287
288
// GraphQL Queries
289
const graphqlResponse = await apiContext.post('/graphql', {
290
data: {
291
query: `
292
query GetUser($id: ID!) {
293
user(id: $id) {
294
id
295
name
296
297
posts {
298
title
299
content
300
}
301
}
302
}
303
`,
304
variables: {
305
id: '123'
306
}
307
}
308
});
309
310
const graphqlData = await graphqlResponse.json();
311
```
312
313
### Testing Utilities
314
315
Built-in utilities for common API testing scenarios including retries, timeouts, and validation.
316
317
**Usage Examples:**
318
319
```typescript
320
// Request with timeout
321
const response = await apiContext.get('/slow-endpoint', {
322
timeout: 5000 // 5 seconds
323
});
324
325
// Request with retries (custom implementation)
326
async function requestWithRetry(url: string, options: any, maxRetries = 3) {
327
for (let i = 0; i < maxRetries; i++) {
328
try {
329
const response = await apiContext.get(url, options);
330
if (response.ok()) return response;
331
332
if (i === maxRetries - 1) throw new Error(`Failed after ${maxRetries} retries`);
333
await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1))); // Exponential backoff
334
} catch (error) {
335
if (i === maxRetries - 1) throw error;
336
}
337
}
338
}
339
340
// Rate limiting handling
341
async function handleRateLimit(response: APIResponse) {
342
if (response.status() === 429) {
343
const retryAfter = await response.headerValue('retry-after');
344
if (retryAfter) {
345
await new Promise(resolve => setTimeout(resolve, parseInt(retryAfter) * 1000));
346
}
347
}
348
}
349
350
// Response validation
351
async function validateApiResponse(response: APIResponse, expectedSchema: any) {
352
if (!response.ok()) {
353
throw new Error(`API error: ${response.status()} ${response.statusText()}`);
354
}
355
356
const data = await response.json();
357
358
// Validate response structure (pseudo-code)
359
if (!validateSchema(data, expectedSchema)) {
360
throw new Error('Response does not match expected schema');
361
}
362
363
return data;
364
}
365
```
366
367
## Configuration Types
368
369
```typescript { .api }
370
interface APIRequestNewContextOptions {
371
/** Base URL for relative requests. */
372
baseURL?: string;
373
/** Additional HTTP headers. */
374
extraHTTPHeaders?: { [key: string]: string; };
375
/** HTTP credentials. */
376
httpCredentials?: { username: string; password: string; };
377
/** Whether to ignore HTTPS errors. */
378
ignoreHTTPSErrors?: boolean;
379
/** Network proxy settings. */
380
proxy?: { server: string; bypass?: string; username?: string; password?: string; };
381
/** Storage state to populate context with. */
382
storageState?: string | StorageState;
383
/** Request timeout in milliseconds. */
384
timeout?: number;
385
/** User agent string. */
386
userAgent?: string;
387
}
388
389
interface APIRequestGetOptions {
390
/** Request data. */
391
data?: string | Buffer | Serializable;
392
/** Whether to throw on non-2xx/3xx status codes. */
393
failOnStatusCode?: boolean;
394
/** Form data. */
395
form?: { [key: string]: string | number | boolean; };
396
/** Request headers. */
397
headers?: { [key: string]: string; };
398
/** Whether to ignore HTTPS errors. */
399
ignoreHTTPSErrors?: boolean;
400
/** Maximum redirects to follow. */
401
maxRedirects?: number;
402
/** Maximum retries on network errors. */
403
maxRetries?: number;
404
/** Multipart form data. */
405
multipart?: { [key: string]: string | number | boolean; };
406
/** Query parameters. */
407
params?: { [key: string]: string | number | boolean; };
408
/** Request timeout. */
409
timeout?: number;
410
}
411
412
interface APIRequestPostOptions {
413
/** Request data. */
414
data?: string | Buffer | Serializable;
415
/** Whether to throw on non-2xx/3xx status codes. */
416
failOnStatusCode?: boolean;
417
/** Form data. */
418
form?: { [key: string]: string | number | boolean; };
419
/** Request headers. */
420
headers?: { [key: string]: string; };
421
/** Whether to ignore HTTPS errors. */
422
ignoreHTTPSErrors?: boolean;
423
/** Maximum redirects to follow. */
424
maxRedirects?: number;
425
/** Maximum retries on network errors. */
426
maxRetries?: number;
427
/** Multipart form data. */
428
multipart?: { [key: string]: string | number | boolean; };
429
/** Query parameters. */
430
params?: { [key: string]: string | number | boolean; };
431
/** Request timeout. */
432
timeout?: number;
433
}
434
435
interface APIRequestPutOptions {
436
/** Request data. */
437
data?: string | Buffer | Serializable;
438
/** Whether to throw on non-2xx/3xx status codes. */
439
failOnStatusCode?: boolean;
440
/** Form data. */
441
form?: { [key: string]: string | number | boolean; };
442
/** Request headers. */
443
headers?: { [key: string]: string; };
444
/** Whether to ignore HTTPS errors. */
445
ignoreHTTPSErrors?: boolean;
446
/** Maximum redirects to follow. */
447
maxRedirects?: number;
448
/** Maximum retries on network errors. */
449
maxRetries?: number;
450
/** Multipart form data. */
451
multipart?: { [key: string]: string | number | boolean; };
452
/** Query parameters. */
453
params?: { [key: string]: string | number | boolean; };
454
/** Request timeout. */
455
timeout?: number;
456
}
457
458
interface APIRequestDeleteOptions {
459
/** Request data. */
460
data?: string | Buffer | Serializable;
461
/** Whether to throw on non-2xx/3xx status codes. */
462
failOnStatusCode?: boolean;
463
/** Form data. */
464
form?: { [key: string]: string | number | boolean; };
465
/** Request headers. */
466
headers?: { [key: string]: string; };
467
/** Whether to ignore HTTPS errors. */
468
ignoreHTTPSErrors?: boolean;
469
/** Maximum redirects to follow. */
470
maxRedirects?: number;
471
/** Maximum retries on network errors. */
472
maxRetries?: number;
473
/** Multipart form data. */
474
multipart?: { [key: string]: string | number | boolean; };
475
/** Query parameters. */
476
params?: { [key: string]: string | number | boolean; };
477
/** Request timeout. */
478
timeout?: number;
479
}
480
481
interface StorageState {
482
/** Cookies to set. */
483
cookies: Array<{
484
name: string;
485
value: string;
486
domain: string;
487
path: string;
488
expires: number;
489
httpOnly: boolean;
490
secure: boolean;
491
sameSite: 'Strict' | 'Lax' | 'None';
492
}>;
493
/** Local storage entries to set. */
494
origins: Array<{
495
origin: string;
496
localStorage: Array<{
497
name: string;
498
value: string;
499
}>;
500
}>;
501
}
502
503
type Serializable = any;
504
```
505
506
## Integration with Browser Context
507
508
API testing can be integrated with browser automation for end-to-end testing scenarios.
509
510
**Usage Examples:**
511
512
```typescript
513
// Share authentication between browser and API contexts
514
const browser = await chromium.launch();
515
const context = await browser.newContext();
516
const page = await context.newPage();
517
518
// Login through browser
519
await page.goto('https://example.com/login');
520
await page.fill('[name="email"]', 'user@example.com');
521
await page.fill('[name="password"]', 'password123');
522
await page.click('button[type="submit"]');
523
524
// Extract authentication state
525
const storageState = await context.storageState();
526
527
// Use authentication state for API testing
528
const apiContext = await request.newContext({
529
baseURL: 'https://api.example.com',
530
storageState
531
});
532
533
// API requests now use the same authentication as browser
534
const apiResponse = await apiContext.get('/user/profile');
535
const userData = await apiResponse.json();
536
537
// Verify UI reflects API data
538
await page.goto('https://example.com/profile');
539
const displayedName = await page.textContent('.user-name');
540
console.assert(displayedName === userData.name);
541
```
542
543
## Error Handling
544
545
**Usage Examples:**
546
547
```typescript
548
try {
549
const response = await apiContext.get('/api/data');
550
551
if (!response.ok()) {
552
const errorBody = await response.text();
553
throw new Error(`API Error ${response.status()}: ${errorBody}`);
554
}
555
556
const data = await response.json();
557
return data;
558
} catch (error) {
559
if (error.message.includes('timeout')) {
560
console.log('Request timed out, retrying...');
561
// Implement retry logic
562
} else if (error.message.includes('ECONNREFUSED')) {
563
console.log('Server is not available');
564
} else {
565
console.log('API request failed:', error.message);
566
}
567
throw error;
568
}
569
```