Open AnandShiva opened 4 years ago
This looks like a duplicate of #44. Currently, I am not aware of any workaround for this, except for splitting up the two await calls in two different functions. But I will look at this again soon
@kingjan1999 Any reason why mockResponse should be set after the axios call has been made? If it is possible to change this architecture I can fork a branch and have this mocking response after the call to be a configuration parameter.
This is currently due to how this library works: It takes any requests made, puts them into a queue and then pops the first one (or the specified one) when mockResponse is called. Feel free to make a pull request to make this more flexible
@AnandShiva did you find a workaround?
Why can't this work like a regular jest mock where you're able to for example do
test('foo', async () => {
const mock = jest.fn()
mock
.mockResolvedValueOnce({ foo: 'bar' })
.mockResolvedValueOnce({ foo: 'bar' })
.mockRejectedValueOnce(new Error('oh no'))
await expect(mock()).resolves.toEqual({ foo: 'bar' })
await expect(mock()).resolves.toEqual({ foo: 'bar' })
await expect(mock()).rejects.toThrowError(new Error('oh no'))
})
Jest fully supports async tests and seen as this package is specifically written for jest I don't see a reason to work outside of its framework.
Why can't this work like a regular jest mock where you're able to for example do
test('foo', async () => { const mock = jest.fn() mock .mockResolvedValueOnce({ foo: 'bar' }) .mockResolvedValueOnce({ foo: 'bar' }) .mockRejectedValueOnce(new Error('oh no')) await expect(mock()).resolves.toEqual({ foo: 'bar' }) await expect(mock()).resolves.toEqual({ foo: 'bar' }) await expect(mock()).rejects.toThrowError(new Error('oh no')) })
Jest fully supports async tests and seen as this package is specifically written for jest I don't see a reason to work outside of its framework.
this' been a pain for me too
I get the same "No request to respond to!" after 10 successful responses using await. My first 10 test cases (with one await call in each) pass well and then this fails. Tried to change the code but always seems to be a 10 limit somehow. Not clear what seems to cause this as I could not see something like a limit in the queue size. Any ideas? Nevermind me :facepalm:
In case it helps anyone else running into this and/or #44: Try axios-mock-adapter
I worked around this by doing something like:
it('can pass through all filter params to the API', async (): Promise<void> => {
mockAxios.get.mockImplementationOnce(() => {
return Promise.resolve(resultArray);
});
const result = await getResource(
{}, // query string params
);
const requestConfig = mockAxios.get.mock.calls[0][1]; // First call, second arg
const requestUrl = mockAxios.get.mock.calls[0][0]; // First call, second arg
expect(requestUrl).toEqual('/example/resource/endpoint');
expect(requestConfig.params).toEqual({});
expect(result).toEqual(resultArray);
});
Excuse the pulling out of the mock call args, I had to only test a subset of them but you get the general idea.
Came here with the same struggle.
My solution was to mock both axios and got using jest's out-of-the-box mocking framework. To clarify, you don't have to use both http packages, I'm just showing that the same mocking concept can be applied to either you're using.
For this example, I'm using the following versions:
"axios": "^0.21.1"
"got": "^11.8.3"
"jest": "^28.1.3"
"ts-jest": "^28.0.7"
"typescript": "^4.9.5"
import axios, { AxiosStatic } from 'axios';
import got, { Got } from 'got';
jest.mock('axios');
jest.mock('got');
describe('mock-test', () => {
let mockedAxios: jest.MaybeMocked<AxiosStatic>;
let mockedGot: jest.MaybeMocked<Got>;
beforeEach(() => {
mockedAxios = jest.mocked(axios);
mockedGot = jest.mocked(got);
});
afterEach(() => {
jest.resetAllMocks();
});
test('mocked post', async () => {
const mockResponse = {
ok: true,
result: {
id: 42,
name: 'Doug'
},
};
mockedAxios.post = jest.fn().mockReturnValue(mockResponse);
const response = await client.createUser({ name: 'Doug' });
expect(mockedAxios.post).toHaveBeenCalledWith(
expect.stringContaining('/user'),
{
name: 'Doug'
}
);
expect(response).toBe(mockResponse.result);
});
test('mocked error', async () => {
mockedGot.get = jest.fn().mockRejectedValue(new Error('failure'));
await expect(async () => {
await client.getUserById(42);
}).rejects.toThrow('failure');
expect(mockedGot.get).toHaveBeenCalledWith(
expect.stringContaining('/user/42'),
);
});
});
Thanks for your package. Love it ! But I seem to have an issue with it when using it along with async-await functions. Test Code looks like
test("authenticate", async () => { let promiseObj = authenticate(email, password).then((msg) => {}).catch(catchFn) // simulating a server response let responseObj = { data: ["centralpet"] }; mockAxios.mockResponse(responseObj); expect(catchFn).not.toHaveBeenCalled(); return promiseObj; })
Now my source code - authenticate implementation looks like
authenticate = async (email, password) => { //This called a chrome async method. Not axios. let client = await utils.updateClientDetailsFromEmail(email); // This calls the axios methods. let status = await httpService.makeNetworkCall(requestObject); return status; }
Since inside the authenticate I am using await, the function gets paused before calling axios. Meanwhile, the calling function continues execution and goes to mockResponse. There mockAxios finds that no axios functions are in Queue so it throws No request to respond to! error. If I await the authenticate call the mockResponse never gets executed so axios times out.
Can you check this issue or is there any workaround or config I am missing to avoid queuing of axios calls?