Here is the unit test solution:
index.tsx:
import React, { useReducer, useEffect } from 'react';
import { listReducer, fetchList } from './reducer';
export const Posts = () => {
const [list, dispatch] = useReducer(listReducer, []);
useEffect(() => {
fetchList(dispatch);
}, []);
return (
<ul>
{list.map((el) => (
<li key={el.id}>{el.title}</li>
))}
</ul>
);
};
reducer.ts:
import axios from 'axios';
const LIST_SUCCES = 'LIST_SUCCES';
const LIST_FAILURE = 'LIST_FAILURE';
export const fetchList = async (dispatch) => {
try {
const result = await axios.get('/list/'); /* AXIOS */
dispatch({ type: LIST_SUCCES, payload: result.data.list });
} catch (error) {
dispatch({ type: LIST_FAILURE });
}
};
export const listReducer = (state, action) => {
switch (action.type) {
case LIST_SUCCES:
return action.payload;
case LIST_FAILURE:
return [];
default:
throw new Error();
}
};
index.spec.tsx:
import React from 'react';
import { Posts } from './';
import { mount } from 'enzyme';
import axios from 'axios';
import { act } from 'react-dom/test-utils';
describe('Posts', () => {
afterAll(() => {
jest.restoreAllMocks();
});
it('should render list correctly', async () => {
const mResponse = { data: { list: [{ id: 1, title: 'jest' }] } };
jest.spyOn(axios, 'get').mockResolvedValueOnce(mResponse);
const wrapper = mount(<Posts></Posts>);
expect(wrapper.find('ul').children()).toHaveLength(0);
await act(async () => {
await new Promise((resolve) => setTimeout(resolve, 0));
});
wrapper.update();
expect(wrapper.find('ul').children()).toHaveLength(1);
expect(wrapper).toMatchInlineSnapshot(`
<Component>
<ul>
<li
key="1"
>
jest
</li>
</ul>
</Component>
`);
});
it('should render empty list when request list data failed', async () => {
const mError = new Error('Internal server error');
jest.spyOn(axios, 'get').mockRejectedValueOnce(mError);
const wrapper = mount(<Posts></Posts>);
expect(wrapper.find('ul').children()).toHaveLength(0);
await act(async () => {
await new Promise((resolve) => setTimeout(resolve, 0));
});
wrapper.update();
expect(wrapper.find('ul').children()).toHaveLength(0);
expect(wrapper).toMatchInlineSnapshot(`
<Component>
<ul />
</Component>
`);
});
});
Unit test result with coverage report:
PASS src/stackoverflow/59197574/index.spec.tsx (12.494s)
Posts
✓ should render list correctly (105ms)
✓ should render empty list when request list data failed (37ms)
› 1 snapshot written.
------------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
------------|----------|----------|----------|----------|-------------------|
All files | 95.83 | 66.67 | 100 | 95 | |
index.tsx | 100 | 100 | 100 | 100 | |
reducer.ts | 92.86 | 66.67 | 100 | 91.67 | 21 |
------------|----------|----------|----------|----------|-------------------|
Snapshot Summary
› 1 snapshot written from 1 test suite.
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 1 written, 1 passed, 2 total
Time: 14.409s
Source code: https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/59197574