想象一个带有oninput
事件监听器的简单contentEditable组件。
export default React.createClass({
render() {
return React.createElement('p', {
contentEditable: true,
onInput: this.emitChange
});
},
emitChange(e) {
console.log("Input event occurred", e);
}
});
在我的测试中,我模拟了组件上的input
事件(例如用户在contentEditable标记中键入字母' a')。
这适用于浏览器,我可以点击该组件,按下' a'钥匙,我会看到一个' a'在标记中,console.log
将触发。我无法让它在这个测试中工作:
// Require the code from the block above.
var CE = require('content-editable');
describe('Component', function() {
it('updates state when we type', function() {
// Render a component instance and get a handle on it.
let ce = TestUtils.renderIntoDocument(<CE/>);
let _ce = ReactDOM.findDOMNode(ce);
TestUtils.Simulate.input(_ce, {
key: 'a'
});
expect(_ce.textContent).to.equal('a');
});
});
此测试失败,因为_ce.textContent
是一个空字符串。我已经尝试在模拟输入之前模拟_ce
上的点击,但它并没有解决问题。
如何通过测试?
答案 0 :(得分:2)
主要问题是TestUtils.Simulate实际上并没有向DOM发送事件,它会创建一个虚假事件并通过React的事件处理系统发送它。您可以通过回调将更改事件传播回父组件来缓解此问题,您可能还需要执行此操作来检索可编辑的值:
export default React.createClass({
propTypes: {
onChange: React.PropTypes.func
},
render() {
return React.createElement('p', {
contentEditable: true,
onInput: this.emitChange
});
},
emitChange(e) {
if (this.props.onChange) {
this.props.onChange(e);
}
}
});
现在我们可以测试是否调用了onChange:
describe('Component', function() {
it('updates state when we type', function() {
let changeFired = false;
let ce = TestUtils.renderIntoDocument(<CE onChange={verify} />);
let _ce = ReactDOM.findDOMNode(ce);
TestUtils.Simulate.input(_ce, {
key: 'a'
});
function verify(e) {
changeFired = true;
expect(e.key).to.equal('a');
}
expect(changeFired).to.equal(true);
});
});
这将对emitChange
函数中的代码进行单元测试,而不与环境的其他部分进行任何实际交互。这可能是您在单元测试中所需要的,因为当用户键入一个键时,您的组件并不关心浏览器对DOM的作用,它关心的是它能够在浏览器告诉它时执行某些操作事情发生了。
通常在React单元测试中,您不会看到textContent
和innerHTML
DOM属性发生更改,而不会导致组件重新呈现。如果您需要更彻底地测试浏览器交互,则可能需要采用集成(端到端)测试解决方案。