如何在useEffect中测试异步功能的基本示例

时间:2019-12-05 14:43:18

标签: reactjs jestjs enzyme

我有一个简单的组件,它可以获取帖子的异步列表。

HGLOBAL hGlob = GlobalAlloc(GMEM_FIXED, 64); // Maybe also need GMEM_MOVEABLE here instead?
char* cCopy = (char*)GlobalLock(hGlob);
strcpy_s(cGlob, 64, "Current selection\r\n");
GlobalUnlock(hGlob); 
if (::SetClipboardData(CF_TEXT, hGlob) == NULL)
{
    //...

在其他文件中,我保留逻辑:

export const Posts = () => {
  const [list, dispatch] = useReducer(listReducer, []);

  useEffect(() => {
    fetchList(dispatch);
  }, []);

  return (
    <ul>
      {list.map((el) => (
        <li key={el.id}>{el.title}</li>
      ))}
    </ul>
  );
};

我尝试了多个库,但是我无法编写测试。我该如何写export const fetchList = async (dispatch) => { try { const result = await api.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() } } 来检查帖子是否被获取和显示,我是在第一次安装组件之后(因此不是Posts.test.js)并且在数据被加载后触发异步fetchList从该异步函数中提取了我的调度动作并更新了列表。

1 个答案:

答案 0 :(得分:1)

这是单元测试解决方案:

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>
    `);
  });
});

带有覆盖率报告的单元测试结果:

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

源代码:https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/59197574