I have the following (simplified) React component.
class SalesView extends Component<{}, State> {
state: State = {
salesData: null
};
componentDidMount() {
this.fetchSalesData();
}
render() {
if (this.state.salesData) {
return <SalesChart salesData={this.state.salesData} />;
} else {
return <p>Loading</p>;
}
}
async fetchSalesData() {
let data = await new SalesService().fetchSalesData();
this.setState({ salesData: data });
}
}
When mounting, I fetch data from an API, which I have abstracted away in a class called SalesService
. This class I want to mock, and for the method fetchSalesData
I want to specify the return data (in a promise).
This is more or less how I want my test case to look like:
- predefine test data
- import SalesView
- mock SalesService
setup mockSalesService to return a promise that returns the predefined test data when resolved
create the component
- await
- check snapshot
Testing the looks of SalesChart is not part of this question, I hope to solve that using Enzyme. I have been trying dozens of things to mock this asynchronous call, but I cannot seem to get this mocked properly. I have found the following examples of Jest mocking online, but they do not seem to cover this basic usage.
- Hackernoon: Does not use asychronous calls
- Wehkamp tech blog: Does not use asynchronous calls
- Agatha Krzywda: Does not use asynchronous calls
- GitConnected: Does not use a class with a function to mock
- Jest tutorial An Async Example: Does not use a class with a function to mock
- Jest tutorial Testing Asynchronous Code: Does not use a class with a function to mock
- SO question 43749845: I can't connect the mock to the real implementation in this way
- 42638889: Is using dependency injection, I am not
- 46718663: Is not showing how the actual mock Class is implemented
My questions are:
- How should the mock class look like?
- Where should I place this mock class?
- How should I import this mock class?
- How do I tell that this mock class replaces the real class?
- How do set up the mock implementation of a specific function of the mock class?
- How do I wait in the test case for the promise to be resolved?
One example that I have that does not work is given below. The test runner crashes with the error throw err;
and the last line in the stack trace is at process._tickCallback (internal/process/next_tick.js:188:7)
# __tests__/SalesView-test.js
import React from 'react';
import SalesView from '../SalesView';
jest.mock('../SalesService');
const salesServiceMock = require('../SalesService').default;
const weekTestData = [];
test('SalesView shows chart after SalesService returns data', async () => {
salesServiceMock.fetchSalesData.mockImplementation(() => {
console.log('Mock is called');
return new Promise((resolve) => {
process.nextTick(() => resolve(weekTestData));
});
});
const wrapper = await shallow(<SalesView/>);
expect(wrapper).toMatchSnapshot();
});