【问题标题】:how to test axios interceptors with jest如何用 jest 测试 axios 拦截器
【发布时间】: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);
    }
);

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

我试过了:

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

谢谢

【问题讨论】:

    标签: javascript typescript jestjs 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
        猜你喜欢
        • 2019-04-28
        • 2021-07-15
        • 2019-03-15
        • 2020-12-18
        • 2019-05-30
        • 2020-01-03
        • 1970-01-01
        • 2020-11-24
        • 2019-06-26
        相关资源
        最近更新 更多