触发 onInput 处理程序
Triggering onInput handler
想象一个带有 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
的点击,但它没有解决问题。
我怎样才能通过考试?
主要问题是 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 属性在不导致组件重新渲染的情况下发生变化。如果您需要更彻底地测试浏览器交互,您可能需要寻求集成(端到端)测试解决方案。
想象一个带有 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
的点击,但它没有解决问题。
我怎样才能通过考试?
主要问题是 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 属性在不导致组件重新渲染的情况下发生变化。如果您需要更彻底地测试浏览器交互,您可能需要寻求集成(端到端)测试解决方案。