Jest Mock with Real Modules

E.Y.
2 min readJun 30, 2020

--

Mocking with jest.requireActual

Photo by Alice Pasqual on Unsplash

Not long ago when I reviewed PR, I found an interesting use case with Jest mock, and would like to share with you.

So most of the time when we used a 3rd party module in the code, we can just mock the whole module. But there are times when we need to use parts of the real implementation of the module, this is when jest.requireActual comes handy.

Consider a module like below:

//EventTracker.jsexport const trackEventName = (
eventType,
eventTitle
) => `Track Event - ${eventType} - ${eventTitle}`;


export function trackEvent(eventName){
//do something not important
}

And then we have a function that we want to be tested:

//ClickBoxTracking.js
import React from 'react';
import { trackEventName, trackEvent } from '../../EventTracker';
import {ClickBox} from "../ClickBox"
export const ClickBoxWithTracking = ({
trackingTitle,
...props
}) => {
const tracking = () => {
trackEvent(trackEventName('ClickBox', trackingTitle));
};

return (<ClickBox tracking={tracking} {...props} />);
};

Finally this is how we test it :

import React from 'react';
import { mount, ReactWrapper } from 'enzyme';
import { ClickBoxWithTracking } from './ClickBoxTracking';
import { trackEvent } from '../../EventTracker';

jest.mock('../../EventTracker', () => {
const actualTracker = jest.requireActual('../../EventTracker');
return {
...actualTracker,
trackEvent: jest.fn(),
};

});

describe('ClickBoxWithTracking', () => {
const MockTrackEvent = trackEvent;
let wrapper;
beforeEach(() => {
wrapper = mount(<ClickBoxWithTracking trackingTitle="Current tick option">Current tick option...</ClickBoxWithTracking>);
});

it('should call trackEvent when the clickBox is ticked', () => {
//do something to simulate the click
expect(MockTrackEvent).toHaveBeenCalledWith('ClickBox - Current tick option');
});

});

Notice when we do the following, we are returning { trackEventName, trackEvent } and then trackEvent: jest.fn() overwrite the trackeEvent returned from the module.

jest.mock('../../EventTracker', () => {
const actualTracker = jest.requireActual('../../EventTracker');
return {
...actualTracker,
trackEvent: jest.fn(),
};

});

The reason we want to do this is because when we do the mounting:

mount(<ClickBoxWithTracking trackingTitle="Current tick option">Current tick option...</ClickBoxWithTracking>);

There is this method get triggered inside the component:

const tracking = () => {
trackEvent(trackEventName('ClickBox', trackingTitle));
};

We still want to call trackEventName but just want to mock trackEvent . So we require the real module thereby requiring the real trackEventName and overwrite the latter with the mocked trackEvent .

Of course you can mock trackEventName as well. But in this test, we don’t want to add another layer of complexity, and would like to actually test if the trackEventName can be passed in to trackEvent and rendered by ClickBoxWithTracking .

You can even more explicitly requiring the real trackEventName like this after you require the module.

jest.mock('../../EventTracker', () => {
const actualTracker = jest.requireActual('../../EventTracker');
return {
...actualTracker,
trackEvent: jest.fn(),
};
});
const { trackEventName } = require('../../EventTracker');
//do something with trackingEventName

You can learn more about jest.requireActual in the documentation.

Happy reading!

--

--

No responses yet