jest-mock-axios icon indicating copy to clipboard operation
jest-mock-axios copied to clipboard

mockAxios.create() may return a new instance of mockAxios

Open spanitz opened this issue 3 years ago • 8 comments

Assuming the following use case:

// api.js
import axios from 'axios';

export function config() {
  v1.defaults.baseURL = `${API_BASEURL}/v1`;
  v2.defaults.baseURL = `${API_BASEURL}/v2`;
  // ...
}

export const v1 = axios.create();
export const v2 = axios.create();
export default v1;

Basic test scenario:

// api.test.js
import mockAxios from 'axios';
import * as Api form './api'

describe('Api', () => {
  test('proper configuration', () => {
    Api.config();

    // the following expectation fails because `mockAxios.create()` returns the singleton
    // whose `defaults.baseURL` was overwritten with `${API_BASEURL}/v2` already
    expect(Api.v1.defaults.baseURL).toEqual(`${API_BASEURL}/v1`);
    expect(Api.v2.defaults.baseURL).toEqual(`${API_BASEURL}/v2`);
  })
})

Because mockAxios works with a shared state, a workaround would be to override the create method and simply return a shalow copy of mockAxios (as in the following example) Since axios.create() actually appears to be a factory, the mock could also return a new instance. I think this would be ideal. What do you guys think?

//__mocks__/axios.js
import mockAxios from 'jest-mock-axios';
import { cloneDeep } from 'lodash';

mockAxios.create = jest.fn(() => cloneDeep(mockAxios));

export default mockAxios;

spanitz avatar Aug 31 '20 10:08 spanitz

Hi,

I agree that there is indeed room for improvement when using multiple axios instances. I'll see how it can be improved over the weekend.

kingjan1999 avatar Sep 01 '20 18:09 kingjan1999

Hi,

so I implemented the desired behavior in the 59-multiple-instances branch as a proof of concept.

This works, but it adds a significant new problem: If you create separate axios instances via axios.create() you can no longer mock them using the mockAxios default export, because it is two different instances with no shared promise queue. See LowercaseProxy.ts and the corresponding spec as an minimal example for this. Similar to your example above, the axios instances need to be exported by the code under test and imported by the test file.

This is somewhat unsatisfactory and I need to think a little bit more about this and how this can be changed to be more backward-compatible (any input welcome!)

kingjan1999 avatar Sep 06 '20 14:09 kingjan1999

I am getting this error ( I am assuming it is tied to this new update)

TypeError: axios.create is not a function

I have a singular instance being created in my file.

sd.instance = axios.create({
                baseURL: process.env.SDApiUrl,
                httpsAgent: new https.Agent({ keepAlive: true }),
                headers: { 'Content-Type': 'application/json' }
            })

rcg-dev avatar Nov 27 '20 10:11 rcg-dev

@rcg-dev I failed to reproduce this error (which isn't that surprising, as create() is used in the tests for this library as well). Can you do console.log to find out what axios.create is, if not a function?

kingjan1999 avatar Dec 02 '20 20:12 kingjan1999

I'm hitting the issue with different instances of axios - is that going to get released? Seems that the fix is in.

httpete avatar Mar 03 '21 23:03 httpete

@httpete The patch for this is still not merged but only in the branch linked above. As described above I was (and still am) hesitant to merge this in as it would break existing, more simple usages of this library. I'm still unsure how to solve this appropriately. Any input welcome.

kingjan1999 avatar Mar 04 '21 21:03 kingjan1999

my $0.02:

when using instances of axios, they should be passed in. in other words, a class that calls _axiosInstance.post() should take in the _axiosInstance as a dependency somehow, e.g. in its constructor.

i would expect the jest-mock-axios library to give me the ability to instantiate a mocked AxiosInstance instance that I can then pass into my constructor.

ryanrhee avatar Jan 25 '22 22:01 ryanrhee

so I implemented the desired behavior in the 59-multiple-instances branch as a proof of concept.

The link does not appear to work anymore.

In my case I use multiple axios instances each configured with it's own interceptor. This seems to wipe out the axios instance that I create.

In the end I just implemented by own https://stackoverflow.com/a/71961832/242042

trajano avatar Apr 21 '22 21:04 trajano