在componentDidMount中获取数据后,如何测试React组件?

时间:2018-08-25 00:26:22

标签: reactjs jestjs enzyme

我有一个有条件的渲染组件(有条件渲染)(如果获取数据则渲染,否则返回null),我想用jest & enzyme进行测试。我遇到的问题是我想测试该类中的一种方法,但是.instance()始终返回null,因此不允许我测试该实例。

我的代码看起来像这样

export default class MyComponent extends React.Component<Props, State> {
    componentDidMount() {
        this.props.fetchData.then(() => 
            this.setState({ loaded: true });
        );
    }

    methodThatIWantToTest() {
        //do some stuff here
    }

    render() {
        if (this.loaded) {
            // render stuff here
        } else {
            return null;
        }
    }
}

在测试中我想测试

describe('myComponent', () => {
   it('should do some stuff', () => {
      const shallowWrapper = shallow(<MyComponent {...props}/>);
      const method = shallowWrapper.instance().methodThatIWantToTest();
      ....such and such

   });
});

,但看起来MyComponent仅返回null,因此shallowWrapper.instance()也返回null。我尝试了shallowWrapper.update()和许多其他操作,但似乎根本不想渲染。.如何等待组件更新然后启动expect语句?

有人遇到过与我类似的问题,并且知道如何解决此问题吗?

2 个答案:

答案 0 :(得分:0)

这是一个有效的示例:


myComponent.js

import * as React from 'react';

export default class MyComponent extends React.Component {

  constructor(...props) {
    super(...props);
    this.state = { loaded: false };
  }

  componentDidMount() {
    this.props.fetchData().then(() =>
      this.setState({ loaded: true })
    );
  }

  methodThatIWantToTest() {
    return 'result';
  }

  render() {
    if (this.state.loaded) {
      return <div>loaded</div>;
    } else {
      return null;
    }
  }
}

myComponent.test.js

import * as React from 'react';
import { shallow } from 'enzyme';

import MyComponent from './myComponent';

describe('myComponent', () => {
  it('should do some stuff', async () => {
    const fetchData = jest.fn(() => Promise.resolve());
    const props = { fetchData };

    const shallowWrapper = shallow(<MyComponent {...props}/>);
    expect(shallowWrapper.html()).toBe(null);

    expect(shallowWrapper.instance().methodThatIWantToTest()).toBe('result');

    // pause the test and let the event loop cycle so the callback
    // queued by then() within componentDidMount can run
    await Promise.resolve();

    expect(shallowWrapper.html()).toBe('<div>loaded</div>');
  });
});

答案 1 :(得分:0)

它是render的结果,而不是null的实例。 shallowWrapper.instance()是组件类的实例,对于有状态组件,它不能是null。正如the reference所述:

  

返回(反应16.x)

     

ReactComponent:有状态的React组件实例。

     

null:如果包装了无状态React组件。

shallowWrapper.html()最初确实是null

原始代码有误,应为this.state.loaded而不是this.loaded

MyComponent extends React.Component {
  state = { loaded: false };

  componentDidMount() {
    this.props.fetchData.then(() => {
          this.setState({ loaded: true });
    });
  }

  methodThatIWantToTest() {
      //do some stuff here
  }

  render() {
      if (this.state.loaded) {
          return <p>hi</p>;
      } else {
          return null;
      }
  }
}

componentDidMountmethodThatIWantToTest最好被视为不同的单位。它们属于不同的测试。如果在生命周期挂钩中调用methodThatIWantToTest,则可能在componentDidMount测试中将其存根:

   it('should fetch data', async () => {
      const props = { fetchData: Promise.resolve('data') };
      const shallowWrapper = shallow(<MyComponent {...props}/>);
      expect(shallowWrapper.html()).toBe(null);
      await props.fetchData;
      expect(shallowWrapper.html()).toBe('<p>hi</p>');
   });

然后可以单独测试该方法。可以禁用生命周期挂钩,以减少活动部件的数量:

   it('should do some stuff', () => {
      const shallowWrapper = shallow(<MyComponent {...props}/>, {disableLifecycleMethods: true});
      const result = shallowWrapper.instance().methodThatIWantToTest();
      expect(result).toBe(...);    
   });