Zebra Codes

How to Mock an HTTP Request in NodeJS with JEST

6th of February, 2023

Performing a real HTTP request in a unit test can make it slow and brittle, so the solution is to mock the Node HTTP library. This guide will show you how to create mock objects that simulate successful and unsuccessful HTTP requests.

Mocking the ‘http’/’https’ Library

If you are using dependency injection and passing the http object into your class then this is simple: create a new object and implement the methods you use via JEST’s jest.fn() function.

test('Test an HTTP request with dependency injection', async () => {
    const http = {
        get: jest.fn(...),
    };

    // Call the function under test and check the expected result.
    const result = functionUnderTest(http);
    expect(result).toBe(true);
}

If you are not using dependency injection then you can use jest.mock() to override it globally:

test('Test an HTTP request without dependency injection', async () => {
    const mock = {
        get: jest.fn(...),
    };

    jest.mock('http', () => mock);

    // Call the function under test and check the expected result.
    const result = functionUnderTest();
    expect(result).toBe(true);
}

Mocking the Request and Response

When http.get() is called it must return an http.Request object. This will then return an http.Response object in the response event handler. You must respond to these events by returning mock objects. These objects should extend EventEmitter. Note that the callback parameter to the http.get()function is bound to the request event on the request object.

test('Test an HTTP request with dependency injection', async () => {
    const request = new EventEmitter();

    const http = {
        get: jest.fn((url, options, callback) => { request.on('request', callback); return request; }),
    };

    const response = new EventEmitter();
    response.statusCode = 200;

    // The response starts by emitting a 'request' event.
    request.emit('request', response);

    // The response body is returned in the 'data' event, followed by 'end'.
    response.emit('data', 'page contents');
    response.emit('end');

    // Indicate that no more responses will be sent.
    request.emit('close');

    // Call the function under test and check the expected result.
    const result = functionUnderTest(http);
    expect(result).toBe(true);
}