开玩笑-如何测试react方法的输出是否正确?

时间:2018-11-19 14:40:56

标签: reactjs jestjs babel-jest

我在尝试了解如何使用Jest来测试react文件中方法的输出时遇到问题。我对这种类型的Web开发完全陌生,因此不胜感激。

我有一个这样的js文件:

import * as React from 'react';
import 'es6-promise';
import 'isomorphic-fetch';

export default class FetchData extends React.Component {
    constructor() {
        super();
        this.state = { documents: [], loading: true };
        fetch('api/SampleData/GetDocuments')
            .then(response => response.json())
            .then(data => {
                this.setState({ documents: data, loading: false });
            });
    }

    render() {
        let contents = this.state.loading ? <p><em>Loading...</em></p>
            : FetchData.renderdocumentsTable(this.state.documents);

        return <div>
            <button onClick={() => { this.refreshData() }}>Refresh</button>
            <p>This component demonstrates bad document data from the server.</p>
            {contents}
        </div>;
    }

    refreshData() {
        fetch('api/SampleData/GetDocuments')
            .then(response => response.json())
            .then(data => {
                this.setState({ documents: data, loading: false });
            });
    }

    static renderdocumentsTable(documents) {
        return <table className='table'>
            <thead>
                <tr>
                    <th>Filename</th>
                    <th>CurrentSite</th>
                    <th>CorrectSite</th>
                </tr>
            </thead>
            <tbody>
                {documents.map(document =>
                    <tr className="document-row" key={document.documentId}>
                        <td>{document.filename}</td>
                        <td>{document.currentSite}</td>
                        <td>{document.correctSite}</td>
                    </tr>
                )}
            </tbody>
        </table>;
    }
}

我基本上希望能够测试返回的表具有正确的列数,但是我无法确切地知道如何用Jest做到这一点。

谢谢, 亚历克斯

1 个答案:

答案 0 :(得分:2)

我遵循以下方法:

  1. Mocking dependencies由被测组件明确调用。
  2. 使用shallow()初始化组件
  3. 尝试不同的修改
  4. 使用.toMatchSnapshot()检查组件

在“尝试不同的修改”下,我的意思是或者使用不同的初始props创建组件,或者与组件的内部元素的props进行交互。

test('closes list on button clicked', () => {
    let wrapper = shallow(<MyComponent prop1={'a'} prop2={'b'} />);
    wrapper.find('button').at(0).simulate('click');
    expect(wrapper).toMatchSnapshot();
});

通过这种方式,您无需分别测试方法。为什么我认为这有道理?

虽然所有方法测试都通过了,但我们仍然不能说它是否可以整体运行(假阳性反应)。 同样,如果我们进行任何重命名之类的重构,我们的测试方法也会失败。同时,组件可能仍然可以正常工作,我们花费更多的时间来修复测试,以使它们通过(假阴性反应)。

相反,我们专注于render()的结果(这是酶适配器在.toMatchSnapshot()匹配器的作用下所做的事情),我们测试了元素在React项目中的作用。

[UPD]基于您的代码的示例:

describe("<FetchData />", () => {
  let wrapper;
  global.fetch = jest.fn();

  beforeEach(() => {
    fetch.mockClear();
  });

  function makeFetchReturning(documents) {
    fetch.mockImplementation(() => Promise.resolve({ json: () => documents }));
  }

  function initComponent() {
    // if we run this in beforeEach we would not able to mock different return value for fetch() mock
    wrapper = shallow(<FetchData />); 
  }

  test("calls appropriate API endpoint", () => {
    makeFetchReturning([]);
    initComponent();
    expect(fetch).toHaveBeenCalledWith("api/SampleData/GetDocuments");
  });

  test("displays loading placeholder until data is fetched", () => {
    // promise that is never resolved
    fetch.mockImplementation(() => new Promise(() => {})); 
    initComponent();
    expect(wrapper).toMatchSnapshot();
  });

  test("looks well when empty data returned", () => {
    makeFetchReturning([]);
    initComponent();
    expect(wrapper).toMatchSnapshot();
  });

  test("reloads documents and displays them", () => {
    makeFetchReturning([]);
    initComponent();
    // no matter what values we include in mock but it should be something non-empty
    makeFetchReturning([{fileName: '_', currentSite: '1', correctSite: '2'}]);
    wrapper.find('button').at(0).simulate('click');
    expect(fetch).toHaveBeenCalledTimes(2);
    expect(wrapper).toMatchSnapshot();
  })

});