Tanmoy Basak
Tanmoy Basak

Reputation: 142

Testing axios interceptors with jest

I am using an axios interceptor to add authorization token to its header. The interceptor works fine.

//api.js
import { getAccessToken } from "./utils";

const apiInstance = axios.create();

apiInstance.interceptors.request.use((configIns) => {

  const token = getAccessToken();
  configIns.headers.Authorization = token ? `Bearer ${token}` : "";
  return configIns;

});

export { apiInstance };

Here is my test file to test the interceptor.

// api.test.js

import { apiInstance } from "./api"
import {getAccessToken} from "./utils";

describe("request interceptor", () => {
    it("API request should add authorization token to header", () => {

      const getAccessToken = jest.fn(getAccessToken);
      getAccessTokenMock.mockReturnValue("token");

      const result = apiInstance.interceptors.request.handlers[0].fulfilled({ headers: {} });

      expect(getAccessTokenMock.mock.calls.length).toBe(1);
      expect(result.headers).toHaveProperty("Authorization");
    });
  });

However the getAccessToken function in not getting mocked for some reason inside the interceptor. The test fails.

Upvotes: 3

Views: 11524

Answers (1)

jjanczyk
jjanczyk

Reputation: 481

That's not how mocks in Jest work. By calling (I assume variable should be getAccessTokenMock, not getAccessToken):

const getAccessTokenMock = jest.fn(getAccessToken);
getAccessTokenMock.mockReturnValue("token");

What you do is: you create new local mock, that when called, would call your getAccessToken function. Then you mock return value. However, your getAccessTokenMock is never called, because it's not the same instance as in your implementation!

What you need to do is mock your actual function getAccessToken from your ./utils file. It can be done, for example, like this:

import { apiInstance } from "./api"
import {getAccessToken} from "./utils";

// Mock here:
jest.mock('./utils', () => ({
  getAccessToken: jest.fn(() => 'token')
});

describe("request interceptor", () => {
  it("API request should add authorization token to header", () => {
    const result = apiInstance.interceptors.request.handlers[0].fulfilled({ headers: {} });

    expect(getAccessToken.mock.calls.length).toBe(1);
    expect(result.headers).toHaveProperty("Authorization");
  });
});

What is happening here is that when file is loaded, jest.mock would run first and would replace your implementation of getAccessToken with the mock - it would be then accessible from both implementation and test (as the same instance), meaning that you can verify if it has been called.

Please find more about mocks here or here. Alternatively you can also use spyOn to achieve similar result (then you don't need jest.mock, but you have to import your getAccessToken function without destructuring).

Upvotes: 4

Related Questions