how can i do a unit testing of axios.create mock with vitest?

3.5k views Asked by At

i am learning unit testing in vue with typescript and i want to test this function

const getCLients =async (): Promise<Client[]> => {
        const {data} = await clientsApi.get('/clients')
        return data
}

But i got an error due to the clientsApi. My clients api is aun axios instance and looks like this:

import axios from 'axios'

const clientsApi = axios.create({
   baseURL:import.meta.env.VITE_API_URL
})
export default clientsApi

my error is this:

TypeError: Cannot read properties of undefined (reading 'get') ❯ getCLients ../src/clients/composables/useClients.ts:14:41

14| const {data} = await clientsApi.get('/clients')

In my tests i have done the axios mock:

vi.mock('axios')
const mockedAxios = axios as jest.Mocked<typeof axios>;

mockedAxios.get.mockResolvedValue({
            data: mockClients,
})

I suposed that i had to make a mock of the axios.create but i have tried with a lot of ways but i always got the same typoe error. I need your help, how could you solve this?

2

There are 2 answers

2
BraedenK On

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(),
  // and any other request type you want to mock
}));

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 clientsApi.getCLients();
  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 (clientsApi.getCLients() 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.

0
user21308033 On

Not sure if I'm on the right track as it just works on my end. I do vi.mock('axios') and have Error: spyOn could not find an object to spy uponenter code here. So I do vi.mock(the path to the instance ), and do vi.spyOn(the axios instance, 'get').mockResolvedValue and in your case, could be clientsApi.