Mocking with jest.requireActual
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!