【问题标题】:how to test a react component after data is fetch in componentDidMount?在componentDidMount中获取数据后如何测试反应组件?
【发布时间】:2018-08-25 00:26:22
【问题描述】:

我有一个有条件渲染的 react 组件(如果获取数据则渲染,否则返回 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 语句?

有没有人遇到过和我类似的问题并且知道如何解决这个问题?

【问题讨论】:

  • 您能否尝试在您的渲染方法中不返回null,而是返回&lt;div /&gt;

标签: reactjs jestjs enzyme


【解决方案1】:

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

返回 (React 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(...);    
   });

【讨论】:

  • 感谢您发现我的错误并试图帮助我。但不幸的是,它正在工作:(我得到了yield is a reserved word for await{disableLifecycleMethods....} 不能解决.instance() 问题
  • 实际上,我使用redux 通过connect 使用store 导出此类。也许这就是测试失败的原因..
  • yield 是保留字 是因为await 没有在async 中使用,已修复。 实际上,我正在使用 redux 通过 connect 导出这个类和 store - 这是很有可能的。连接的组件不是您的组件类,它是您的组件包装的另一个组件,它没有methodThatIWantToTest。考虑单独测试您的单元。你的班级是一个单元。连接类是另一个。额外的移动部件会阻止您有效地检测到麻烦制造者,这是单元测试所必需的。
【解决方案2】:

这是一个工作示例:


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

【讨论】:

    猜你喜欢
    • 2021-09-09
    • 1970-01-01
    • 2015-11-02
    • 2023-03-07
    • 2020-11-26
    • 2019-05-01
    • 2020-02-04
    • 2022-06-10
    • 1970-01-01
    相关资源
    最近更新 更多