Automated browser testing for the modern web development stack.
—
TestCafe provides powerful HTTP request and response interception capabilities through request hooks, allowing you to monitor, log, and mock network traffic during test execution.
Monitor and log HTTP requests and responses for debugging and verification.
/**
* Creates a request logger to monitor HTTP traffic
* @param requestFilterRuleInit - Filter rule to specify which requests to log
* @param logOptions - Configuration options for logging behavior
* @returns RequestLogger instance for attaching to tests
*/
function RequestLogger(
requestFilterRuleInit?: string | RegExp | object | Function,
logOptions?: RequestLoggerOptions
): RequestLogger;
interface RequestLogger {
/** Array of logged request objects */
requests: LoggedRequest[];
/** Number of requests that have been logged */
count: number;
/**
* Checks if request matching criteria was logged
* @param predicate - Function to test each logged request
* @returns True if matching request exists
*/
contains(predicate: (request: LoggedRequest) => boolean): boolean;
/**
* Clears all logged requests
*/
clear(): void;
}
interface RequestLoggerOptions {
/** Log request body content */
logRequestBody?: boolean;
/** Log response body content */
logResponseBody?: boolean;
/** Stringify request body */
stringifyRequestBody?: boolean;
/** Stringify response body */
stringifyResponseBody?: boolean;
}
interface LoggedRequest {
/** Request information */
request: {
url: string;
method: string;
headers: object;
body?: string;
isAjax: boolean;
};
/** Response information */
response: {
statusCode: number;
statusText: string;
headers: object;
body?: string;
};
}Usage Examples:
import { RequestLogger } from 'testcafe';
const logger = RequestLogger();
fixture('Request Logging')
.page('https://example.com')
.requestHooks(logger);
test('Monitor API calls', async t => {
await t.click('#load-data-button');
// Wait for requests to complete
await t.wait(2000);
// Check logged requests
await t.expect(logger.count).gte(1);
// Find specific API call
const apiCall = logger.requests.find(request =>
request.request.url.includes('/api/data')
);
await t.expect(apiCall).ok();
await t.expect(apiCall.response.statusCode).eql(200);
});
// Log only specific requests
const apiLogger = RequestLogger(/\/api\//, {
logRequestBody: true,
logResponseBody: true
});
test('Monitor specific API endpoints', async t => {
await t.click('#submit-form');
// Check API request was made
const postRequest = apiLogger.requests.find(req =>
req.request.method === 'POST' &&
req.request.url.includes('/api/submit')
);
await t.expect(postRequest).ok();
await t.expect(postRequest.request.body).contains('formData');
});Mock HTTP requests and responses to control application behavior during tests.
/**
* Creates a request mock for intercepting and responding to HTTP requests
* @returns RequestMock instance for configuring mock responses
*/
function RequestMock(): RequestMock;
interface RequestMock {
/**
* Configures mock to respond to requests matching the filter
* @param requestFilterRuleInit - Filter rule to match requests
* @param responseEventConfigurer - Response configuration
* @returns RequestMock instance for chaining
*/
onRequestTo(
requestFilterRuleInit: string | RegExp | object | Function,
responseEventConfigurer: ResponseEventConfigurer
): RequestMock;
}
interface ResponseEventConfigurer {
/**
* Responds with specified data and status
* @param body - Response body content
* @param statusCode - HTTP status code (default: 200)
* @param headers - Response headers
* @returns Response configuration
*/
respond(body?: any, statusCode?: number, headers?: object): void;
/**
* Responds with data from file
* @param filePath - Path to response file
* @param statusCode - HTTP status code (default: 200)
* @param headers - Response headers
* @returns Response configuration
*/
respondWithFile(filePath: string, statusCode?: number, headers?: object): void;
}Usage Examples:
import { RequestMock } from 'testcafe';
// Mock API responses
const mockAPI = RequestMock()
.onRequestTo(/\/api\/users/)
.respond([
{ id: 1, name: 'John Doe', email: 'john@example.com' },
{ id: 2, name: 'Jane Smith', email: 'jane@example.com' }
], 200, {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
})
.onRequestTo(/\/api\/error/)
.respond({ error: 'Not found' }, 404);
fixture('Request Mocking')
.page('https://example.com')
.requestHooks(mockAPI);
test('Mock successful API response', async t => {
await t.click('#load-users-button');
// Verify mocked data is displayed
await t.expect(Selector('.user-list .user-item').count).eql(2);
await t.expect(Selector('.user-item').nth(0).innerText).contains('John Doe');
});
test('Mock error response', async t => {
await t.click('#trigger-error-button');
// Verify error handling
await t.expect(Selector('.error-message').innerText).contains('Not found');
});
// Mock with file response
const fileMock = RequestMock()
.onRequestTo(/\/api\/large-data/)
.respondWithFile('./fixtures/large-response.json', 200, {
'Content-Type': 'application/json'
});Create custom request hooks for advanced request/response processing.
/**
* Base class for creating custom request hooks
*/
class RequestHook {
/**
* Creates custom request hook
* @param requestFilterRuleInit - Filter rule to specify which requests to intercept
*/
constructor(requestFilterRuleInit?: string | RegExp | object | Function);
/**
* Called when request is made (override in subclass)
* @param event - Request event object
* @returns Promise for async processing
*/
onRequest(event: RequestEvent): Promise<void>;
/**
* Called when response is received (override in subclass)
* @param event - Response event object
* @returns Promise for async processing
*/
onResponse(event: ResponseEvent): Promise<void>;
}
interface RequestEvent {
/** Request information */
request: {
url: string;
method: string;
headers: object;
body: string;
isAjax: boolean;
};
/** Modify request headers */
setHeaders(headers: object): void;
/** Remove request header */
removeHeader(name: string): void;
}
interface ResponseEvent {
/** Request information */
request: {
url: string;
method: string;
headers: object;
body: string;
isAjax: boolean;
};
/** Response information */
response: {
statusCode: number;
statusText: string;
headers: object;
body: string;
};
/** Modify response headers */
setHeaders(headers: object): void;
/** Remove response header */
removeHeader(name: string): void;
}Usage Examples:
import { RequestHook } from 'testcafe';
// Custom authentication hook
class AuthHook extends RequestHook {
constructor() {
super(/\/api\//);
}
async onRequest(event) {
// Add authentication header to API requests
event.setHeaders({
'Authorization': 'Bearer test-token',
'X-Test-Mode': 'true'
});
}
async onResponse(event) {
// Log API responses
console.log(`API ${event.request.method} ${event.request.url}: ${event.response.statusCode}`);
}
}
// Custom timing hook
class TimingHook extends RequestHook {
constructor() {
super();
this.requestTimes = new Map();
}
async onRequest(event) {
this.requestTimes.set(event.request.url, Date.now());
}
async onResponse(event) {
const startTime = this.requestTimes.get(event.request.url);
const duration = Date.now() - startTime;
console.log(`Request to ${event.request.url} took ${duration}ms`);
}
}
const authHook = new AuthHook();
const timingHook = new TimingHook();
fixture('Custom Request Hooks')
.page('https://example.com')
.requestHooks([authHook, timingHook]);
test('Custom request processing', async t => {
await t.click('#api-call-button');
// Requests will be processed by custom hooks
await t.wait(1000);
});Define sophisticated filters for targeting specific requests.
// String URL filter
const stringFilter = 'https://api.example.com/users';
// RegExp URL filter
const regexpFilter = /\/api\/.*\/data/;
// Object filter with multiple criteria
const objectFilter = {
url: /\/api\//,
method: 'POST',
headers: {
'content-type': /application\/json/
}
};
// Function filter with custom logic
const functionFilter = (request) => {
return request.url.includes('/api/') &&
request.method === 'GET' &&
request.headers['authorization'];
};Usage Examples:
// Filter by URL pattern
const apiLogger = RequestLogger(/\/api\/v\d+\//);
// Filter POST requests to specific endpoint
const postLogger = RequestLogger({
url: 'https://api.example.com/submit',
method: 'POST'
});
// Filter by custom criteria
const customLogger = RequestLogger((request) => {
return request.isAjax &&
request.url.includes('/data') &&
!request.url.includes('/cache');
});
// Filter by headers
const authLogger = RequestLogger({
url: /\/api\//,
headers: {
'authorization': /Bearer .+/
}
});
fixture('Request Filtering')
.page('https://example.com')
.requestHooks([apiLogger, postLogger, customLogger, authLogger]);
test('Filtered request monitoring', async t => {
// Trigger various types of requests
await t
.click('#get-data-button')
.click('#post-form-button')
.click('#cached-request-button');
// Check filtered results
await t.expect(apiLogger.count).gte(1);
await t.expect(postLogger.count).eql(1);
await t.expect(customLogger.count).gte(1);
});Attach request hooks to tests, fixtures, or globally.
// Fixture-level hooks
fixture('API Tests')
.page('https://example.com')
.requestHooks([logger, mock]);
// Test-level hooks
test('Specific test with hooks', async t => {
// Test implementation
}).requestHooks([specificLogger]);
// Multiple hooks
const hooks = [
RequestLogger(/\/api\//),
RequestMock().onRequestTo(/\/mock\//).respond({ success: true }),
new CustomHook()
];
fixture('Multiple Hooks')
.requestHooks(hooks);Usage Examples:
const globalLogger = RequestLogger();
const apiMock = RequestMock()
.onRequestTo(/\/api\/error/)
.respond({ error: 'Mocked error' }, 500);
// Apply to entire fixture
fixture('Request Hook Attachment')
.page('https://example.com')
.requestHooks([globalLogger, apiMock]);
test('Test with fixture hooks', async t => {
// Uses globalLogger and apiMock
await t.click('#api-button');
});
// Test-specific additional hooks
const testLogger = RequestLogger(/\/specific-api\//);
test('Test with additional hooks', async t => {
// Uses globalLogger, apiMock, and testLogger
await t.click('#specific-api-button');
}).requestHooks([testLogger]);
// Conditional hook attachment
const conditionalHook = process.env.NODE_ENV === 'test'
? RequestLogger()
: RequestMock().onRequestTo().respond();
fixture('Conditional Hooks')
.requestHooks([conditionalHook]);Install with Tessl CLI
npx tessl i tessl/npm-testcafe