14

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();
});
Community
  • 1
  • 1
Leon Gaban
  • 36,509
  • 115
  • 332
  • 529
  • 1
    Can you post a snippet showing how you're binding the `yearOnChange` method to the instance? – shamsup Jul 08 '19 at 22:46
  • Are you performing a shallow or full mount? – James Jul 08 '19 at 22:47
  • @shamsup added! James, using shallow, there are problems with mount and redux-forms that I've been running into :( – Leon Gaban Jul 09 '19 at 02:11
  • Does this answer your question? [Jest spyOn function called](https://stackoverflow.com/questions/44769404/jest-spyon-function-called) – Liam Nov 30 '21 at 11:05

2 Answers2

6

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();
});
Liam
  • 27,717
  • 28
  • 128
  • 190
Leon Gaban
  • 36,509
  • 115
  • 332
  • 529
  • 3
    Just a note on your test code, usually when you spy on something, you shouldn't call it yourself like you did here `wrapper.instance().yearOnChange(event);` – Ion Jul 09 '19 at 15:26
2

You are spying and calling yearOnChange manually.

Try not calling wrapper.instance().yearOnChange(event);

Call the wrapper.instance().onChange event, or like you did, run the simulate('change') will be enough.

You could also try VehiclePicker.prototype.yearOnChange = jest.fn()

expect(VehiclePicker.prototype.yearOnChange).toBeCalled();

Ion
  • 1,262
  • 12
  • 19