I am testing on the execution of functions inside a React component that's connected to redux store. I was only able to spy on some of the functions, the rest all returned: Cannot spy the setEmail(or other function names) property because it is not a function; undefined given instead
below in code I added arrows pointing out which ones are spy-able, when I console.log(BaseForm.WrappedComponent.prototype.functionName) the ones that are not spy-able returned undefined. the one that can be spied on returned [Function:...] I really do not understand why?
class BaseForm extends React.Component {
constructor(props) {
super(props);
this.state = {
ages: [],
};
}
componentDidMount() {
this.createAges(); <----- can spy on this one as it is a function
}
setEmail = (elemName, value) => { <------ Cannot spy the setEmail property because it is not a function; undefined
this.setState({ email: value });
this.props.saveEmail(value);
};
handleEmailSignup = (e) => { <-------- Cannot spy the setEmail property because it is not a function; undefined
this.setState({ offersSignup: e.target.checked });
};
onChangeAge = (e) => { <------ Cannot spy the setEmail property because it is not a function; undefined
this.setState({
selectedAge: e.target.value,
selectedAgeIndex: e.target.index - 1,
errorAge: '',
});
};
createAges() { <------ can spyOn as it is a function
let ages = [
{ value: '', text: !__isEmpty(sessionStorage.getItem('gf')) ? 'Kid age' : 'Your age' },
{ value: '14 and younger', text: '14 and younger' },
{ value: '15', text: '15' },
{ value: '16', text: '16' },
{ value: '17', text: '17' },
];
this.setState({ ages: ages });
}
render() {
return (
<div>
<div data-type="email" className="textbox-wrapper">
<Textbox
type="email"
placeholder="Email Address"
name="register-email"
onChange={this.setEmail}
onBlur={this.checkUserByEmail}
defaultValue={this.state.email} <------- in test the value does not change, but on UI it does and functions well
isError={!__isEmpty(this.props.emailErrorClass)}
/>
</div>
<Dropdown options={this.state.ages} onChange={this.onChangeAge} selectedValue={this.state.selectedAge} />
<div>
<input name="offersSignup" type="checkbox" onChange={this.handleEmailSignup} checked={this.state.offersSignup} />
</div>
</div>
);
}
}
const mapDispatchToProps = { saveEmail };
export default connect(null, mapDispatchToProps)(BaseForm);
it.only('set email in local state if onChange of Textbox is fired', () => {
//console.log(BasePartnerRegistrationForm.WrappedComponent.prototype.setEmail);
// above is undefined
const setEmailSpy = jest.spyOn(BaseForm.WrappedComponent.prototype, 'setEmail');
const wrapper = mount(
<Provider store={store}>
<BaseForm {...baseProps} />
</Provider>
);
const event = { target: { value: 'event value' } };
wrapper.find('Textbox').at(0).simulate('change', event);
wrapper.update();
expect(setEmailSpy).toHaveBeenCalled();
// below shows unchanged email value in state
// expect(wrapper.find('Textbox').at(0).props().defaultValue).toBe(event.target.value);
});
Below tried a new approach, console errors: Expected: "event value" Received: "" in other words,per test case, the setState is not functioning, but it functions well on UI and in chrome console too.
it('set email in local state if onChange of Textbox is fired', async () => {
const wrapper = mount(
<Provider store={store}>
<BasePartnerRegistrationForm {...baseProps} />
</Provider>
);
const event = { target: { value: 'event value' } };
wrapper.find('Textbox').at(0).simulate('change', event);
await waitFor(() => expect(wrapper.find('Textbox').at(0).props().defaultValue).toBe(event.target.value));
});