3.2 Partial Module Mocking
When testing application code it can be useful to mock only part of a module.
In order to do this, we should use jest.requireActual
.
Partial module mocking with jest.requireActual
We’ve seen how to mock modules using jest.mock
. One of the issues we might have with that is that jest.mock
either automatically stubs out
It’s possible to require/import and expose the real module while using jest.mock
.
jest.requireActual(moduleName)
Returns the actual module instead of a mock, bypassing all checks on whether the module should receive a mock implementation or not
The case where you would want to mock something partially is if you have a module that exposes both constants, pure functions and non-pure functions (that usually do I/O).
You’ll want to mock the operations that do I/O most of the time, the pure/business logic functions some of the time and the constants very seldom.
Here’s an example module that we might want to mock, src/03.02-notifications.js
. It contains some constants under OPERATIONS
, createEmailNotification
and createPushNotification
which create payloads in-memory, and sendNotification
which makes a network call.
const OPERATIONS = {
SEND_EMAIL: 'SEND_EMAIL',
SEND_PUSH_NOTIFICATION: 'SEND_PUSH_NOTIFICATION'
};
function createEmailNotification(to, subject, content) {
return {
type: OPERATIONS.SEND_EMAIL,
payload: {
to,
subject,
content
}
};
}
function createPushNotification(to, title, content) {
return {
type: OPERATIONS.SEND_PUSH_NOTIFICATION,
payload: {
to,
title,
content
}
};
}
async function sendNotification() {
// Send something to an API
}
module.exports = {
OPERATIONS,
createEmailNotification,
createPushNotification,
sendNotification
};
Here’s how we’re likely to want to mock it:
jest.mock('./03.02-notifications', () => ({
...jest.requireActual('./03.02-notifications'),
sendNotification: jest.fn(async () => {})
}));
In our test we are then able to access the real OPERATIONS
, createEmailNotification
and createPushNotification
.
jest.mock('./03.02-notifications', () => ({
...jest.requireActual('./03.02-notifications'),
sendNotification: jest.fn(async () => {})
}));
const {
OPERATIONS,
createEmailNotification,
createPushNotification
} = require('./03.02-notifications');
test('access tests', () => {
expect(OPERATIONS).toEqual({
SEND_EMAIL: 'SEND_EMAIL',
SEND_PUSH_NOTIFICATION: 'SEND_PUSH_NOTIFICATION'
});
expect(
createEmailNotification(
'[email protected]',
'new email notification',
'This is an email notification'
)
).toEqual({
type: 'SEND_EMAIL',
payload: {
to: '[email protected]',
subject: 'new email notification',
content: 'This is an email notification'
}
});
expect(
createPushNotification(
'[email protected]',
'new push notification',
'This is a push notification'
)
).toEqual({
type: 'SEND_PUSH_NOTIFICATION',
payload: {
to: '[email protected]',
title: 'new push notification',
content: 'This is a push notification'
}
});
});
This test passes as expected with the following output.
npx jest src/03.02-notifications.test.js
PASS src/03.02-notifications.test.js
✓ access tests (4ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
We’ve seen a real-life example of how to partially mock a module in order to maintain some of its real values.
Next we’ll see how to stub out module internals by exposing a module object reference.