Friday, May 17, 2024
 Popular · Latest · Hot · Upcoming
132
rated 0 times [  136] [ 4]  / answers: 1 / hits: 17699  / 5 Years ago, thu, august 29, 2019, 12:00:00

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?


More From » reactjs

 Answers
10

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.


[#51717] Thursday, August 22, 2019, 5 Years  [reply] [flag answer]
Only authorized users can answer the question. Please sign in first, or register a free account.
kieraelsies

Total Points: 718
Total Questions: 103
Total Answers: 104

Location: England
Member since Sun, May 21, 2023
1 Year ago
kieraelsies questions
Tue, Aug 3, 21, 00:00, 3 Years ago
Tue, Feb 23, 21, 00:00, 3 Years ago
Thu, Nov 12, 20, 00:00, 4 Years ago
Wed, Sep 9, 20, 00:00, 4 Years ago
Mon, Sep 16, 19, 00:00, 5 Years ago
;