【问题标题】:Testing Loading state in async operation in Jest在 Jest 中测试异步操作中的加载状态
【发布时间】:2019-01-18 19:16:52
【问题描述】:

我有以下 React 组件,它在 componentDidMount() 上执行异步操作,一旦接收到数据,就会使用结果更新状态。

import * as React from "react";

export interface IAppProp {
    App: any
}

export interface IAppProp {
    App: any
}

export class App extends React.Component<IAppProp, IAppState> {
    constructor(props: IAppProp) {
        super(props);
        this.state = { App: undefined };
    }
    public componentDidMount(){
        // Some async operation
        // Once data comes in update state as follows 
        this.setState({ App: data returned from async operation });
    }
    public render() {
        if (this.state && this.state.App) {
            return (
                <SomeComponent />
            )
        } else {
            return <span>Loading...</span>
        }
    }
}

但是,当我等待数据返回时,我在 render() 函数中返回了 Loading... 消息。

我正在尝试在我的 Jest 测试中测试此 Loading 状态。这是我目前所拥有的:

 it("Should display loading when state is undefined", () => {
    const inputControl = enzyme.mount(<MyApp App={pass in the right prop} />);

    expect(inputControl.find("span").text()).toEqual("Loading...");
});

我知道上面的内容是错误的,因为它永远找不到加载中的span。我还尝试在 props 中传递 undefined,但这会使测试崩溃,因为 componentDidMount() 中的异步操作需要一个合法的 prop。

我该如何测试呢?谢谢!

【问题讨论】:

  • 您应该能够通过mocking 测试中的异步操作或/和将async 添加到您的测试中来测试它。能否提供componentDidMount的完整代码?

标签: reactjs jestjs enzyme


【解决方案1】:

对不起(只是一点点)

我发现很难一次性测试一切,从业务逻辑到渲染全部。

所以我将测试拆分为:

  • 测试来自用户交互和/或异步操作的副作用,即 prop/state 更改
  • 测试我期望收到的确切 prop/state 组合的快照。

【讨论】:

    【解决方案2】:

    这是一个基于您的代码的工作示例(已修改,因为我没有 SomeComponent,未指定异步函数等)。

    鉴于App.tsx中定义的这个组件:

    import * as React from "react";
    
    const getMessageById = (id: number): Promise<string> => {
      return Promise.resolve('Message ' + id);
    }
    
    interface IAppProp {
        messageid: number
    }
    
    interface IAppState {
        message: string
    };
    
    export class App extends React.Component<IAppProp, IAppState> {
        constructor(props: IAppProp) {
            super(props);
            this.state = { message: '' };
        }
        public componentDidMount(){
            // Some async operation
            // Once data comes in update state as follows 
            getMessageById(this.props.messageid).then((message) => {
              this.setState({ message });
            });
        }
        public render() {
            if (this.state && this.state.message && this.state.message.length > 0) {
                return (
                    <div>The message: {this.state.message}</div>
                )
            } else {
                return <span>Loading...</span>
            }
        }
    }
    

    可以按如下方式创建测试App.test.tsx

    import { mount } from 'enzyme';
    import * as React from 'react';
    
    import { App } from './App';
    
    describe('App', () => {
    
      it ('Should display loading until data arrives', async () => {
        const inputControl = mount(<App messageid={1} />);
        expect(inputControl.html()).toBe('<span>Loading...</span>');
        // Let the event loop cycle so the callback queued by 'then' 
        // in 'componentDidMount()' has a chance to execute
        await Promise.resolve();
        expect(inputControl.html()).toBe('<div>The message: Message 1</div>');
      });
    
    });
    

    对于您的实际组件,您可能需要模拟获取数据的异步函数(这样您就可以避免发出网络请求等),但这应该为您尝试做的事情提供一个坚实的开端,并且是尽我所能提供的信息。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-06-25
      • 2019-10-21
      • 1970-01-01
      • 2023-01-14
      • 2019-04-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多