Jest - Create React App - Axios: test get mocked

Viewed 264

I have a axiosInstance.js axios instance:

import axios from "axios"
import { REACT_FE_ACCESS_TOKEN } from "../../constants/constant";

const axiosInstance = axios.create({
  baseURL: process.env.REACT_APP_BACKEND_URL,
  headers: {
    "content-type": "application/json"
  },
  responseType: "json"
});

axiosInstance.interceptors.request.use((config) => {

  const token = localStorage.getItem(REACT_FE_ACCESS_TOKEN);
  if (token) {
    config.headers.Authorization = `Bearer ${token}`;
  }
  return config;

});

export { axiosInstance };

I call it from a class:

import { axiosInstance as api } from "./axiosInstance";

export default class ApiCrud {

  constructor(baseUrl) {
    this.baseUrl = baseUrl;
  }

  fetchItems() {
    return api.get(`${this.getBaseUrl()}`).then(result => result.data);
  }

  getBaseUrl() {
    return this.baseUrl;
  }

}

I want to do a write test (using Create React App and Jest).

This is the axiosInstance.test.js file, that works:

import { axiosInstance } from "../../../../utils/api/base/axiosInstance";
import { REACT_FE_ACCESS_TOKEN } from "../../../../utils/constants/constant";

const token = "a1.b2.c3";

beforeEach(() => {
  localStorage.clear();
});

describe('Test API Instance', () => {
  it ('Test request interceptor with token', () => {
    localStorage.setItem(REACT_FE_ACCESS_TOKEN, token);
    expect(localStorage.getItem(REACT_FE_ACCESS_TOKEN)).toBe(token);
    const result = axiosInstance.interceptors.request.handlers[0].fulfilled({ headers: {} });
    expect(result.headers).toHaveProperty("Authorization");
  });

  it ('Test request interceptor without token', () => {
    const result = axiosInstance.interceptors.request.handlers[0].fulfilled({ headers: {} });
    expect(result.headers).not.toHaveProperty("Authorization");
  });
});

This is the apiCrud.test.js

import ApiCrud from "../../../../utils/api/base/ApiCrud";

const mockedGet = {
  email: "info@example.com",
}

jest.mock('axios', () => {
  return {
    create: jest.fn(() => ({
      get: jest.fn(() => Promise.resolve({ data: mockedGet })),
      interceptors: {
        request: { use: jest.fn(), eject: jest.fn() },
        response: { use: jest.fn(), eject: jest.fn() }
      }
    }))
  }
})

describe('Test API crud', () => {


  it ('Test can get base url', () => {
    const apiCrud = new ApiCrud('/fake-url');
    expect(apiCrud.getBaseUrl()).toBe('/fake-url');
  });

  it ('Test can fetch items', () => {
    const apiCrud = new ApiCrud('/fake-url');
    return apiCrud.fetchItems().then(data => {
      expect(data).toBe(mockedGet);
    })
  });
});

But I get

 FAIL  src/__tests__/utils/api/base/apiCrud.test.js
  ● Test API crud › Test can fetch items

    TypeError: Cannot read property 'then' of undefined

       8 |
       9 |   fetchItems() {
    > 10 |     return api.get(`${this.getBaseUrl()}`).then(result => result.data);
         |            ^
      11 |   }
      12 |
      13 |   getBaseUrl() {

      at ApiCrud.fetchItems (src/utils/api/base/ApiCrud.js:10:12)
      at Object.<anonymous> (src/__tests__/utils/api/base/apiCrud.test.js:29:20)

So, I think I'm getting wrong with mocking the get for axios, but... How solve?

1 Answers

You are testing ApiCrud class that depends on the ./axiosInstance module. It's simpler to mock direct dependency ./axiosInstance module than indirect dependency - axios module.

ApiCrud.js:

import { axiosInstance as api } from './axiosInstance';

export default class ApiCrud {
  constructor(baseUrl) {
    this.baseUrl = baseUrl;
  }

  fetchItems() {
    return api.get(`${this.getBaseUrl()}`).then((result) => result.data);
  }

  getBaseUrl() {
    return this.baseUrl;
  }
}

ApiCrud.test.js:

import ApiCrud from './ApiCrud';
import { axiosInstance } from './axiosInstance';

const mockedGet = {
  email: 'info@example.com',
};
jest.mock('./axiosInstance');

describe('Test API crud', () => {
  afterEach(() => {
    jest.clearAllMocks();
  });
  afterAll(() => {
    jest.resetAllMocks();
  });
  it('Test can get base url', () => {
    const apiCrud = new ApiCrud('/fake-url');
    expect(apiCrud.getBaseUrl()).toBe('/fake-url');
  });

  it('Test can fetch items', () => {
    axiosInstance.get.mockResolvedValueOnce({ data: mockedGet });
    const apiCrud = new ApiCrud('/fake-url');
    return apiCrud.fetchItems().then((data) => {
      expect(data).toBe(mockedGet);
    });
  });
});

test result:

 PASS  examples/69531160/ApiCrud.test.js (10.676 s)
  Test API crud
    ✓ Test can get base url (3 ms)
    ✓ Test can fetch items (1 ms)

------------------|---------|----------|---------|---------|-------------------
File              | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
------------------|---------|----------|---------|---------|-------------------
All files         |   73.33 |        0 |      80 |   71.43 |                   
 ApiCrud.js       |     100 |      100 |     100 |     100 |                   
 axiosInstance.js |   55.56 |        0 |       0 |   55.56 | 13-17             
------------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        14.978 s
Related