如何用 jest 测试 axios 拦截器

Posted

技术标签:

【中文标题】如何用 jest 测试 axios 拦截器【英文标题】:how to test axios interceptors with jest 【发布时间】:2021-05-04 21:21:25 【问题描述】:

在我的项目中,我有一个命名空间,用于导出一些使用 Axios 的函数,在同一个文件中,我向 axios 实例添加了一个拦截器,如下所示:

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);
    
);

我想测试这个拦截器是否按预期工作,我在这里搜索表单并用谷歌搜索了很多,但所有答案基本上都是在嘲笑拦截器而不是测试它。

我试过了:

    模拟 axios 发布请求的响应并检查返回的 AxiosPromise,但它只包含我模拟的结果。当我使用mockResolvedValue 模拟时,它似乎忽略了拦截器。 我尝试向模拟的 axios 实例添加一个拦截器,但这也不起作用。

谢谢

【问题讨论】:

【参考方案1】:

使用这个模拟功能

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

【讨论】:

【参考方案2】:

您必须模拟拦截器并运行回调。

下面是一个例子:

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();
);

【讨论】:

【参考方案3】:

不使用 axios 把函数拉出来测试一下怎么样?

import axios,  AxiosError, AxiosResponse  from 'axios'

export const onFullfilled = (response: AxiosResponse) => 
  // Your interceptor handling a successful response

export const onRejected = (error: AxiosError) => 
  // Your interceptor handling a failed response


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

现在您可以测试函数 onFullfilled 和 onRejected,减少对 axios 的依赖。

【讨论】:

这样测试会遗漏一部分,因为这些拦截器是否有效并不明显。 这仍然错过了@EstusFlask 上面解释的要点。但是谢谢 也许我可以尝试这种解决方法并测试它们是否被调用。但我不确定这是否正确。我会试一试,lyk。 @simon flepp

以上是关于如何用 jest 测试 axios 拦截器的主要内容,如果未能解决你的问题,请参考以下文章

使用 jest.mock('axios') 时如何模拟拦截器?

如何用 jest 测试 redux saga?

Axios 中的单元测试拦截器逻辑

如何用CORS来解决JS中跨域的问题

vue axios拦截器常用之重复请求取消

vue axios拦截器常用之重复请求取消