如何模拟 axios.create([config]) 函数到 return 它的实例方法而不是用模拟覆盖它们?

How to mock axios.create([config]) function to return its instance methods instead of overriding them with mock?

我正在尝试模拟 axios.create() 因为我在整个应用程序中使用它的实例并且显然需要它的所有实现被破坏mock,因此无法正确获取 get, post 方法的结果。

代码在实际文件中是这样的:

 export const axiosInstance = axios.create({
        headers: {
           ...headers
        },
        transformRequest: [
            function (data, headers) {
                return data;
            },
        ],
    });
    const response = await axiosInstance.get(endpoint);

这是测试文件中 axios 的模拟设置

   jest.mock('axios', () => {
        return {
            create: jest.fn(),
            get: jest.fn(() => Promise.resolve()),
        };
    }
);

我怎样才能获得 axiosInstance 变量中的所有实例方法,而不是仅仅拥有一个什么都不做的模拟函数?

axios.create 和实例方法的文档:https://github.com/axios/axios#instance-methods

你可以使用 jest 的 genMockFromModule。它将为每个模块的方法生成 jest.fn(),您将能够在 create 到 return 相同实例上使用 .mockReturnThis()

示例:

./src/__mocks__/axios.js
const axios = jest.genMockFromModule('axios');

axios.create.mockReturnThis();

export default axios;
working example

编辑:

Jest 26.0.0+ 重命名为 jest.createMockFromModule

最终坚持使用 axios 模拟并通过将 axiosInstance 指针分配给创建的 axios 模拟来指向该模拟。 基本上正如 @jonrsharpe 建议的

简要说明:

import * as m from 'route';
jest.mock('axios', () => {
        return {
            create: jest.fn(),
            get: jest.fn(() => Promise.resolve()),
        };
    }
);
m.axInstance = axios

如果没有它我会很高兴。

以下代码有效!

jest.mock("axios", () => {
    return {
        create: jest.fn(() => axios),
        post: jest.fn(() => Promise.resolve()),
    };
});

因为我需要管理 Axios 实例,所以我需要一种方法来检索创建的模拟,以便我可以操纵响应。这是我的做法。

import type { AxiosInstance, AxiosStatic } from 'axios';

const mockAxios = jest.createMockFromModule<AxiosStatic>('axios') as jest.Mocked<AxiosStatic>;

let mockAxiosInstances: jest.Mocked<AxiosInstance>[] = [];

mockAxios.create = jest.fn((defaults) => {
  const mockAxiosInstance = jest.createMockFromModule<AxiosInstance>(
    'axios'
  ) as jest.Mocked<AxiosInstance>;
  mockAxiosInstance.defaults = { ...mockAxiosInstance.defaults, ...defaults };
  mockAxiosInstances.push(mockAxiosInstance);
  return mockAxiosInstance;
});

export function getMockAxiosInstances() {
  return mockAxiosInstances;
}
export function mostRecentAxiosInstanceSatisfying(fn: (a: AxiosInstance) => boolean) {
  return mockAxiosInstances.filter(fn).at(-1);
}
export function clearMockAxios() {
  mockAxiosInstances = [];
}

export default mockAxios;

我添加了三个额外的方法:

  • 清除实例列表的clearMockAxios
  • getMockAxiosInstances 获取 axios.create
  • 生成的 axios 实例列表
  • mostRecentAxiosInstanceSatisfying 是一个函数,它将执行过滤器以获取满足谓词的最新 axios 实例。这是我通常在测试用例中使用的,因为 React 可能会呈现比预期(或预期)更多的内容,而我通常只需要最后一个实例。

我是这样使用的:

import { getMockAxiosInstances, mostRecentAxiosInstanceSatisfying, clearMockAxios } from '../../__mocks__/axios';

it("...", () => {

  ...
  
  const mockAppClient = mostRecentAxiosInstanceSatisfying(
    a => a.defaults.auth?.username === "myusername"
  );
  mockAppClient.post.mockImplementation(() => {
    return Promise.resolve({ data: "AAA" })
  })

  ... do something that calls the client ...

});