首页 文章

在Jest中测试异步操作中的加载状态

提问于
浏览
1

我有以下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测试中测试这个加载状态 . 这是我到目前为止:

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...");
});

我知道上面的错误是因为它从未找到Loading span . 我也尝试在道具中传递 undefined ,但是因为 componentDidMount() 中的异步操作需要一个合法的道具而导致测试崩溃 .

我该怎么测试呢?谢谢!

1 回答

  • 2

    这是一个基于您的代码的工作示例(由于我没有 SomeComponent ,未指定async函数等进行了修改) .

    鉴于 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>');
      });
    
    });
    

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

相关问题