使用异步setState进行反应测试

时间:2016-02-05 13:50:23

标签: javascript testing reactjs

我是React测试的新手,我很难搞清楚以下问题:

我正在尝试模拟输入onChange事件。它是一个文本输入,用于过滤表格中的结果。 InteractiveTable有一个受控输入字段(ControlledInput)和一个Facebook FixedDataTable的实例。

这是测试:

let filter = ReactTestUtils.findRenderedComponentWithType(component, ControlledInput);
let input = ReactTestUtils.findRenderedDOMComponentWithTag(filter, 'input');
input.value = 'a';
ReactTestUtils.Simulate.change(input);
console.log(component.state);

在输入更改时,组件使用输入的值更新其状态,但由于setState是异步的,因此console.log将注销先前的状态,并且我无法查询结构用于测试的组件,因为它尚未更新。我错过了什么?

编辑:要清楚,如果我在setTimeout中进行断言,它将通过,所以它肯定是setState的异步性质的问题。

我找到了一个解决方案,其中我覆盖了组件的componentDidUpdate方法:

component.componentDidUpdate = () => {
  console.log(component.state); // shows the updated state
  let cells = ReactTestUtils.scryRenderedComponentsWithType(component, Cell);
  expect(cells.length).toBe(30);
  done();
};

如果组件有自己的componentDidUpdate方法,那么这是不可能的,所以这不是一个好的解决方案。这似乎是一个非常普遍的问题,但我找不到它的解决方案。

1 个答案:

答案 0 :(得分:2)

通常情况下,当我在测试时遇到类似情况时,我会尝试将事情分开一点。在您当前的测试中,(根据您的测试框架的风格),您可以模拟组件的setState方法,并确保在模拟更改时使用您期望的方法调用它。

如果你想进一步覆盖,在另一个测试中,你可以使用一些模拟数据调用真实的setState,然后使用callback对所呈现的内容进行断言,或者确保其他内部方法是调用。

或者:如果您的测试框架允许simulating async内容,您也可以尝试调用它并一次性测试整个事情。