使用酶异步安装后测试反应子组件

时间:2020-01-22 05:32:50

标签: reactjs unit-testing jestjs enzyme

我要测试的是在点击Item组件的元素之后,检查addToSelectList是否被调用

以下是简化代码。

ItemList组件

import React, {useState, useEffect} from 'react';
import {fetchItems} from '../api';
import {addToSelectList} from '../listModule';
import Item from './Item';

function ItemList() {
  const [page, setPage] = useState(1);

  const [items, setItems] = useState([]);
  useEffect(() => {
    fetchItems().then(res => {
      setItems(res.data.items);
    });
  }, [page]);

  function onClickItem(item) {
    addToSelectList(item);
  }


  return (
    <ul>
      {items.map((item, index) => (
        <li>
          <Item key={index} name={item.name} onClick={() => {
            onClickItem(item);
          }} />
        </li>
      ))}
    </ul>
  );
}

项目组件

import React from 'react';

function Item(props) {
  return (
    <div>
      <div onClick={() => {
        props.onClick();
      }}>{props.name}</div>
    </div>
  );
}

itemList.test.js

import React from 'react';
import {mount} from 'enzyme';
import {addToSelectList} from '../listModule';
import ItemList from '../view/ItemList';
import Item from '../view/Item';

describe('<ItemList />, () => {
  test('onClickItem', () => {
    let wrapper = mount(<ItemList />);

    // fail
    // Expected: >0
    // Received:  0
    expect(wrapper.find(Item).length).toBeGreaterThan(0);
  });

});

但是有两个问题。

  1. 当我mount ItemList组件并执行wrapper.find(Item)时,没有Item组件,因为Item组件在{{ 1}}状态已更新。 如何检查那些items组件是否正确呈现

  2. 在我检查了Item组件的呈现后,如何触发Item组件的onClick事件并检查Item方法是叫

1 个答案:

答案 0 :(得分:1)

这是单元测试解决方案:

itemList.tsx

import React, { useState, useEffect } from 'react';
import { fetchItems } from './api';
import { addToSelectList } from './listModule';
import Item from './item';

export default function ItemList() {
  const [page, setPage] = useState(1);
  const [items, setItems] = useState([]);

  useEffect(() => {
    fetchItems().then((res) => {
      setItems(res.data.items);
    });
  }, [page]);

  function onClickItem(item) {
    addToSelectList(item);
  }

  return (
    <ul>
      {items.map((item: any, index) => (
        <li key={index}>
          <Item
            name={item.name}
            onClick={() => {
              onClickItem(item);
            }}
          />
        </li>
      ))}
    </ul>
  );
}

api.ts

export const fetchItems = async () => {
  return { data: { items: [] } } as any;
};

item.tsx

import React from 'react';

export default function Item(props) {
  return (
    <div>
      <div
        onClick={() => {
          props.onClick();
        }}
      >
        {props.name}
      </div>
    </div>
  );
}

listModule.ts

export const addToSelectList = (item) => {
  console.log(item);
};

itemList.test.tsx

import React from 'react';
import ItemList from './itemList';
import { mount } from 'enzyme';
import { fetchItems } from './api';
import { act } from 'react-dom/test-utils';
import Item from './item';
import { addToSelectList } from './listModule';

jest.mock('./api', () => {
  return { fetchItems: jest.fn() };
});

jest.mock('./listModule', () => {
  return { addToSelectList: jest.fn() };
});

describe('59853199', () => {
  it('should pass', async () => {
    const mFetchItemsResponse = { data: { items: [{ name: 'a' }, { name: 'b' }] } };
    (fetchItems as jest.MockedFunction<typeof fetchItems>).mockResolvedValueOnce(mFetchItemsResponse);
    const wrapper = mount(<ItemList />);
    expect(wrapper.find(Item).length).toBe(0);
    // when useEffect stable
    await act(async () => {
      await new Promise((resolve) => setTimeout(resolve));
    });
    wrapper.update();
    expect(wrapper.find(Item).length).toBeGreaterThan(0);
    wrapper
      .find(Item)
      .at(0)
      .prop('onClick')();
    expect(addToSelectList).toBeCalledWith(mFetchItemsResponse.data.items[0]);
  });
});

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

 PASS  src/stackoverflow/59853199/itemList.test.tsx
  59853199
    ✓ should pass (98ms)

--------------|----------|----------|----------|----------|-------------------|
File          |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
--------------|----------|----------|----------|----------|-------------------|
All files     |    94.44 |      100 |     87.5 |    94.44 |                   |
 item.tsx     |       75 |      100 |       50 |       75 |                 8 |
 itemList.tsx |      100 |      100 |      100 |      100 |                   |
--------------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        4.18s, estimated 10s

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