How to assert a function is called from within another function?

32,990

As I mentioned in the comment, You can pass a mocked function as prop whose implementation will contain a call to your sendEventToParentWindow function. i.e. You'll need to create two mocked function.

  1. sendEventToParentWindow mock function.
  2. onChangeImage mock function with implementation, where implementation will only contain call to your sendEventToParentWindow mock function.

So the test will look something like this,

describe('<Gallery />', () => {
  it('Expect sendMessageToParentWindow to be called on image change', () => {
    const sendEventToParentWindowMock = jest.fn();
    const onChangeImageMock = jest.fn(() => {
         sendEventToParentWindowMock();
    });

    const gallery = shallow(<Gallery images={imagesMockData} onChange={onChangeImageMock} />); // Passing the mocked onChangeImage as prop
    gallery.find('input#image-1').simulate('change');

    expect(sendEventToParentWindowMock).toBeCalled();
  });
}

Hope it helps :)

Share:
32,990
blueyodeler
Author by

blueyodeler

Dad, husband, software developer, banjo/guitar picker, and occasional yodeler.

Updated on August 12, 2020

Comments

  • blueyodeler
    blueyodeler over 3 years

    I have a component in React with an onChange event. In the code below, I need to assert that the correct method is called when

    this.props.onChangeImage()
    

    is invoked in the Gallery component.

    export class Form extends React.PureComponent {
    
      componentDidMount = () => {
        this.props.getUser();
        this.props.getImages();
        this.props.getBoards();
      }
    
      render() {
        if (this.props.pin === null) {
          let boards = [];
          boards = this.props.boards;
          boards = boards.data.map(
            (item) => <MenuItem key={item.id.toString()} value={item.name} primaryText={item.name} />
          );
          return (
            <div>
              <Helmet
                title="Form"
                meta={[
                  { name: 'description', content: 'Description of Form' },
                ]}
              />
              <Gallery images={this.props.images} onChange={this.props.onChangeImage} />
            </div>
          );
        }
        return (<div className="spinner-container"><CircularProgress /></div>);
      }
    }
    

    Below, in the onChangeImage method, I am trying to assert that the sendEventToParentWindow method is called.

    function mapDispatchToProps(dispatch) {
      return {
    
        onChangeImage: (event) => {
          dispatch(createPinImage(event.target.value));
          sendEventToParentWindow({
            action: 'change-image',
            description: 'Change image',
          });
        },
      };
    }
    
    function sendEventToParentWindow(message) {
      window.postMessage(message, window.location.href);
    }
    
    export default connect(mapStateToProps, mapDispatchToProps)(Form);
    

    I've looked at a number of answers here, and while this one seemed closest, it's not quite getting me there: Jest - mocking a function call

    EDIT: Here is my test which I believe is wrong because it's assigning the mocked function to be called directly onChange when it really should be calling the function that in turn calls the mock. I need somehow to invoke the onImageChange function and then verify that my spy was called.

    import Gallery from '../index';
    import * as formIndex from '../../../containers/Form';
    
    describe('<Gallery />', () => {
      it('Expect sendMessageToParentWindow to be called on image change', () => {
        const sendEventToParentWindowMock = jest.spyOn(formIndex, 'sendEventToParentWindow');
        const gallery = shallow(<Gallery images={imagesMockData} onChange={sendEventToParentWindowMock} />);
        gallery.find('input#image-1').simulate('change');
    
        expect(sendEventToParentWindowMock).toBeCalled();
      });
    }
    
  • blueyodeler
    blueyodeler almost 7 years
    That's the piece of understanding I was missing! I'll give this a try on Monday when I get back to the office, but thanks again for your patience and example code! It really helps to be able to see a solid example.
  • blueyodeler
    blueyodeler almost 7 years
    That was the missing bit! Thanks again. I've accepted the answer.