如何使用快照在useEffect中使用异步回调测试功能组件

时间:2019-09-03 21:10:54

标签: javascript reactjs unit-testing jestjs react-test-renderer

我试图在组件上编写单元测试,看起来像这样。

export const myComponent = ({text, list, getData = transport.getData}) => {
const [rows, setRows] = React.useState([]);

    React.useEffect(() => {
        const fetchData = async () => {
           const rows = await getData(list);
           setRows(rows);
        };
        fetchData();
    }, [list]);

    if (rows.length === 0) {
       return null;
    }

    return (
        // some JSX
    );
};

问题在于组件通过异步函数获取数据,因此在组件检查rows是否为空并返回空值之后将调用它。

if (rows.length === 0) {
   return null;
}

我嘲笑了getData,所以它应该返回一些值。但是,我仍然不明白如何在单元测试中涵盖该组件。我想这应该是快照,也许是不对的。

我的测试:

import React from 'react';
import {myComponent} from '../components/myComponent';
import renderer from 'react-test-renderer';

describe('myComponent', () => {
    test('should renders correctly', async () => {
        const mock = {
            text: 'text',
            list: [],
            getData: () =>
                Promise.resolve([
                    {
                        // ...
                    },
                ]),
        };
        const component = renderer.create(<myComponent text={mock.text} 
list={mock.list} getData={mock.getData}/>);
        let popup = component.toJSON();
        expect(popup).toMatchSnapshot();
    });
});

1 个答案:

答案 0 :(得分:0)

这是单元测试解决方案:

index.tsx

import React from 'react';

const transport = {
  async getData(list) {
    return [{ id: 1 }];
  }
};

export const MyComponent = ({ text, list, getData = transport.getData }) => {
  const [rows, setRows] = React.useState<any[]>([]);

  React.useEffect(() => {
    console.count('useEffect');
    const fetchData = async () => {
      console.count('fetchData');
      const newRows = await getData(list);
      setRows(newRows);
    };
    fetchData();
  }, [list]);

  if (rows.length === 0) {
    return null;
  }

  return <div>rows count: {rows.length}</div>;
};

index.spec.tsx

import React from 'react';
import { MyComponent } from './';
import renderer, { act } from 'react-test-renderer';

describe('myComponent', () => {
  test('should renders correctly', async () => {
    const mProps = {
      text: 'text',
      list: [],
      getData: jest.fn().mockResolvedValueOnce([{ id: 1 }, { id: 2 }, { id: 3 }])
    };
    let component;
    await act(async () => {
      component = renderer.create(<MyComponent {...mProps}></MyComponent>);
    });
    expect(component.toJSON()).toMatchSnapshot();
  });
});

单元测试结果:

PASS  src/stackoverflow/57778786/index.spec.tsx
  myComponent
    ✓ should renders correctly (29ms)

  console.count src/stackoverflow/57778786/index.tsx:13
    useEffect: 1

  console.count src/stackoverflow/57778786/index.tsx:15
    fetchData: 1

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   1 passed, 1 total
Time:        3.557s, estimated 8s

index.spec.tsx.snap

// Jest Snapshot v1

exports[`myComponent should renders correctly 1`] = `
<div>
  rows count: 
  3
</div>
`;

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