0
# Request Interception
1
2
TestCafe provides powerful HTTP request and response interception capabilities through request hooks, allowing you to monitor, log, and mock network traffic during test execution.
3
4
## Capabilities
5
6
### Request Logging
7
8
Monitor and log HTTP requests and responses for debugging and verification.
9
10
```javascript { .api }
11
/**
12
* Creates a request logger to monitor HTTP traffic
13
* @param requestFilterRuleInit - Filter rule to specify which requests to log
14
* @param logOptions - Configuration options for logging behavior
15
* @returns RequestLogger instance for attaching to tests
16
*/
17
function RequestLogger(
18
requestFilterRuleInit?: string | RegExp | object | Function,
19
logOptions?: RequestLoggerOptions
20
): RequestLogger;
21
22
interface RequestLogger {
23
/** Array of logged request objects */
24
requests: LoggedRequest[];
25
26
/** Number of requests that have been logged */
27
count: number;
28
29
/**
30
* Checks if request matching criteria was logged
31
* @param predicate - Function to test each logged request
32
* @returns True if matching request exists
33
*/
34
contains(predicate: (request: LoggedRequest) => boolean): boolean;
35
36
/**
37
* Clears all logged requests
38
*/
39
clear(): void;
40
}
41
42
interface RequestLoggerOptions {
43
/** Log request body content */
44
logRequestBody?: boolean;
45
46
/** Log response body content */
47
logResponseBody?: boolean;
48
49
/** Stringify request body */
50
stringifyRequestBody?: boolean;
51
52
/** Stringify response body */
53
stringifyResponseBody?: boolean;
54
}
55
56
interface LoggedRequest {
57
/** Request information */
58
request: {
59
url: string;
60
method: string;
61
headers: object;
62
body?: string;
63
isAjax: boolean;
64
};
65
66
/** Response information */
67
response: {
68
statusCode: number;
69
statusText: string;
70
headers: object;
71
body?: string;
72
};
73
}
74
```
75
76
**Usage Examples:**
77
78
```javascript
79
import { RequestLogger } from 'testcafe';
80
81
const logger = RequestLogger();
82
83
fixture('Request Logging')
84
.page('https://example.com')
85
.requestHooks(logger);
86
87
test('Monitor API calls', async t => {
88
await t.click('#load-data-button');
89
90
// Wait for requests to complete
91
await t.wait(2000);
92
93
// Check logged requests
94
await t.expect(logger.count).gte(1);
95
96
// Find specific API call
97
const apiCall = logger.requests.find(request =>
98
request.request.url.includes('/api/data')
99
);
100
101
await t.expect(apiCall).ok();
102
await t.expect(apiCall.response.statusCode).eql(200);
103
});
104
105
// Log only specific requests
106
const apiLogger = RequestLogger(/\/api\//, {
107
logRequestBody: true,
108
logResponseBody: true
109
});
110
111
test('Monitor specific API endpoints', async t => {
112
await t.click('#submit-form');
113
114
// Check API request was made
115
const postRequest = apiLogger.requests.find(req =>
116
req.request.method === 'POST' &&
117
req.request.url.includes('/api/submit')
118
);
119
120
await t.expect(postRequest).ok();
121
await t.expect(postRequest.request.body).contains('formData');
122
});
123
```
124
125
### Request Mocking
126
127
Mock HTTP requests and responses to control application behavior during tests.
128
129
```javascript { .api }
130
/**
131
* Creates a request mock for intercepting and responding to HTTP requests
132
* @returns RequestMock instance for configuring mock responses
133
*/
134
function RequestMock(): RequestMock;
135
136
interface RequestMock {
137
/**
138
* Configures mock to respond to requests matching the filter
139
* @param requestFilterRuleInit - Filter rule to match requests
140
* @param responseEventConfigurer - Response configuration
141
* @returns RequestMock instance for chaining
142
*/
143
onRequestTo(
144
requestFilterRuleInit: string | RegExp | object | Function,
145
responseEventConfigurer: ResponseEventConfigurer
146
): RequestMock;
147
}
148
149
interface ResponseEventConfigurer {
150
/**
151
* Responds with specified data and status
152
* @param body - Response body content
153
* @param statusCode - HTTP status code (default: 200)
154
* @param headers - Response headers
155
* @returns Response configuration
156
*/
157
respond(body?: any, statusCode?: number, headers?: object): void;
158
159
/**
160
* Responds with data from file
161
* @param filePath - Path to response file
162
* @param statusCode - HTTP status code (default: 200)
163
* @param headers - Response headers
164
* @returns Response configuration
165
*/
166
respondWithFile(filePath: string, statusCode?: number, headers?: object): void;
167
}
168
```
169
170
**Usage Examples:**
171
172
```javascript
173
import { RequestMock } from 'testcafe';
174
175
// Mock API responses
176
const mockAPI = RequestMock()
177
.onRequestTo(/\/api\/users/)
178
.respond([
179
{ id: 1, name: 'John Doe', email: 'john@example.com' },
180
{ id: 2, name: 'Jane Smith', email: 'jane@example.com' }
181
], 200, {
182
'Content-Type': 'application/json',
183
'Access-Control-Allow-Origin': '*'
184
})
185
.onRequestTo(/\/api\/error/)
186
.respond({ error: 'Not found' }, 404);
187
188
fixture('Request Mocking')
189
.page('https://example.com')
190
.requestHooks(mockAPI);
191
192
test('Mock successful API response', async t => {
193
await t.click('#load-users-button');
194
195
// Verify mocked data is displayed
196
await t.expect(Selector('.user-list .user-item').count).eql(2);
197
await t.expect(Selector('.user-item').nth(0).innerText).contains('John Doe');
198
});
199
200
test('Mock error response', async t => {
201
await t.click('#trigger-error-button');
202
203
// Verify error handling
204
await t.expect(Selector('.error-message').innerText).contains('Not found');
205
});
206
207
// Mock with file response
208
const fileMock = RequestMock()
209
.onRequestTo(/\/api\/large-data/)
210
.respondWithFile('./fixtures/large-response.json', 200, {
211
'Content-Type': 'application/json'
212
});
213
```
214
215
### Custom Request Hooks
216
217
Create custom request hooks for advanced request/response processing.
218
219
```javascript { .api }
220
/**
221
* Base class for creating custom request hooks
222
*/
223
class RequestHook {
224
/**
225
* Creates custom request hook
226
* @param requestFilterRuleInit - Filter rule to specify which requests to intercept
227
*/
228
constructor(requestFilterRuleInit?: string | RegExp | object | Function);
229
230
/**
231
* Called when request is made (override in subclass)
232
* @param event - Request event object
233
* @returns Promise for async processing
234
*/
235
onRequest(event: RequestEvent): Promise<void>;
236
237
/**
238
* Called when response is received (override in subclass)
239
* @param event - Response event object
240
* @returns Promise for async processing
241
*/
242
onResponse(event: ResponseEvent): Promise<void>;
243
}
244
245
interface RequestEvent {
246
/** Request information */
247
request: {
248
url: string;
249
method: string;
250
headers: object;
251
body: string;
252
isAjax: boolean;
253
};
254
255
/** Modify request headers */
256
setHeaders(headers: object): void;
257
258
/** Remove request header */
259
removeHeader(name: string): void;
260
}
261
262
interface ResponseEvent {
263
/** Request information */
264
request: {
265
url: string;
266
method: string;
267
headers: object;
268
body: string;
269
isAjax: boolean;
270
};
271
272
/** Response information */
273
response: {
274
statusCode: number;
275
statusText: string;
276
headers: object;
277
body: string;
278
};
279
280
/** Modify response headers */
281
setHeaders(headers: object): void;
282
283
/** Remove response header */
284
removeHeader(name: string): void;
285
}
286
```
287
288
**Usage Examples:**
289
290
```javascript
291
import { RequestHook } from 'testcafe';
292
293
// Custom authentication hook
294
class AuthHook extends RequestHook {
295
constructor() {
296
super(/\/api\//);
297
}
298
299
async onRequest(event) {
300
// Add authentication header to API requests
301
event.setHeaders({
302
'Authorization': 'Bearer test-token',
303
'X-Test-Mode': 'true'
304
});
305
}
306
307
async onResponse(event) {
308
// Log API responses
309
console.log(`API ${event.request.method} ${event.request.url}: ${event.response.statusCode}`);
310
}
311
}
312
313
// Custom timing hook
314
class TimingHook extends RequestHook {
315
constructor() {
316
super();
317
this.requestTimes = new Map();
318
}
319
320
async onRequest(event) {
321
this.requestTimes.set(event.request.url, Date.now());
322
}
323
324
async onResponse(event) {
325
const startTime = this.requestTimes.get(event.request.url);
326
const duration = Date.now() - startTime;
327
console.log(`Request to ${event.request.url} took ${duration}ms`);
328
}
329
}
330
331
const authHook = new AuthHook();
332
const timingHook = new TimingHook();
333
334
fixture('Custom Request Hooks')
335
.page('https://example.com')
336
.requestHooks([authHook, timingHook]);
337
338
test('Custom request processing', async t => {
339
await t.click('#api-call-button');
340
341
// Requests will be processed by custom hooks
342
await t.wait(1000);
343
});
344
```
345
346
### Request Filtering
347
348
Define sophisticated filters for targeting specific requests.
349
350
```javascript { .api }
351
// String URL filter
352
const stringFilter = 'https://api.example.com/users';
353
354
// RegExp URL filter
355
const regexpFilter = /\/api\/.*\/data/;
356
357
// Object filter with multiple criteria
358
const objectFilter = {
359
url: /\/api\//,
360
method: 'POST',
361
headers: {
362
'content-type': /application\/json/
363
}
364
};
365
366
// Function filter with custom logic
367
const functionFilter = (request) => {
368
return request.url.includes('/api/') &&
369
request.method === 'GET' &&
370
request.headers['authorization'];
371
};
372
```
373
374
**Usage Examples:**
375
376
```javascript
377
// Filter by URL pattern
378
const apiLogger = RequestLogger(/\/api\/v\d+\//);
379
380
// Filter POST requests to specific endpoint
381
const postLogger = RequestLogger({
382
url: 'https://api.example.com/submit',
383
method: 'POST'
384
});
385
386
// Filter by custom criteria
387
const customLogger = RequestLogger((request) => {
388
return request.isAjax &&
389
request.url.includes('/data') &&
390
!request.url.includes('/cache');
391
});
392
393
// Filter by headers
394
const authLogger = RequestLogger({
395
url: /\/api\//,
396
headers: {
397
'authorization': /Bearer .+/
398
}
399
});
400
401
fixture('Request Filtering')
402
.page('https://example.com')
403
.requestHooks([apiLogger, postLogger, customLogger, authLogger]);
404
405
test('Filtered request monitoring', async t => {
406
// Trigger various types of requests
407
await t
408
.click('#get-data-button')
409
.click('#post-form-button')
410
.click('#cached-request-button');
411
412
// Check filtered results
413
await t.expect(apiLogger.count).gte(1);
414
await t.expect(postLogger.count).eql(1);
415
await t.expect(customLogger.count).gte(1);
416
});
417
```
418
419
### Request Hook Attachment
420
421
Attach request hooks to tests, fixtures, or globally.
422
423
```javascript { .api }
424
// Fixture-level hooks
425
fixture('API Tests')
426
.page('https://example.com')
427
.requestHooks([logger, mock]);
428
429
// Test-level hooks
430
test('Specific test with hooks', async t => {
431
// Test implementation
432
}).requestHooks([specificLogger]);
433
434
// Multiple hooks
435
const hooks = [
436
RequestLogger(/\/api\//),
437
RequestMock().onRequestTo(/\/mock\//).respond({ success: true }),
438
new CustomHook()
439
];
440
441
fixture('Multiple Hooks')
442
.requestHooks(hooks);
443
```
444
445
**Usage Examples:**
446
447
```javascript
448
const globalLogger = RequestLogger();
449
const apiMock = RequestMock()
450
.onRequestTo(/\/api\/error/)
451
.respond({ error: 'Mocked error' }, 500);
452
453
// Apply to entire fixture
454
fixture('Request Hook Attachment')
455
.page('https://example.com')
456
.requestHooks([globalLogger, apiMock]);
457
458
test('Test with fixture hooks', async t => {
459
// Uses globalLogger and apiMock
460
await t.click('#api-button');
461
});
462
463
// Test-specific additional hooks
464
const testLogger = RequestLogger(/\/specific-api\//);
465
466
test('Test with additional hooks', async t => {
467
// Uses globalLogger, apiMock, and testLogger
468
await t.click('#specific-api-button');
469
}).requestHooks([testLogger]);
470
471
// Conditional hook attachment
472
const conditionalHook = process.env.NODE_ENV === 'test'
473
? RequestLogger()
474
: RequestMock().onRequestTo().respond();
475
476
fixture('Conditional Hooks')
477
.requestHooks([conditionalHook]);
478
```