Jest - 如何测试反应方法的输出是否正确?

Jest - How to test output of react methods is correct?

我在尝试了解如何使用 Jest 测试反应文件中方法的输出时遇到问题。我对这种 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>;
    }
}

我基本上希望能够测试 table 返回的列数是否正确,但是我不知道如何使用 Jest 执行此操作。

谢谢, 亚历克斯

我遵循下一个方法:

  1. Mocking dependencies 被测试组件显式调用。
  2. 正在使用 shallow()
  3. 初始化组件
  4. 尝试不同的修改
  5. 检查组件 .toMatchSnapshot()

在 "trying different modifications" 下,我的意思是要么创建具有不同初始 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();
});

这样你就不需要单独测试方法了。为什么我认为这是有道理的?

虽然所有的方法测试都通过了,但我们仍然不能说它是否作为一个整体起作用(假阳性反应)。 此外,如果我们进行任何重构,如重命名方法,我们的 tests-per-method 将失败。同时,组件可能仍然可以正常工作,我们会花更多的时间来修复测试,只是为了让它们通过(假阴性反应)。

从相反的角度关注 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();
  })

});