React, how to simulate user input for unit testing?
You seem to have a bug in your Input component. When event.target.value.length > this.props.maxLength
you never set the actual state, leaving the state.value
as ''
. It seems you expected it to have been set to the value, but truncated to maxLength. You'll need to add that yourself:
handleChange(event) {
/* Check if max length has been set. If max length has been
set make sure the user input is less than max Length, otherwise
return before updating the text string. */
if (this.props.maxLength) {
if (event.target.value.length > this.props.maxLength) {
// ** Truncate value to maxLength
this.setState({ value: event.target.value.substr(0, this.props.maxLength) });
return;
}
}
this.setState({ value: event.target.value });
}
... then, the following test works and passes:
it('Make sure inputted text is shorter than max length', () => {
const result = mount(<Input maxLength={10}></Input>);
result.find('input').simulate('change', { target: { value: '1234567890!!!' } });
expect(result.state().value).to.equal("1234567890");
});
2trill2spill
Fuzzing, FreeBSD, MacOS, C, Golang, Node.js, and React.
Updated on July 16, 2022Comments
-
2trill2spill almost 2 years
I have been trying to unit test a react component that takes in user input. More specifically I'm trying to test the
onChange
function within the react component. However I can't seem to set the input value, I've tried a few different ways suggested on the internet and none seem to work. Below is the component I'm trying to test.class Input extends Component { constructor(props) { super(props); this.state = {value: ''}; this.handleChange = this.handleChange.bind(this); } handleChange(event) { /* Check if max length has been set. If max length has been set make sure the user input is less than max Length, otherwise return before updating the text string. */ if(this.props.maxLength) { if(event.target.value.length > this.props.maxLength) { return; } } this.setState({ value: event.target.value }); } render () { const { disabled, label, maxLength, multiline, type, value, ...others} = this.props; const theme = themeable(others.theme); let inputClassName = classNames({ "input": type !== 'checkbox', "checkbox": type == 'checkbox', disabled, multiline, value, [`${this.props.className}`]: !!this.props.className }); return ( <div {...theme(1, 'container')}> {this.props.label ? <label htmlFor={this.props.htmlFor} {...theme(2, 'label')}>{label}</label> : null} <input value={this.state.value} {...theme(3, ...inputClassName)} onChange={this.handleChange} type={type} /> </div> ); } }
I found this issue: https://github.com/airbnb/enzyme/issues/76 and tried the suggestions towards the bottom, I keep getting either undefined or a blank string. I tried levibuzolic's suggestion of using enzyme's simulate change, which can be seen below. However this just returns
AssertionError: expected '' to equal 'abcdefghij'
it('Make sure inputted text is shorter than max length', function() { const result = mount(<Input maxLength={10}></Input>); result.find('input').simulate('change', {target: {value: 'abcdefghijk'}}); expect(result.state().value).to.equal("abcdefghij"); });
Then I tried takkyuuplayer's suggestion which is also below. This also fails with
AssertionError: expected '' to equal 'abcdefghij'
it('Make sure inputted text is shorter than max length', function() { const result = mount(<Input maxLength={10}></Input>); result.find('input').node.value = 'abcdefghijk'; expect(result.state().value).to.equal("abcdefghij"); });
I found this article: https://medium.com/javascript-inside/testing-in-react-getting-off-the-ground-5f569f3088a#.f4gcjbaak and tried their way which also failed.
it('Make sure inputted text is shorter than max length', function() { const result = mount(<Input maxLength={10}></Input>); let input = result.find('input'); input.get(0).value = 'abcdefghijk'; input.simulate('change'); expect(result.state().value).to.equal("abcdefghij"); });
Finally I tried using the react test utils as suggested by Simulating text entry with reactJs TestUtils, below is the code I tried, however this failed with the error message:
TypeError: Cannot read property '__reactInternalInstance$z78dboxwwtrznrmuut6wjc3di' of undefined
it('Make sure inputted text is shorter than max length', function() { const result = mount(<Input maxLength={10}></Input>); let input = result.find('input'); TestUtils.Simulate.change(input, { target: { value: 'abcdefghijk' } }); expect(result.state().value).to.equal("abcdefghij"); });
So how does one simulate user input so they can test the
onChange
function? -
umesh shakya over 4 yearshow can web write test case without using state?