Issue
I am trying to test calling a component method from a React Native Button
element.
For some reason, the test fails unless I do BOTH of these things.
wrapper.find(Button).first().props().onPress();
wrapper.find(Button).first().simulate('press');
If I comment out either of the lines, the test fails indicating that expect(instance.toggleEmailPasswordModal).toHaveBeenCalled();
failed.
Here is my component:
import React, { Component } from 'react';
import { Button, SafeAreaView, Text } from 'react-native';
import EmailPasswordModal from './EmailPasswordModal/EmailPasswordModal';
class Login extends Component {
state = {
emailPasswordModalVisible: false,
};
toggleEmailPasswordModal = () => {
console.log('TOGGLED!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!');
const { emailPasswordModalVisible } = this.state;
this.setState({ emailPasswordModalVisible: !emailPasswordModalVisible });
};
render() {
const { emailPasswordModalVisible } = this.state;
return (
<SafeAreaView>
<EmailPasswordModal
visible={ emailPasswordModalVisible }
close={ this.toggleEmailPasswordModal }
/>
<Text>Login Screen!</Text>
<Button
onPress={ this.toggleEmailPasswordModal }
title="Login with Email and Password"
color="#841584"
accessibilityLabel="Login with Email and Password"
/>
</SafeAreaView>
);
}
}
export default Login;
Here is my test:
import React from 'react';
import ShallowRenderer from 'react-test-renderer/shallow';
import { shallow } from 'enzyme';
import { Button } from 'react-native';
import Login from './Login';
describe('Login Screen', () => {
describe('Snapshot Tests', () => {
it('renders the screen with default state', () => {
const renderer = new ShallowRenderer();
const props = {};
renderer.render(<Login { ...props } />);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
});
describe('Functional Tests', () => {
it('calls the toggleEmailPasswordModal method', () => {
const wrapper = shallow(<Login />);
const instance = wrapper.instance();
jest.spyOn(instance, 'toggleEmailPasswordModal');
wrapper.find(Button).first().props().onPress();
wrapper.find(Button).first().simulate('press');
expect(instance.toggleEmailPasswordModal).toHaveBeenCalled();
});
});
});
Oddly, when the test runs, the output shows "TOGGLED!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" twice because of the logging in the component.
However, if I change the expect
to :
expect(instance.toggleEmailPasswordModal).toHaveBeenCalledTimes(1);
the test passes.
If I change the expect
to :
expect(instance.toggleEmailPasswordModal).toHaveBeenCalledTimes(2);
the test fails saying toggleEmailPasswordModal
was only called 1 time.
Why do I need BOTH of those wrapper.find(Button)...
lines? I've never seen any other tests requiring both of them.
Thanks, Justin
UPDATE:
I updated my test as follows:
it('calls the toggleEmailPasswordModal method', () => {
const wrapper = shallow(<Login />);
const instance = wrapper.instance();
jest.spyOn(instance, 'toggleEmailPasswordModal');
wrapper.find(Button).first().props().onPress();
wrapper.find(Button).first().simulate('press');
expect(instance.toggleEmailPasswordModal).toHaveBeenCalled();
// I ADDED THIS SECTION HERE
expect(instance.state.emailPasswordModalVisible).toBe(true);
});
The test fails because instance.state.emailPasswordModalVisible = false
. That's strange as the toggleEmailPasswordModal apparently is called. However, since I suspect it's actually being called twice, I update the test as follows:
it('calls the toggleEmailPasswordModal method', () => {
const wrapper = shallow(<Login />);
const instance = wrapper.instance();
jest.spyOn(instance, 'toggleEmailPasswordModal');
wrapper.find(Button).first().props().onPress();
// CHANGES START HERE
// wrapper.find(Button).first().simulate('press');
// expect(instance.toggleEmailPasswordModal).toHaveBeenCalled();
expect(instance.state.emailPasswordModalVisible).toBe(true);
});
Guess what? The test passes properly. So CLEARLY calling the wrapper.find...
functions twice truly is calling the toggleEmailPasswordModal
method twice. So, why does it fail to detect it if I don't call twice? Why does it improperly believe the method has only been called once?
Solution
I have an answer finally. According to Jest spyOn function called, I need to do instance.forceUpdate()
to attach the spy to the component.
it('calls the toggleEmailPasswordModal method', () => {
const wrapper = shallow(<Login />);
const instance = wrapper.instance();
const spy = jest.spyOn(instance, 'toggleEmailPasswordModal');
// This is added per https://stackoverflow.com/questions/44769404/jest-spyon-function-called/44778519#44778519
instance.forceUpdate();
wrapper.find(Button).first().props().onPress();
expect(spy).toHaveBeenCalledTimes(1);
expect(instance.state.emailPasswordModalVisible).toBe(true);
});
Now, the test passes!
Answered By - Justin Noel
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.