Intercept HTTP Requests

This section describes how to handle HTTP requests in your tests. TestCafe ships with request hooks that allow you to log the requests and mock the responses. You can also create a custom HTTP request hook, which enables you, for instance, to emulate authentications like Kerberos or Client Certificate Authentication.

Log HTTP Requests

You can use the request logger to record HTTP requests the tested web app sends and responses it receives. For instance, you may want to make sure that the data from a remote service is correct.

Use the RequestLogger constructor to create a request logger.

import { RequestLogger } from 'testcafe';

const simpleLogger = RequestLogger('http://example.com');
const headerLogger = RequestLogger(/testcafe/, {
    logRequestHeaders: true,
    logResponseHeaders: true
});

To enable the logger to track requests, attach the logger to a test or fixture.

The RequestLogger stores the following parameters by default:

  • The URL where the request is sent.
  • The request's HTTP method.
  • The status code received in the response.
  • The user agent that sent the request.

Use the logger's API to access the data it stores.

Member Description
contains Returns whether the logger contains a request that matches the predicate.
count Returns the number of requests that match the predicate.
clear Clears all logged requests.
requests Returns an array of logged requests.

Example

import { Selector, RequestLogger } from 'testcafe';
import fs from 'fs';
import path from 'path';

const url = 'https://demos.devexpress.com/ASPxGridViewDemos/Exporting/Exporting.aspx';

const logger = RequestLogger({ url, method: 'post' }, {
    logResponseHeaders: true,
    logResponseBody:    true
});

fixture `Export`
    .page(url)
    .requestHooks(logger);

test('export to csv', async t => {
    const exportToCSVButton = Selector('span').withText('Export to CSV');

    await t
        .click(exportToCSVButton)
        .expect(logger.contains(r => r.response.statusCode === 200)).ok();

    // After clicking 'Export', the response comes as a gziped CSV.
    // The browser unpacks the archive and gives you the file that was inside.
    // The test receives the archive as is.
    const filePath = path.join(__dirname, 'exported-grid.zip');

    console.log(filePath);
    console.log(logger.requests[0].response.headers);

    fs.writeFileSync(filePath, logger.requests[0].response.body);

    // Here you can use 3rd party modules to
    // unpack the archive, parse CSV and check the data.
    // Or you can just verify the file manually.
});

Mock HTTP Requests

Use TestCafe request mocker to substitute infrastructure that is difficult to deploy or that you do not want to use for test purposes. This can be a third-party service that charges you per pageview or an analytics service that should not log page views that tests generate. The mocker can intercept requests to this resource and emulate the response as needed.

Use the RequestMock constructor to create a request mocker.

var mock = RequestMock();

Then call the onRequestTo and respond methods in a chained fashion. The onRequestTo method specifies a request to intercept, while the respond method specifies the mocked response for this request. Call these methods repeatedly to provide a mock for every request you need.

var mock = RequestMock()
    .onRequestTo(request1)
    .respond(responseMock1)
    .onRequestTo(request2)
    .respond(responseMock2);

Next, attach it to a test or fixture.

Example

import { Selector, RequestMock } from 'testcafe';

// A URL to which Google Analytics sends data.
const collectDataGoogleAnalyticsRegExp = new RegExp('https://www.google-analytics.com/collect');

// Technically, Google Analytics sends an XHR request for a GIF image.
// So, the mocked response should contain binary data.
const mockedResponse = Buffer.from([0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x01, 0x00, 0x01]);

const mock = RequestMock()
    .onRequestTo(collectDataGoogleAnalyticsRegExp)

    // The hook responds to Analytics requests with the prepared data
    // represented as a GIF image and changes the status code to 202.
    .respond(mockedResponse, 202, {
        'content-length': mockedResponse.length,
        'content-type': 'image/gif'
    });

fixture `Fixture`
    .page('https://devexpress.github.io/testcafe/')
    .requestHooks(mock);

test('basic', async t => {
    await t
        .click('.get-started-button')

        // During the pause, you can open DevTools and
        // find the request sent to Analytics
        // and the mocked response received.
        .debug();
});

Create a Custom Request Hook

You can create your own request hook to handle HTTP requests. This topic describes request hooks and how to create a custom hook.

Do the following to write a custom hook:

  • inherit from the RequestHook class,
  • override the onRequest method to handle the request before it is sent,
  • override the onResponse method to handle the response after it is received.
import { RequestHook } from 'testcafe';

export class MyRequestHook extends RequestHook {
    constructor (requestFilterRules, responseEventConfigureOpts) {
        super(requestFilterRules, responseEventConfigureOpts);
        // ...
    }
    async onRequest (event) {
        // ...
    }
    async onResponse (event) {
        // ...
    }
}

In test code, create a hook instance and attach it to a test or fixture.

import { MyRequestHook } from './my-request-hook';

const customHook = new MyRequestHook(/https?:\/\/example.com/);

fixture `My fixture`
    .page('http://example.com')
    .requestHooks(customHook);

test('My test', async t => {
        // test actions
});

Example

import { Selector, RequestHook } from 'testcafe';

class JwtBearerAuthorization extends RequestHook {
    constructor () {
        // No URL filtering applied to this hook
        // so it will be used for all requests.
        super();
    }

    onRequest (e) {
        e.requestOptions.headers['Authorization'] = 'generate token here';
    }

    onResponse (e) {
        // This method must also be overridden,
        // but you can leave it blank.
    }
}

const jwtBearerAuthorization = new JwtBearerAuthorization();

fixture `Fixture`
    .page('<website URL>')
    .requestHooks(jwtBearerAuthorization);

test('basic', async t => {
    /* some actions */
});

Attach Hooks to Tests and Fixtures

To attach a hook to a test or fixture, use the fixture.requestHooks and test.requestHooks methods. A hook attached to a fixture handles requests from all tests in the fixture.

Hooks attached to a fixture are invoked before the hooks attached to individual tests.

You can use the t.addRequestHooks and t.removeRequestHooks methods to attach and detach hooks during the test.

import { RequestLogger, RequestMock } from 'testcafe';

const logger = RequestLogger('http://example.com');
const mock   = RequestMock()
    .onRequestTo('http://external-service.com/api/')
    .respond({ data: 'value' });

fixture `My fixture`
    .page('http://example.com')
    .requestHooks(logger);

test
    .requestHooks(mock)
    ('My test', async t => {
    await t
         .click('#send-logged-request')
         .expect(logger.count(() => true)).eql(1)
         .removeRequestHooks(logger)
         .click('#send-unlogged-request')
         .expect(logger.count(() => true)).eql(1)
         .addRequestHooks(logger)
         .click('#send-logged-request')
         .expect(logger.count(() => true)).eql(2);
});