【问题标题】:Jest - How to test output of react methods is correct?开玩笑 - 如何测试反应方法的输出是否正确?
【发布时间】:2018-11-19 14:40:56
【问题描述】:

我在尝试了解如何使用 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>;
    }
}

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

谢谢, 亚历克斯

【问题讨论】:

    标签: reactjs jestjs babel-jest


    【解决方案1】:

    我遵循下一个方法:

    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() matcher 的作用下所做的事情),我们测试我们的元素作为 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();
      })
    
    });
    

    【讨论】:

    • 我正在尝试很多你说的东西,但仍然没有做对。网上的教程似乎都没有像我的反应类的例子。例如从 'react' 导入 React;从'./fetchdata'导入FetchData;从'react-test-renderer'导入渲染器; it('正确渲染', () => { const tree = renderer .create() .toJSON(); expect(tree).toMatchSnapshot(); });就是不行。
    • 您能否举个例子,使用我在原始问题中附加的课程? :)
    • 太棒了。非常感谢!
    • 注意:我还需要添加酶并将其设置为浅 :)
    猜你喜欢
    • 2017-01-25
    • 2019-07-16
    • 2020-03-02
    • 2021-03-12
    • 1970-01-01
    • 2018-02-22
    • 1970-01-01
    • 1970-01-01
    • 2018-02-25
    相关资源
    最近更新 更多