问题
I am building an app with React. I am hiding a file input element (<input type="file"/>
) "behind" a react-bootstrap Button
to be able to control styling. So, when the button is clicked I turn around and fire a synthetic click event on the text input element, as shown below.
class OpenFileButton extends React.Component {
...
clickHandler() {
this.refs['input'].click();
}
render() {
return (
<ButtonGroup>
<div>
<input type="file" onChange={this.props.someCallback}
ref="input" style={{display: 'none'}}/>
<Button onClick={this.clickHandler}>Open File</Button>
</div>
</ButtonGroup>
);
}
}
I want to be able to test this with Jest/Enzyme. However, while I can simulate a click event on the button, I haven't figured out how to detect a synthetic click event on the file input element.
I have tried using Jest/Enzyme to mock the click method on the input element.
const component = mount(<OpenFileButton/>);
const fileInput = component.find('input');
const button = component.find('Button');
fileInput.click = jest.fn();
button.simulate('click');
expect(fileInput.click).toHaveBeenCalled();
However, mocking the click
method this way does not work. I also can't add an onClick
attribute, i.e. fileInput.props().onClick = jest.fn()
does not work.
This question is about detecting synthetic click events in the code itself, not in the test code, and so is not relevant.
So, how can I detect a (synthetic) click event on a DOM element using Jest/Enzyme?
回答1:
<input />
or this.refs.input
is an instance of HTMLInputElement
.
Then you can test if HTMLInputElement.prototype.click
is called .
Using sinon you will have :
import sinon from 'sinon';
import {mount} from 'enzyme';
const clickInputSpy = sinon.spy(HTMLInputElement.prototype, 'click')
const component = mount(<OpenFileButton/>);
const button = component.find('Button');
button.simulate('click');
expect(clickInputSpy.called).toBeTruthy();
clickInputSpy.restore();
const clickInputSpy = sinon.spy(HTMLInputElement.prototype, 'click');
console.log(
'Is <input /> clicked ? ', clickInputSpy.called
);
document.querySelector('input').click();
console.log(
'Is <input /> clicked ? ', clickInputSpy.called
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/sinon.js/1.15.4/sinon.min.js"></script>
<input />
回答2:
The solution here involves spying on the click
method of the particular file input element that I'm interested in. I can thus check to see if this file-input-element-click-spy was called after a click is simulated on the button element, as follows:
const openFileButtonWrapper = mount(<OpenFileButton/>);
const buttonWrapper = openFileButtonWrapper.find(Button);
const fileInputWrapper = openFileButtonWrapper.find('input [type="file"]');
const fileInput = fileInputWrapper.get(0);
const clickInputSpy = spyOn(fileInput, 'click');
buttonWrapper.simulate('click');
expect(clickInputSpy).toHaveBeenCalled();
The answer by @AbdennourTOUMI used Sinon's spy
method which reminded me that Jest uses some Jasmine functionality, including its spyOn
method, that isn't obvious from the Jest documentation. So, even though that other answer ended up spying on _all_ input elements, which is not ideal, it did send me in the right direction, so thank you, Adbennour.
来源:https://stackoverflow.com/questions/42600805/detect-synthetic-click-in-react-during-testing-with-jest-enzyme