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.