React-Jest Unit test an external module method that affects state - reactjs

I am working on a React application using Jest.
I want to test an imported module component method (closemodal):
<Modal
visible={this.state.showModal}
closemodal={() => this.setState({ showModal: false })} // <= this one
type="slideInDown"
>
I tried in my unit test to spy Modal closemodal method like that:
import Modal from "react-animated-modal";
let spyOnCloseModal;
beforeEach(() => {
spyOnCloseModal = jest.spyOn(Modal, "closemodal");
wrapper = shallow(<App />);
});
But when UT running I get this error:
Cannot spy the closemodal property because it is not a function; undefined given instead

Try passing a mock function.
test("checks closemodel", () => {
const props = {
closemodal: jest.fn()
};
const wrapper = shallow(<Modal {...props} />);
// trigger your `closemodal` function here
expect(props.closemodal).toHaveBeenCalledTimes(1);
});

Related

Why is JEST testing giving "Could not find "store" error when call setState?

I'm trying to test this:
(I need to confirm that when selectedDevice is called with DESKTOP prop, it calls openModal and that method sets the state of modalOpen to true)
openModal = () => {
this.setState({ modalOpen: true });
};
selectedDevice = () => {
const { device } = this.props;
const isMobile = device === MOBILE;
if (isMobile) {
this.closeWindow();
} else {
this.openModal();
}
};
and I'm testing like this (with JEST)
test('should openModal be called', () => {
const wrapper = mount(<Component
{...sampleProps}
deviceType={DESKTOP}
/>);
const selectedDevice = jest.spyOn(wrapper.instance(), 'selectedDevice');
selectedDevice();
expect(wrapper.state().modalActivated).toEqual(true);
});
Apparently, it seems to be reaching the openModal method in my component. However, I'm getting this error:
Invariant Violation: Could not find "store" in either the context or props of "Connect(Styled(Component))". Either wrap the root component in a <Provider>, or explicitly pass "store" as a prop to "Connect(Styled(Component))".
36 |
37 | openModal = () => {
> 38 | this.setState({ modalOpen: true });
| ^
I saw another solutions to that error message, but nothing seems to work for this specific error.
I already tried wrapping the component inside a Provider component with no luck.
You're getting the error because you're using a component which is wrapped inside of the connect HOC from react-redux and the connect HOC needs the redux Provider component with a state.
Your code should be something like this:
test("should openModal be called", () => {
const wrapper = mount(
<Provider store={CreateANewStoreForTest}>
<Component {...sampleProps} deviceType={DESKTOP} />
</Provider>
);
const selectedDevice = jest.spyOn(wrapper.instance(), "selectedDevice");
selectedDevice();
expect(wrapper.state().modalActivated).toEqual(true);
});
and for data on how to create a store read the DOC here

How to test or get value from state in react?

Hi could you please tell me How to test or get value from state in react ?
getting error
wrapper.instance(...).handleClickShowPassword is not a function
here is my code
https://codesandbox.io/s/l2lk4n794l
it("toggle showpassword value", () => {
wrapper.setState({ showPassword: false });
wrapper.instance().handleClickShowPassword();
expect(wrapper.state.showPassword).toEqual(true);
});
Since LoginContainer is an wrapped with an HOC, you either need to export the component without withStyles HOC or use dive on the wrapper to get the instance of the component. Also state is a function on component instance and hence you need to call it to access state
describe("<LoginContainer/>", () => {
let wrapper;
beforeEach(() => {
wrapper = shallow(<LoginContainer />);
});
it("toggle showpassword value", () => {
const comp = wrapper.dive();
comp.dive().setState({ showPassword: false });
comp.instance().handleClickShowPassword();
expect(comp.state("showPassword")).toEqual(true);
});
});
Working demo

How do I mock a react component property in jest which is instance of another class?

I want to test a react component which has instance of a service as a property. This service's method is called by a method in the component. I want to mock the service so its implementation is not my concern. Following is excerpts of my requirement:
// Component
export class SomeComponent extends React.Component {
constructor(props) {
super(props)
this.handleClick = this.handleClick.bind(this)
}
someService - new SomeService(arg1, arg2)
handleClick() {
// some transformations
this.someService.someMethod()
}
render() {
return <Button onClick={this.handleClick}>
</Button>
}
}
// test
describe.only('<SomeComponent/>', () => {
it.only('should call handleClick when button is clicked', () => {
const wrapper = shallow(<SomeComponent/>) // shallow render from enzyme
const handleClick = jest.fn()
const instance = wrapper.instance()
instance.handleClick = handleClick
wrapper.find(Button).simulate('click')
expect(handleClick).toHaveBeenCalledTimes(1)
})
})
But now I get the implementation details error of the services. How can I mock the service so that I can simply test the method of my Component?
If your project is a webpack project, then https://github.com/plasticine/inject-loader is very useful. You can simply swap any dependency with a mock in just a few lines of code.
describe('SomeComponent', () => {
let SomeComponent;
let SomeServiceSpy;
beforeEach(() => {
SomeServiceSpy= // {a mock/spy};
SomeComponent= require('inject-loader!./SomeComponent')({
'../services/SomeService': {SomeServiceSpy},
});
});
it('should ...', () => {
const wrapper = shallow(<SomeComponent/>)
wrapper.find(Button).simulate('click')
expect(SomeServiceSpy).toHaveBeenCalledTimes(1)
});
});
Note: make sure you don't import the module under test (SomeComponent) at the top of your file. The require call does that part.

How do I test that a function is called within a method using jest+enzyme+react+typescript?

Say I have this method in my react component
handleSubmit(){
if (this.state.fireRedirect === false){
this.setState({ fireRedirect: true }, () => { this.addEndpoint() });
}
}
How do I test that addEndpoint was called using Jest and Enzyme?
Use jest.spyOn
const spy = jest.spyOn(Component.prototype, "addEndPoint");
const wrapper = shallow(<Component/>);
expect(spy).not.toHaveBeenCalled();
wrapper.instance().handleSubmit();
expect(spy).toHaveBeenCalled();

Test if function is called react and enzyme

I am trying to test one of the methods in my react component. It is being called after a button click so I have the simulation in place with enzyme
it('clone should call handleCloneClick when clicked', () => {
const cloneButton = wrapper.find('#clone-btn');
cloneButton.simulate('click');
});
My component method is here:
_handleCloneClick(event) {
event.preventDefault();
event.stopPropagation();
this.props.handleClone(this.props.user.id);
}
The _handleCloneClick is being called when the user clicks on the button thats in the simulation, how can I go about testing that its been called successfully?
There are two options, either you should spy on _handleCloneClick of component's prototype, before you render the component:
export default class cloneButton extends Component {
constructor(...args) {
super(...args);
this. _handleCloneClick = this. _handleCloneClick.bind(this);
}
_handleCloneClick() {
event.preventDefault();
event.stopPropagation();
this.props.handleClone(this.props.user.id);
}
render() {
return (<button onClick={this. _handleCloneClick}>Clone</button>);
}
}
And in your test:
it('clone should call handleCloneClick when clicked', () => {
sinon.spy(cloneButton.prototype, '_handleCloneClick');
const wrapper = mount(<cloneButton/>);
wrapper.find('#clone-btn').simulate('click');
expect(spy).toHaveBeenCalled() //adept assertion to the tool you use
});
Or, you can try to set a spy after rendering the component and invoke wrapper.update() afterwards:
it('clone should call handleCloneClick when clicked', () => {
const wrapper = mount(<cloneButton/>);
sinon.spy(wrapper.instance(), "_handleCloneClick");
wrapper.update();
wrapper.find('#clone-btn').simulate('click');
expect(spy).toHaveBeenCalled() //adept assertion to the tool you use
});

Resources