ReactTestUtils.Simulate问题小记
首先哀悼Hexo好像被墙了。。。不知道两会之后会不会恢复。
好久没写过一篇像样的技术博客了。。。赶巧最近几天碰到好几个以前碰到过但是没太弄清楚的问题,现在抽时间记一下吧。这篇先记一下今天碰到的关于ReactTestUtils.Simulate的一点小问题。
ReactTestUtils.Simulate
首先ReactTestUtils是一套便于对React进行unit test的工具(React Test Utils,字面意思了。。。),其中官方文档提到Simulate is possibly the single most useful utility in ReactTestUtils.
我测试时用到了如下代码:
被测文件step-input.jsx
1 | //change event handler |
1 | //lots of Material UI TextField components |
测试文件部分代码
1 | ; |
测试代码中的ReactTestUtils.Simulate.change部分并没能触发onChange事件,从而没调用changeHandler。
github上找到了类似issue[RaisedButton] TestUtils.click does not work,看完后仔细思考了一下,发现问题在ReactTestUtils.Simulate官方文档里提到的Simulate an event dispatch on a DOM node,既然是DOM node,我的测试代码中const node = stepInput.refs.base固然有问题了,因为这里的stepInput.refs.base是React Component而不是DOM node。
仿照类似该issue中的做法,通过找React Component下的关键DOM node可以完成。但是其中有意思的地方是issue下几个人的留言,@weeksie用了instance.getDOMNode().firstChild即只找了一层就找到了, 而@omerts用了React.findDOMNode(saveButton).firstChild.firstChild则找了两层。再仔细想,可能跟Material UI Component实现时,关键DOM node(例如此issue里RaisedButton的关键DOM node是<button>)相对于Component顶层DOM node的位置有关。
通过查看自己的页面Elements信息,发现TextField顶层DOM node下的第三个DOM node<input>是我要查找的关键DOM node,即查找方法是node.getDOMNode().childNodes[2]。修改代码后再进行测试,发现部分TextField正确触发了onChange事件,另一部分还是没触发。通过审查页面Elements信息发现,同为Material UI TextField Component,生成的DOM node的结构会有不同的结果,本例中另一种的关键DOM node变成了<textarea>,且在node.getDOMNode().childNodes[2].childNodes[2]的位置。最后经研究发现是Material UI通过各种参数配置(例如floatingLabelText, multiLine等)生成的DOM node结构不一样。
总结
ReactTestUtils.Simulate确实便于测试React,但是仅便于直接测试React中的DOM Node- 若React Component生成的DOM结构较为固定,也可以使用
ReactTestUtils.Simulate - 若React Component生成的DOM结构不固定,不建议使用
ReactTestUtils.Simulate进行测试,例如Material UI。因为很可能因为调整UI界面造成测试出错,例如仅仅因为给TextField添加了Label,或修改了multiLine属性就造成测试出错,且这种错误具有不确定性,不知道修改某个属性是否会引起其关键DOM node相对顶层DOM node位置的改变。