Islam Rostom
Islam Rostom

Reputation: 171

how to test axios interceptors with jest

In my project, I have a namespace that exports some functions that use Axios, in the same file I add an interceptor to axios instance like that :

axios.interceptors.response.use(
    (res) => res,
    (error) => {
      if (
        error.response &&
        (error.response.status?.toString() === "400" ||
          error.response.status?.toString() === "403" ||
          error.response.status?.toString() === "404")
      ) {
        return Promise.reject(
          Error(JSON.stringify(error.response.data?.status?.errors[0]))
        );
      } else if (error.response) {
        return Promise.reject(
          Error(
            `server responsed with the following code: ${error.response?.status} and the following message: ${error.response?.statusText}`
          )
        );
      } else if (error.request) {
        return Promise.reject(
          Error(
            "The request was made but no response was received, check your network connection"
          )
        );
      } else Promise.reject(error);
    }
);

I want to test that this interceptor works as expected, I search the forms here and googled a lot but all the answers are basically mocking the interceptor not testing it.

I have tried:

  1. mocking the response of an axios post request and checking the AxiosPromise that gets returned but it only contained the result I mocked. it seems that it ignores the interceptor when I mock using mockResolvedValue.
  2. I have tried adding an interceptor to the mocked axios instance but that did not work too.

Thanks

Upvotes: 17

Views: 26148

Answers (4)

Vu Nguyen
Vu Nguyen

Reputation: 21

I have the same issue with you and this is how I solved it:

  const axiosResponse = await axios.get(your-url);

  expect(axiosResponse.config.headers.Authorization).toBe('Bearer test-token');

From the axiosResponse you can test all of logic you set in the interceptors

Upvotes: 2

ueznem
ueznem

Reputation: 97

What about pulling the function out and testing it without axios?

import axios, { AxiosError, AxiosResponse } from 'axios'

export const onFulfilled = (response: AxiosResponse) => {
  // Your interceptor handling a successful response
}
export const onRejected = (error: AxiosError) => {
  // Your interceptor handling a failed response
}

axios.interceptors.response.use(onFulfilled, onRejected)

Now you can test the functions onFullfilled and onRejected with less dependencies to axios.

Upvotes: 5

Hakob Khurshudyan
Hakob Khurshudyan

Reputation: 25

Use this mock functionality

jest.mock('axios', () => {
   return {
      interceptors: {
         request: {
            use: jest.fn(),
            eject: jest.fn()
         },
         response: {
            use: jest.fn(),
            eject: jest.fn()
         },
      },
   };
});

Upvotes: -3

lueenavarro
lueenavarro

Reputation: 606

You have to mock the interceptor and run the callbacks.

Here is an example on how to do it:

httpService.ts

import axios from "axios";
import { toast } from "react-toastify";

axios.interceptors.request.use((config) => {
  config.baseURL = process.env.API_URL || "http://localhost:5000";
  return config;
});

axios.interceptors.response.use(null, (error) => {
  const expectedError =
    error.response &&
    error.response.status >= 400 &&
    error.response.status < 500;

  if (!expectedError) {
    toast.error("An unexpected error occured");
  }

  return Promise.reject(error);
});

export default {
  get: axios.get,
  post: axios.post,
  put: axios.put,
  delete: axios.delete,
};

httpService.test.ts

import axios from "axios";
import { toast } from "react-toastify";
import "./httpService";

jest.mock("axios", () => ({
  __esModule: true,
  default: {
    interceptors: {
      request: { use: jest.fn(() => {}) },
      response: { use: jest.fn(() => {}) },
    },
  },
}));

const fakeError = {
  response: {
    status: undefined,
  },
};

const mockRequestCallback = (axios.interceptors.request.use as jest.Mock).mock
  .calls[0][0];
const mockResponseErrorCallback = (axios.interceptors.response.use as jest.Mock)
  .mock.calls[0][1];
const toastErrorSpy = jest.spyOn(toast, "error");

beforeEach(() => {
  toastErrorSpy.mockClear();
});

test("request error interceptor", () => {
  expect(mockRequestCallback({})).toStrictEqual({
    baseURL: "http://localhost:5000",
  });
});

test("unexpected error on response interceptor", () => {
  fakeError.response.status = 500;

  mockResponseErrorCallback(fakeError).catch(() => {});
  expect(toastErrorSpy).toHaveBeenCalled();
});

test("expected error on response interceptor", () => {
  fakeError.response.status = 400;

  mockResponseErrorCallback(fakeError).catch(() => {});
  expect(toastErrorSpy).not.toHaveBeenCalled();
});

Upvotes: 3

Related Questions