javascripttypescriptaxiosvitest

Mocking axios.create using vitest


I am using axios.create method to create and configure axios instance. And I can't get it to work in tests with vi.fn() so I cannot assert if endpoint was called.

workaround for tests to be able to return data from api calls looks like

  return {
    AxiosInstance: {},
    AxiosRequestConfig: {},
    default: {
      post: vi.fn(),
      create: vi.fn(() => {
        return {
          post: (url: string, config: object) => {
            return Promise.resolve({ status: 200 });
          },
          get: (url: string, config: object) => {
            return Promise.resolve({ status: 200 });
          },
          interceptors: {
            request: {
              use: vi.fn(),
              eject: vi.fn(),
            },
            response: {
              use: vi.fn(),
              eject: vi.fn(),
            },
          },
        };
      }),
    },
  };
});

But would like to use something like

    (axios.get as MockedFunction<typeof axios.get>).mockImplementationOnce(
      () => promise
    );

maybe someone mocked axios.create using vitest and could share configuration?


Solution

  • If, for instance, you're using axios.create() in your codebase to generate an AxiosInstance, you can mock this functionality as follows in your Vitest test file:

    const mocks = vi.hoisted(() => ({
      get: vi.fn(),
      post: vi.fn(),
    }));
    
    vi.mock('axios', async(importActual) => {
      const actual = await importActual<typeof import ('axios')>();
    
      const mockAxios = {
        default: {
          ...actual.default,
          create: vi.fn(() => ({
            ...actual.default.create(),
            get: mocks.get,
            post: mocks.post,
          })),
        },
      };
    
      return mockAxios;
    });

    Initially, we set up the mocks object that includes the get and post functions we want to mock. Using vi.hoisted(), we ensure these mocked functions are hoisted (i.e., moved to the top of the scope), allowing us to reference them within our vi.mock() function.

    Then, we mock the entire axios module using vi.mock(). In order to maintain the existing functionality that we don't intend to mock, we employ importActual to import the real axios module. We then specify the parts we wish to mock, namely the create function and the get/post functions.

    With these mocks in place, we can now spy on our mocked get and post methods. Here's an example of how to do it:

    it('should call axios.get', async() => {
      mocks.get.mockResolvedValueOnce({
        data: {},
      });
      await api.getFromAPI();
      expect(mocks.get).toHaveBeenCalled(); // should return true
    });

    In the test case, we mock a resolved value for our get method and call the function we want to test (api.getFromAPI() in this case). We then check whether our mocked get function has been called using expect().toHaveBeenCalled().

    This setup provides a controlled environment to test the interactions with the axios library in our code.