0
votes

I have the following react-native test code.

import { shallow } from 'enzyme';
import React from 'react';

import {
  BorderlessButton,
  InputBox,
  ProgressBar,
} from 'components';

import Name from '../name.component';

describe('Name component', () => {
  let wrapper: any;

  const mockOnPress = jest.fn();
  const mockSaveStep = jest.fn();

  const mockProps: any = {
    errors: null,
    values: [{ givenName: 'givenName', familyName: 'familyName' }],
  };

  beforeEach(() => {
    wrapper = shallow(<Name signUpForm={mockProps} saveStep={mockSaveStep} />);
  });

  it('should render Name component', () => {
    expect(wrapper).toMatchSnapshot();
  });

  it('should render 2 <InputBox />', () => {
    expect(wrapper.find(InputBox)).toHaveLength(2);
  });

  it('should render a <ProgressBar />', () => {
    expect(wrapper.find(ProgressBar)).toHaveLength(1);
  });

  it('should render a <BorderlessButton /> with the text NEXT', () => {
    expect(wrapper.find(BorderlessButton)).toHaveLength(1);
    expect(wrapper.find(BorderlessButton).props().text).toEqual('NEXT');
  });

  it('should press the NEXT button', () => {
    wrapper.find(BorderlessButton).simulate('click');
    expect(mockOnPress).toHaveBeenCalled();
  });
});

But the last test doesn't work properly. How can I simulate a this button click? This gives me an error saying

expect(jest.fn()).toHaveBeenCalled(). Expected mock function to have been called, but it was not called.

This is the component.

class NameComponent extends Component {
  componentDidMount() {
    const { saveStep } = this.props;
    saveStep(1, 'Name');
  }

  disableButton = () => {
    const {
      signUpForm: {
        errors, values,
      },
    } = this.props;

    if (errors && values && errors.givenName && errors.familyName) {
      if (errors.givenName.length > 0 || values.givenName === '') return true;
      if (errors.familyName.length > 0 || values.familyName === '') return true;
    }
  }

  handleNext = () => {
    navigationService.navigate('PreferredName');
  }

  resetForm = () => {
    const { resetForm } = this.props;
    resetForm(SIGN_UP_FORM);
    navigationService.navigate('LoginMain');
  }

  render() {
    const { name, required } = ValidationTypes;
    const { step } = this.props;

    return (
      <SafeAreaView style={{ flex: 1 }}>
        <KeyboardAvoidingView style={{ flex: 1 }}
          behavior={Platform.OS === 'ios' ? 'padding' : null}
          enabled>
          <ScreenContainer
            navType={ScreenContainer.Types.LEVEL_THREE}
            levelThreeOnPress={this.resetForm}>

            <View style={styles.container}>
              <View style={{ flex: 1 }}>
                <SinglifeText
                  type={SinglifeText.Types.H1}
                  label='Let’s start with your legal name'
                  style={styles.textLabel}
                />

                <View style={styles.names}>
                  <InputBox
                    name='givenName'
                    form={SIGN_UP_FORM}
                    maxLength={22}
                    placeholder='Given name'
                    containerStyle={styles.givenNameContainer}
                    inputContainerStyle={styles.inputContainer}
                    errorStyles={styles.inputError}
                    keyboardType={KeyBoardTypes.default}
                    validations={[required, name]}
                  />
                  <InputBox
                    name='familyName'
                    form={SIGN_UP_FORM}
                    maxLength={22}
                    placeholder='Family name'
                    inputContainerStyle={styles.inputContainer}
                    errorStyles={styles.inputError}
                    keyboardType={KeyBoardTypes.default}
                    validations={[required, name]}
                  />
                </View>

                <SinglifeText
                  type={SinglifeText.Types.HINT}
                  label='Please use the same name you use with your bank'
                  style={styles.hint}
                />
              </View>
            </View>
          </ScreenContainer>

          <ProgressBar presentage={(step / MANUAL_SIGNUP_STEP_COUNT) * 100} />

          <View style={styles.bottomButtonContainer}>
            <BorderlessButton
              text='NEXT'
              disabled={this.disableButton()}
              onPress={this.handleNext}
            />
          </View>

        </KeyboardAvoidingView>
      </SafeAreaView>
    );
  }
}

How can I solve this??

1
When you say 'doesn't work properly' what do you mean? What is the error?rrd
The way I will test this is that you have to also mock the function that will be triggered when the button is clicked and change to expect(function).toHaveBeencalled();Ange
Can you add the whole test code? This will help us to know where the actually problem really is.raman
Updated the post with the full test code.Shashika
Whats the actual onclick fucntion are you calling? I guess mockpress is just a mock name. Can you post the component code as well. Just wanted to see which function are you calling on the onclick event.raman

1 Answers

0
votes

You create the function mockOnPress(), but mockOnPress() is never injected into the component.

In the component you wrote, NameComponent has a child BorderlessButton component, in which the line, onPress={this.handleNext} is hard-coded in. handleNext() is defined elsewhere as:

handleNext = () => {
    navigationService.navigate('PreferredName');
}

To test that the functionality of the button is working, I see two viable options. One is to use dependency injection. Instead of hard-coding the button to call navigationService.navigate('PreferredName'), you could have it execute code that is passed in as a prop. See the following as an example:

it('Button should handle simulated click', function (done) {
  wrappedButton = mount(<MyButton onClick={() => done()}>Click me!</BaseButton>)
  wrappedButton.find('button').simulate('click')
}

Note that you could take the principle provided in the above example and expand it to your example by passing in the functionality you want to occur onClick as a prop to your NameComponent.

Another option you have, is to test whether clicking the button causes the side effects you want to occur. As written, pressing the button should call, navigationService.navigate('PreferredName'). Is this the intended effect? If so, you can change your test to validate whether navigationService.navigate('PreferredName') was called somehow.