Trying to test a simulate change on a textinput component using Jest - reactjs

I'm trying to simulate a change event on a component(ListPage)
<TextInput
className="search-s"
id="textM"
width="m"
type="search"
handleChange={this.props.updateS}
placeholder="Search for a scenario"
/>
</div>
The handleChange attribute calls a prop function called updateS which looks like
updateS(e) {
this.setState({
name: e.target.value,
});
}
And what I currently have for the test function
it("should call handleChange on change with the correct params", () => {
const wrapper = shallow(<ListPage />);
const spy = jest.spyOn(wrapper.instance(), "handleChange");
wrapper.instance().forceUpdate();
const p = wrapper.find(".search-s");
p.simulate("change");
expect(spy).toHaveBeenCalled();
});
For some reason my test function doesnt work when I try to simulate a change and check whether the updateSearch function was called. All the guides online have examples of testing functions within the component but not passed props which I feel is what is causing the problem. Any insight would be great

Related

Jest test failing and not receiving toHaveBeenCalled from simulated click

I am having an issue with a Jest test using React. I am also using Enzyme as well. Additionally, I am using Redux.
If you see the jest test below you will see two simulated clicks. The reason for two simulated clicks in my test below is that the inputs inside the "showAddItem" check are both hidden. Clicking on "div#add_item" allows this div to be visible. After this, clicking on the "input#add_item_submit" should call the addItemToWatchList.
In my testing using a debugger and running the tests, the first simulated click does set the state to showAddItem to true. This allows the input "add_item_submit" to be available in the DOM. After that is shown the second simulated click in the test doesn't seem to fire because the addItemToWatchList doesn't get called. The output of my test is:
Expected number of calls: >= 1
Received number of calls: 0
relevant react component code:
{ this.state.showAddItem ? <div>
<input type="text" name="watchListItem" value={this.state.watchListItem}
onChange={this.handleInputChange}></input><br />
<input type="submit" id="add_item_submit" value="Add Item"
onClick={ () => this.addItemToWatchList()}/>
</div> : null }
relevant Jest/enzyme test
it('should call addItemToWatchList when adding a item', () => {
const initialState = { userReducer: {user: { id: 1, email: "test#test.com"}} }
const mockStore = configureStore([]);
const store = mockStore(initialState);
const component = mount(<Provider store={store}>
<AddItem />
</Provider>);
const mockedAddItemToWatchList = jest.fn();
component.instance().addItemToWatchList = mockedAddItemToWatchList
//sets state to showAddItem to true
component.find('div#add_item').simulate('click')
component.find('input#add_item_submit').simulate('click')
expect(mockedAddItemToWatchList).toHaveBeenCalled()
});
Just a side note, I also did try doing jest.spyOn without any luck as well.
The component.instance() might be returning the instance of Provided. You can try mounting AddItem directly an mocking its internal method behaviour.
const component = mount(
<AddItem />);

how to test a method of a component in enzyme is it calls a method which is passed as prop

handleConfirm = () => {
this.props.handleCompletionDateChange();
this.setState({ showInformation: false });
};
I have above method handleConfirm in our class component DateSection
if I test handleConfirm method using below code I am getting error as
TypeError: _this.props.handleCompletionDateChange is not a function
const wrapper1 = shallow(<DateSection {...props} />);
const instance = wrapper1.instance() as any;
spyOn(instance, 'handleConfirm').and.callThrough();
expect(instance.handleConfirm()).toBe(true);
expect(instance.handleConfirm).toHaveBeenCalled();
How should pass the above function as a prop while testing,
You better not access instance() in tests. Tests become fragile(say, converting component into functional will break everything while component itself can be fine) and less reliable(if you calling methods that will never be called in real life - e.g. if that method is not called by others and not bound as event handler).\
Instead you need to find way to call that with the help of .simulate() or .props().someCabllackProp(...).
Assuming this handleConfirm is onClick handled for some <button name="confirm">:
it('calls handleCompletionDateChange', () => {
const handleCompletionDateChange = jest.fn();
const wrapper1 = shallow(<DateSection
{...props}
handleCompletionDateChange={handleCompletionDateChange} \
/>);
wrapper1.find("button[name='confirm']").simulate('click');
expect(handleCompletionDateChange).toHaveBeenCalled();
})
The same to validate this.setState({ showInformation: false }); part. We need to figure out how to validate that based on render results.
Something like
expect(wrapper1.find("[data-id='information-block']")).toHaveLength(0);

Jest mocking with react calling actual event handler after calling mock function

I have this component test
const component = mount(<MemoryRouter><Login/></MemoryRouter>);
const emailField = component.find('input[type="email"]');
const passwordField = component.find('input[type="password"]');
const mockedSubmitFunction=jest.fn();
component.find(Login).instance().onSubmit=mockedSubmitFunction;
emailField.simulate('change', { target: { value: testEmail } });
passwordField.simulate('change', { target: { value: testPassword } });
component.find('form').simulate('submit');
expect(mockedSubmitFunction).toBeCalled();
and in the component i have
in constructor :-
this.onSubmit = this.onSubmit.bind(this);
and the eventhandler
onSubmit(event) {
event.preventDefault();
when i put a breakpoint in onSubmit it is coming to the component function after executing the mocked onSubmit, why is this happening.
I assumed it will only call the mocked onSubmit.
What am I doing differently?
CodeSandbox :https://codesandbox.io/s/q95lv7vlrw
But the sandbox is showing Could not find module in path: 'object-inspect/util.inspect' relative to '/node_modules/object-inspect/index.js' for some reason, which is unrelated i guess
So you got function mocked, but actual onSubmit is called. Instead if you want to call only mocked fn you have to provide it (as a prop in your test spec for example).
const mockedSubmitFunction = jest.fn(event => {
console.log("Mocked function");
});
const component = mount(
<MemoryRouter>
<Login login={mockedSubmitFunction} />
</MemoryRouter>
);
I updated sandbox for you.
You can additionally check this explained example on form testing.
Update: i suppose that the actual problem OP has was that mock function was firing, but it was copied to instance, thus expect...toBeCalled() fails (actual mockedFn was not called). You can avoid these problems by passing mocked function as a prop, spying on a function, etc.

How to mock component method using Jest and Enzyme

I have a React component that has a text input as one of the children inside the main wrapper. When the input gains focus it calls a function via its onFocus property. So the component's structure is something like this:
<div className="main-wrapper">
<input type="text" onFocus={this.focusHandler} />
</div>
Elsewhere in the class there is a method named focusHandler that looks something like this
focusHandler = () => {
//Do whatever it is that focus handlers do.
//In this case that involves changing the local state, so there is something like
this.setState({ fieldHasFocus: true });
}
What I would like to do is to have a test (in Jest) that would verify that when the input gains focus the focusHandler() method is called. However, I can't figure out how to put a mock into my test for focusHandler() and to check whether or not it is called when I simulate('focus') on the input field.
You can spy on the before you render the component. You don't need to force update the instance of the component. Declare the spy function at the top of the file before your spec/describe block.
const focusHandlerSpy = jest.spyOn(YourComponent.prototype, 'focusHandler');
Then ...
describe('When the input field is focused', () => {
beforeEach(() => {
component.find('input').simulate('focus');
});
it('should invoke the focusHandlerSpy function', () => {
expect(focusHandlerSpy).toHaveBeenCalled();
});
});
Try something like this:
const wrapper = shallow(<YourComponent />);
const focusHandlerSpy = jest.spyOn(wrapper.instance(), 'focusHandler');
wrapper.instance().forceUpdate();
Now your focusHandlerSpy will be called on focus.

Why is my button undefined in my test?

My test:
describe('button component', () => {
it('should toggle off when clicked', () => {
let component;
component = ReactTestUtils.renderIntoDocument(<Search />);
let searchbtn = ReactTestUtils.findRenderedDOMComponentWithTag(component, 'button');
ReactTestUtils.Simulate.click(searchbtn);
console.log(searchbtn, 'search button***'); //UNDEFINED
expect(searchbtn.calledOnce).to.equal(false);
})
});
This is my search component:
render() {
return (
<div className="search">
<button className="searchButton" onClick={this.handleSearch}>{this.state.on ? 'ON' : 'OFF'}</button>
</div>
);
}
Do I need to spy on it or mock it? or is there a better way to test buttons in react?
Since you have added enzyme tag I will answer using enzyme.
It can be tested very easily via shallow rendering -
const searchWrapper = shallow(<Search />);
const button = searchWrapper.find('button').first();
When you simulate click event on button the onClick handler provided via onClick prop which is handleSearch in your case will be called.
So if you are setting some state based on the onClick function call corresponding ui changes based on the state changes can be compared or checked if changes were reflecting correctly in the dom.
or
if you just want to check if method was called or not by using a fake method of similar name -
const onButtonClick = sinon.spy();
expect(onButtonClick.calledOnce).to.equal(false);
button.setProps({ onClick:onButtonClick});
button.simulate('click');
expect(onButtonClick.calledOnce).to.equal(true);

Resources