How can I mock this http request using jest?

Viewed 15667

I am new to using Jest for unit tests. How can I mock this simple http request method "getData"? Here is the class:

const got = require("got")

class Checker {


    constructor() {
        this.url

        this.logData = this.logData.bind(this);
        this.getData = this.getData.bind(this);

    }

    async getData(url) {
        const response = await got(url);
        const data = await response.body;
        return data;
    }

    async logData(first, second, threshold) {
        
        let data = await this.getData(this.url)
        
        console.log("received " + data.body);

    }

}

I am trying to mock "getData" so I can write a unit test for "logData". Do I need to mock out the entire "got" module? Thanks.

3 Answers

If you change invoking got to got.get you should be able to have a working test like so:

const got = require('got');
const Checker = require('../index.js');

describe("some test", () => {
    beforeEach(() => {
        jest.spyOn(got, 'get').mockResolvedValue({ response: { body: { somekey: "somevalue" } } } );
    });
    it("works", async () => {
        new Checker().getData();
        expect(got.get).toBeCalledTimes(1);
    })
})

One approach is to use dependency injection. Instead of calling 'got' directly, you can 'ask for it' in the class constructor and assign it to a private variable. Then, in the unit test, pass a mock version instead which will return what you want it to.

const got = require("got");
class Checker {
    constructor(gotService) {
        this.got = gotService;
        this.logData = this.logData.bind(this);
        this.getData = this.getData.bind(this);
    }

    async getData(url) {
        const response = await this.got(url);
        const data = await response.body;
        return data;
    }

    async logData(first, second, threshold) {        
        let data = await this.getData(this.url)        
        console.log("received " + data.body);
    }
}

//real code
const real = new Checker(got);

//unit testable code
const fakeGot = () => Promise.resolve(mockedData);
const fake = new Checker(fakeGot);

Here is what we are doing:

  1. 'Inject' got into the class.
  2. In the class, call our injected version instead of directly calling the original version.
  3. When it's time to unit test, pass a fake version which does what you want it to.

You can include this directly inside your test files. Then trigger the test that makes the Http request and this will be provided as the payload.

global.fetch = jest.fn(() =>
  Promise.resolve({
    json: () => Promise.resolve({ data: { eth: 0.6, btc: 0.02, ada: 1 } }),
  })
);

it('should return correct mock token values', async () => {
  const addresses = ["mockA", "mockB", "mockC"];
  const res = await getTokenData(addresses);
  expect(res.data).toEqual({ eth: 0.6, btc: 0.02, ada: 1 });
});
Related