Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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();
});
like image 305
Leon Gaban Avatar asked Jul 08 '19 22:07

Leon Gaban


People also ask

How do you call a mocked function in Jest?

You can create a namespace that you export as the default object and call b using the namespace. This way, when you call jest. mock it will replace the b function on the namespace object. const f = require('./f'); jest.

How do you check if a function is called in Jest?

To check if a component's method is called, we can use the jest. spyOn method to check if it's called. We check if the onclick method is called if we get the p element and call it.

How do you use the Jest spy function?

To spy on an exported function in jest, you need to import all named exports and provide that object to the jest. spyOn function. That would look like this: import * as moduleApi from '@module/api'; // Somewhere in your test case or test suite jest.

Can I use Jest mock inside a test?

mock() doesn't work inside tests, only outside tests. Bookmark this question.


1 Answers

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();
});
like image 124
Leon Gaban Avatar answered Sep 20 '22 15:09

Leon Gaban