Search code examples
javascriptreactjsjestjsspy

Jest mocked spy function, not being called in test


The component:

The Input component with the onChange handler:

<Field
    component={FormattedTextInput}
    className={colMd113}
    name={NAMES.VEHICLE_YEAR}
    label={constants.VEHICLE_YEAR}
    validate={[required, validator.validateYearOfVehicle]}
    formatting="9999"
    onChange={this.yearOnChange}
/>

The method:

constructor(props) {
    super(props);

    this.yearOnChange = this.yearOnChange.bind(this)
}

yearOnChange(event) {
    if (event.target && event.target.value) {
        const value = event.target.value;
        this.setState({
            year: value
        });
    }
}

The Test

it('yearOnChange method is called', function() {
    const spy = jest.spyOn(wrapper.instance(), 'yearOnChange');
    wrapper.update();
    // const instance = wrapper.instance();
    // console.log('instance', instance);
    wrapper.simulate('change', {
        target: {
            name: 'vehicleYear',
            value: '1999'
        }
    });
    expect(spy).toHaveBeenCalled();
});

The Error

Vehicle Picker Component › yearOnChange method is called

   expect(jest.fn()).toBeCalled()

   Expected mock function to have been called, but it was not called.

     50 |         console.log(wrapper.instance())
     51 |
   > 52 |         expect(spy).toBeCalled();
        |                     ^
     53 |     });

This is what we see when I log the wrapper.instance()

VehiclePicker {
       props: {},
       context: {},
       refs: {},
       updater:
        Updater {
          _renderer:
           ReactShallowRenderer {
             _context: {},
             _element: [Object],
             _instance: [Circular],
             _newState: null,
             _rendered: [Object],
             _rendering: false,
             _forcedUpdate: false,
             _updater: [Circular],
             _dispatcher: [Object],
             _workInProgressHook: null,
             _firstWorkInProgressHook: null,
             _isReRender: false,
             _didScheduleRenderPhaseUpdate: false,
             _renderPhaseUpdates: null,
             _numberOfReRenders: 0 },
          _callbacks: [] },
       state:
        { year: '',
          make: '',
          makeArray: [],
          model: '',
          modelArray: [],
          token: '' },
       yearOnChange: [Function: bound yearOnChange],
       makeOnChange: [Function: bound makeOnChange],
       setState: [Function] }

UPDATE

With the following code, the expect(result).toEqual('1999') test works! But still the expect(spy).toHaveBeenCalled() does not :( How is it that when I instantiate the method yearOnChange and actually change the state in the component, that the spy still isn't detected to have been called?

it('yearOnChange method is called', function() {
   const spy = jest.spyOn(VehiclePicker.prototype, 'yearOnChange');
   wrapper.instance().forceUpdate();

   const event = {
       target: {
           value: '1999'
       }
   };

   wrapper.instance().yearOnChange(event);
   wrapper.simulate('change', event);

   const result = wrapper.state('year');
   console.log('result', result); // result = 1999
   expect(result).toEqual('1999');
   expect(spy).toHaveBeenCalled();
});

Solution

  • Found great help from the answer here: Jest spyOn function called

    This was the important step I was missing:

    const instance = wrapper.instance()
    const spy = jest.spyOn(instance, 'yearOnChange')
    

    Updated working test with 2 working expects.

    it('yearOnChange method is called', function() {
        const instance = wrapper.instance();  // <-- Needed to do this here
        const spy = jest.spyOn(instance, 'yearOnChange');  // <-- Then use instance here
        wrapper.instance().forceUpdate();
        
        const event = {
            target: {
                value: '1999'
            }
        };
    
        wrapper.instance().yearOnChange(event);
        wrapper.simulate('change', event);
    
        const result = wrapper.state('year');
        console.log('result', result); // result = 1999
        expect(result).toEqual('1999');
        expect(spy).toHaveBeenCalled();
    });