So I am attempting to test the positive and negative sides of my implementation. If I do this:
jest.mock('./apiClient', () => ({
get: jest.fn((url: string) => Promise.resolve({ data: mockData }))
}));
jest.mock('./apiClient', () => ({
get: jest.fn().mockImplementation((url: string) => {
console.log('error result');
return Promise.reject(mockError);
})
}));
Then the only test passing will be the last one declared. In the above case, it will be the reject
case which will pass and the first mock will be ignored.
This is my whole test:
// @ts-ignore
import ApiClient from './apiClient';
import ApiService from './apiService';
const mockData = {};
const mockError = { message: 'Smth Bad Happened' };
const firstCallback = jest.fn((data: any) => data);
const secondCallback = jest.fn((data: any) => data);
jest.mock('./apiClient', () => ({
get: jest.fn((url: string) => Promise.resolve({ data: mockData }))
}));
jest.mock('./apiClient', () => ({
get: jest.fn().mockImplementation((url: string) => {
console.log('error result');
return Promise.reject(mockError);
})
}));
describe('apiService', () => {
it('should call callbacks consequently', done => {
ApiService.makeApiCall('testUrl', firstCallback, secondCallback).then(() => {
expect(firstCallback).toBeCalledTimes(1);
expect(firstCallback).toBeCalledWith(mockData);
expect(secondCallback).toBeCalledTimes(1);
expect(secondCallback).toBeCalledWith(firstCallback(mockData));
done();
});
});
it('should handle error', done => {
console.error = jest.fn();
ApiService.makeApiCall('testUrl', firstCallback, secondCallback).then(() => {
expect(firstCallback).toBeCalledTimes(0);
expect(secondCallback).toBeCalledTimes(0);
expect(console.error).toBeCalledTimes(1);
expect(console.error).toBeCalledWith('ApiClient testUrl', mockError);
done();
});
});
});
As it is right now, the test passing is should handle error
which is the second one, but if I have switch the positions from
jest.mock('./apiClient', () => ({
get: jest.fn((url: string) => Promise.resolve({ data: mockData }))
}));
jest.mock('./apiClient', () => ({
get: jest.fn().mockImplementation((url: string) => {
console.log('error result');
return Promise.reject(mockError);
})
}));
To
jest.mock('./apiClient', () => ({
get: jest.fn().mockImplementation((url: string) => {
console.log('error result');
return Promise.reject(mockError);
})
}));
jest.mock('./apiClient', () => ({
get: jest.fn((url: string) => Promise.resolve({ data: mockData }))
}));
then the test passing will be should call callbacks consequently
, so what can I do to mock both reject and resolve without interfering one with the other?
I've reached this question while I was looking for a good practice to do that, because I had the same problem but I found a workaround to make it work. And although I suppose you already solved this issue, I'll leave here my temporary solution for future readers.
Basically I overridden the mock implementation of the method right in the test where I want to reject the promise.
So I would get rid of the reject implementation before the describe
declaration and add it in the 'should handle error'
test by this way:
ApiClient.get: jest.fn().mockImplementation((url: string) => {
console.log('error result');
return Promise.reject(mockError);
})
Your final test would look like this:
// @ts-ignore
import ApiClient from './apiClient';
import ApiService from './apiService';
const mockData = {};
const mockError = { message: 'Smth Bad Happened' };
const firstCallback = jest.fn((data: any) => data);
const secondCallback = jest.fn((data: any) => data);
jest.mock('./apiClient', () => ({
get: jest.fn((url: string) => Promise.resolve({ data: mockData }))
}));
describe('apiService', () => {
it('should call callbacks consequently', done => {
ApiService.makeApiCall('testUrl', firstCallback, secondCallback).then(() => {
expect(firstCallback).toBeCalledTimes(1);
expect(firstCallback).toBeCalledWith(mockData);
expect(secondCallback).toBeCalledTimes(1);
expect(secondCallback).toBeCalledWith(firstCallback(mockData));
done();
});
});
it('should handle error', done => {
ApiClient.get: jest.fn().mockImplementation((url: string) => {
console.log('error result');
return Promise.reject(mockError);
});
console.error = jest.fn();
ApiService.makeApiCall('testUrl', firstCallback, secondCallback).then(() => {
expect(firstCallback).toBeCalledTimes(0);
expect(secondCallback).toBeCalledTimes(0);
expect(console.error).toBeCalledTimes(1);
expect(console.error).toBeCalledWith('ApiClient testUrl', mockError);
done();
});
});
});
I think this is not the best way to do it, but it is not bad at all, and it should work for this example.
I'll keep looking for a smarter solution.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With