Jitender
Jitender

Reputation: 7969

How to improve test coverage Jest, Enzyme

By following code I am able to get 66.27 branch coverage and the matrix still show that some improvement can done on line 27. I did some hit and trial but none work for me. any suggestion would be appreciated.

matrix

enter image description here

requestService.js

import axios from 'axios';
import HttpError from 'standard-http-error';


export const successResponse = response => (
  {
    status: response.status,
    data: response.data,
  }
);


export const throwHttpError = (error) => {
  if (error.response.data) {
    throw new HttpError(error.response.status, error.response.statusText, {
      data: error.response.data,
    });
  }

  throw new HttpError(error.response.status, error.response.statusText);
};

**line no: 27**
export default async (request, httpService = axios) => {
  const {
    method, url, data, headers,
  } = request;
  return httpService.request({
    method,
    url,
    headers: Object.assign({}, headers),
    data,
  }).then(successResponse, (error) => {
    throwHttpError(error);
  });
};

requestService.test.js

  import HttpError from 'standard-http-error';
import request, { successResponse, throwHttpError } from './requestService';

describe('requestService', () => {
  describe('successResponse', () => {
    const mockRes = {
      status: 9001,
      data: {
        stuff: 'stuff',
      },
    };
    it('should returns an object with only status and data properties', () => {
      const responseKeys = Object.keys(successResponse(mockRes));
      expect(responseKeys).toMatchObject(['status', 'data']);
      expect(responseKeys.length).toBe(2);
    });

    it('should map the status of the reponse to the status property', () => {
      expect(successResponse(mockRes).status)
        .toBe(mockRes.status);
    });

    it('should map the data of the reponse to the data property', () => {
      expect(successResponse(mockRes).data)
        .toMatchObject(mockRes.data);
    });

    it('should have a valid request object', async () => {
      const requestObj = {
        method: 'POST',
        url: 'http://mock.url',
        data: {},
        headers: {},
      };

      const mockRequest = jest.fn(() => Promise.resolve({}));

      const httpService = {
        request: mockRequest,
      };

      await request(requestObj, httpService);
      expect(mockRequest).toHaveBeenCalledWith({
        method: requestObj.method,
        url: requestObj.url,
        headers: {},
        data: requestObj.data,
      });
    });
  });

  describe('httpThrowError', () => {
    const mockErr = {
      response: {
        status: 9001,
        statusText: 'error message goes here',
      },
    };

    it('should map the status of the reponse to the error.status property', () => {
      try {
        throwHttpError(mockErr);
      } catch (e) {
        expect(e).not.toBe(null);
        expect(e.status).toBe(mockErr.response.status);
        expect(e.message).toBe(mockErr.response.statusText);
      }
    });

    it('should map the data of the reponse to the error.data property', () => {
      const mockErrWithData = Object.assign({}, mockErr);
      mockErrWithData.response.data = {};
      try {
        throwHttpError(mockErrWithData);
      } catch (e) {
        expect(e).not.toBe(null);
        expect(e.data).toBe(mockErrWithData.response.data);
      }
    });
  });

  describe('request', () => {
    const testCases = [
      ['should return error response on server error', 500],
      ['should return error response on bad request', 400],
      ['should return error response on unauthorised', 401],
    ];

    testCases.forEach(([testName, errorStatus]) => {
      it(testName, async () => {
        const errorResponse = {
          response: {
            status: errorStatus,
          },
        };
        const mockRequest = jest.fn(() => Promise.reject(errorResponse));

        const httpService = {
          request: mockRequest,
        };

        try {
          await request({ url: 'http://mock.url' }, httpService);
          throw new Error('Expected an exception, but none was thrown');
        } catch (err) {
          expect(err).not.toBe(null);
          expect(err).toMatchObject(
            new HttpError(errorResponse.response.status,
              errorResponse.response.statusText),
          );
        }
      });
    });

    it('should return an valid response (empty)', async () => {
      const response = {
        data: {
          meta: {},
          results: [],
        },
        status: 200,
        statusText: 'OK',
        headers: {},
        config: {},
        request: {},
      };

      const mockRequest = jest.fn(() => Promise.resolve(response));

      const httpService = {
        request: mockRequest,
      };

      const res = await request({ url: 'http://mock.url' }, httpService);

      expect(res).not.toBe(null);
      expect(res).toMatchObject(
        {
          status: response.status,
          data: response.data,
        },
      );
    });
  });
});



  [1]: https://i.sstatic.net/GErLI.png

Upvotes: 2

Views: 4229

Answers (1)

Estus Flask
Estus Flask

Reputation: 222503

Since throwHttpError and request function reside in same module, it's impossible to spy on throwHttpError, so request result should be tested similarly to how throwHttpError is tested.

It should be something like:

const errorResponse = {
  response: {
    status: errorStatus,
  },
};
const mockRequest = jest.fn(() => Promise.reject(errorResponse));

const httpService = {
  request: mockRequest,
};

const resPromise = request({ url: 'http://mock.url' }, httpService);

await expect(resPromise).rejects.toMatchObject(
  new HttpError(errorResponse.response.status,
    errorResponse.response.statusText),
);

Upvotes: 3

Related Questions