通过 ajax 调用在 componentDidMount 中正确设置测试状态

Testing state gets set correctly within componentDidMount from an ajax call

我的反应组件中有以下代码

componentDidMount() {

    ajax.call().then((data)=> {

        this.setState({a:data.a});
    });
}

我正在对一个 returns 承诺的函数进行简单调用。

当我尝试测试状态是否从已解决的承诺中正确设置时,我的测试看起来像这样。

        it('should set state of a', (done)=> {

            let ajax = {
                call: ()=>{}
            };

            spyOn(ajax, 'call').and.returnValue(Promise.resolve({a:'a'}));

            let component = TestUtils.renderIntoDocument(<MyComp/>);

            expect(component.state.a).toEqual('a');
        });

我很确定状态实际上是从 promise 返回的数据中设置的,但问题是我没有地方可以调用 jasmine 'done()' 函数来告诉 jasmine 异步操作已经完成并且可以测试状态上的断言。

React 社区大多同意通过以下方式更好地管理状态 “好像它是同步出现的,因此可以对其进行快照。这为我们提供了作为单个状态变量函数的视图,并使我们的代码易于测试。如果您不投资于架构 - 我建议您尝试 FLUX 之类的体系结构并检查通用库,如 redux 和 este。

就是说,像您一样在 AJAX 之后显式设置组件的状态是完全没问题的。我将测试分成两部分:

  • state 变量设置为 AJAX 的 return,您可以通过简单地检查对象是否已更改来测试它。
  • 调用 render 重新呈现您正在测试的组件(而不是 setStateing)。

然后,您可以测试呈现和以不同方式设置状态的承诺,使您的呈现测试易于推理(它们是同步的)并且 AJAX 测试容易(它只是对象)。

一般来说,当您使用 mocha 测试 promise 时,您可以使用专用的 promise 语法,因为您使用的是 React,所以无论如何您都在使用 Babel,因此您不妨在代码中使用新的 JavaScript 功能:

it('does ajax', async function(){ // can also `async () =>`
    var result = await ajax.call(); // call the ajax, get response, can be mocked
    var state = result;
    var str = React.renderToString(<MyComp prop={result} />);
    // assert against the returned HTML, can also test against DOM
});