使用上下文的React组件对单元测试很困难

时间:2016-05-07 16:10:44

标签: unit-testing reactjs

React不提供允许您将上下文传递给已创建的组件类的API,因此您必须编写一个提供上下文的包装器组件。

不幸的是,一旦你这样做,你就不再可以直接访问你想要测试的组件 - 与TestUtils.renderIntoDocument不同,像TestUtils.findRenderedComponentWithType这样的函数不返回实际的渲染组件实例,它们只返回组件构造函数。因此,您无法在执行测试之前调用组件上的方法,或将组件状态设置为某个已知值。您唯一可以访问的是组件的DOM节点,如果你想做的只是黑盒测试,但是对于某些类型的组件是不够的,这很好。

我很想知道是否有人为此提出了解决方案。我尝试过十几种不同的方法,但都没有。 (例如,我尝试在我的包装器组件中使用'ref',但它有同样的问题 - 不能让你访问真实对象。)

2 个答案:

答案 0 :(得分:3)

(回答我自己的问题)

对所有这一切的正确答案是使用enzyme,它取代了标准的React测试工具 - 它提供了大量的功能与类似jQuery的API,最重要的是它完全支持组件上下文。我已将所有测试都转换为它,这很棒!

答案 1 :(得分:0)

您可以构建一个模拟父组件,如:

class MockContextContainer extends Component {
  static propTypes = {
    children: PropTypes.element.isRequired,
  };
  static childContextTypes = {
    onSetTitle: PropTypes.func,
  };
  getChildContext() {
    return {
      onSetTitle: () => {},
    };
  }
  render() {
    return this.props.children;
  }
}

然后在测试中使用它(在这种情况下,它是一个忘记密码的形式示例):

const cxtForgot = TestUtils.renderIntoDocument(
      <MockContextContainer><ForgotPasswordForm /></MockContextContainer>
);

您可能已经在做什么。 然后你可以做以下事情:

const input = TestUtils.findRenderedDOMComponentWithClass(
      cxtForgot, 'ForgotPasswordForm-input'
);

// enter a valid email
input.value = 'abc@hotmail.com';

TestUtils.Simulate.change(input);

// no error class and button is now enabled
assert(!input.classList.contains('error'));
const button1 = TestUtils.findRenderedDOMComponentWithClass(
    cxtForgot, 'primary-button'
);
assert(!button1.disabled);

上面的Simulate.change可以改变组件的内部状态。 至于你的问题:“在执行测试之前将组件状态设置为某个已知值”,你可以将不同的道具传递给组件,并为每个场景进行不同的测试