I'm trying to test a component which renders two different sub-components when its internal state changes from false to true: when it's false it renders a button that, if pressed, changes the state from false to true and renders the other one. The other is a form that on submit does the opposite.
I've tried to spy on the useState hook to test if it's actually called. But by mocking the module, the actual setState won't work when I need it in the second part of the test, to test the form that renders after.
This is my component:
import React, { useState } from 'react';
const MyComponent = ({handleChange, handleInput}) => {
const [state, setState] = useState(false);
return (
<div>
{!state
? (
<button
data-test="button1"
type="button"
onClick={() => setState(true)}
>
RenderForm
</button>
)
: (
<form onSubmit={() => setState(false)}>
<input type="text" onChange={e => handleChange(e)} />
<button type="submit">
Submit Form
</button>
<button type="button" onClick={() => setState(false)}>
Go Back
</button>
</form>
)
}
</div>
);
};
export default MyComponent;
This is my test:
import React from 'react';
import { mount } from 'enzyme';
import MyComponent from './MyComponent';
describe('MyComponent', () => {
let component;
const mockChange = jest.fn();
const mockSubmit = jest.fn();
const setState = jest.fn();
const useStateSpy = jest.spyOn(React, 'useState');
useStateSpy.mockImplementation(init => [init, setState]);
beforeEach(() => {
component = mount(<MyComponent handleChange={mockChange} handleSubmit={mockSubmit}/>);
});
afterEach(() => {
component.unmount();
});
it('calls setState when pressing btn', ()=> {
component
.find('[data-test="button1"]')
.simulate('click')
expect(setState).toHaveBeenCalledWith(true) // passes
})
it('calls handleChange when input changes value', () => {
component
.find('[data-test="button1"]') //can't be found
.simulate('click')
component
.find('input')
.simulate('change', { target: { value: 'blabla' }})
expect(mockChange).toHaveBeenCalled() // doesn't pass
})
});
I know what's the problem, but I don't know how to fix it. Is there a way to mock setState? Or is there a way to split the tests so that they don't interfere with each other?