4

I have written a simple unit test for API call using NockJS and Jest for a react application as bellow:

AjaxService.js

export const AjaxService = {
    post: (url, data, headers) => {
        return axios({
            method: "POST",
            url: url,
            headers: headers || { "content-type": "application/json" },
            data: data
        });
    },
};

API Promise:

export const getDashboard = (request) => {
  return AjaxService.post(API_DASHBOARD_URL + "/getDashboard", request
  ).then(
    response => {
      return response.data;
    },
    (error) => {
      return error.response.data;
    }
  )
};

Unit test using NockJS:

nock(baseUrl)
    .post(subUrl, request)
    .reply(200, response);

getDashboard(request)
    .then(resp => {
        let compareVal = getNestedObject(resp, keyToCompare);
        let actualVal = getNestedObject(response, keyToCompare);
        expect(compareVal).to.equal(actualVal);
    })
    .then(() => {});

But when the code-coverage report is generated using Jest --coverage as below:

enter image description here

We can see that in promise, success callback and error callback is not called during unit test. How to cover this part of code as it affects code-coverage percentage when an application is having numerous API calls? Or am I not testing is properly? Please help as I am new to unit testing. Thanks in advance.

Suraj A J
  • 359
  • 4
  • 19
  • Just to confirm, the `baseUrl` value being passed to nock is the same `API_DASHBOARD_URL` correct? I want to make sure you're mocking the outbound request from your app and not the inbound request to the app. – Matt R. Wilson Aug 27 '19 at 23:16
  • Yes!. BaseUrl and API_DASHBOARD_URL is the same. – Suraj A J Aug 28 '19 at 05:49
  • What is `AjaxService`? Have you tried messing with the contents of your success callback to see if the test still passes? – Matt R. Wilson Aug 28 '19 at 13:28
  • AjaxService will return axios instance. And no I have not tried to change any contents of callbacks. I have updated question. Please check. – Suraj A J Aug 29 '19 at 06:18

1 Answers1

5

Jest counts a line as covered only if it runs during a test.

In this case it looks like you are calling getDashboard during the test...

...but getDashboard is asynchronous and the test isn't waiting for it to finish.

This means that the test completes synchronously before the asynchronous code in getDashboard has a chance to run and any code that hasn't run yet is not included in the Jest code coverage.

To make sure that code is properly tested and included in the code coverage make sure you await the Promise returned by getDashboard:

test('getDashboard', async () => {  // <= async test function
  nock(baseUrl)
    .post(subUrl, request)
    .reply(200, response);

  await getDashboard(request)  // <= await the Promise
    .then(resp => {
      let compareVal = getNestedObject(resp, keyToCompare);
      let actualVal = getNestedObject(response, keyToCompare);
      expect(compareVal).to.equal(actualVal);
    })
})
Brian Adams
  • 43,011
  • 9
  • 113
  • 111
  • Or you can `return` (instead of `await`) the `Promise` in the `test`, in case the callback is not written as `async`. See [this example](https://github.com/reduxjs/redux-mock-store#asynchronous-actions) – Fanchen Bao Apr 19 '20 at 02:59