Here is the unit test solution:
app.jsx
:
import React, { useState, useEffect } from 'react';
import { fetchData } from './api';
function App({ id }) {
const [data, setData] = useState(null);
const [isFetching, setIsFetching] = useState(false);
const [error, setError] = useState(null);
useEffect(() => {
setIsFetching(true);
fetchData(id)
.then(
(response) => {
setData(response.data);
setIsFetching(false);
},
(err) => {
setError(err);
setIsFetching(false);
},
)
.catch((err) => {
setError(err);
setIsFetching(false);
});
}, [id]);
if (data) {
return <pre>{JSON.stringify(data)}</pre>;
}
if (isFetching) {
return <div>fetching...</div>;
}
if (error) {
return <pre>{JSON.stringify(error)}</pre>;
}
return <div>null</div>;
}
export default App;
api.js
:
export function fetchData() {
// real implementation
}
app.test.jsx
:
import App from './app';
import { mount } from 'enzyme';
import { fetchData } from './api';
import { act } from 'react-dom/test-utils';
jest.mock('./api.js', () => {
return {
fetchData: jest.fn(),
};
});
describe('59586141', () => {
afterEach(() => {
jest.clearAllMocks();
});
it('should fetch data correctly', async () => {
const mResponse = { data: { id: 1 } };
const mProps = { id: 1 };
fetchData.mockResolvedValueOnce(mResponse);
const wrapper = mount(<App {...mProps}></App>);
expect(wrapper.exists).toBeTruthy();
expect(wrapper.find('div').text()).toBe('fetching...');
await act(async () => {
await new Promise((resolve) => setTimeout(resolve, 0));
});
wrapper.update();
expect(wrapper.find('pre').text()).toBe(JSON.stringify(mResponse.data));
expect(fetchData).toBeCalledWith(1);
});
it('should handle error if fetch data failure', async () => {
const mError = new Error('some network error');
const mProps = { id: 1 };
fetchData.mockRejectedValueOnce(mError);
const wrapper = mount(<App {...mProps}></App>);
expect(wrapper.exists).toBeTruthy();
expect(wrapper.find('div').text()).toBe('fetching...');
await act(async () => {
await new Promise((resolve) => setTimeout(resolve, 0));
});
wrapper.update();
expect(wrapper.find('pre').text()).toBe(JSON.stringify(mError));
expect(fetchData).toBeCalledWith(1);
});
});
Unit test result with coverage report:
PASS src/stackoverflow/59586141/api.test.jsx (9.079s)
59586141
✓ should fetch data correctly (119ms)
✓ should handle error if fetch data failure (12ms)
----------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
----------|----------|----------|----------|----------|-------------------|
All files | 93.1 | 100 | 80 | 91.3 | |
app.jsx | 93.1 | 100 | 80 | 91.3 | 22,23 |
----------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 10.458s
Source code: https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/59586141