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

Jest documentation

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.

Jump to table of contents