Hone logo
Hone
Problems

Jest Import Interception with jest-mock

Often in testing, you need to isolate the unit under test from its dependencies. This is crucial for ensuring that your tests focus solely on the logic of the unit itself and not on the behavior of its external collaborators. Jest provides powerful mocking capabilities to achieve this. This challenge will test your understanding of how to intercept and mock imported modules within your Jest tests using TypeScript.

Problem Description

Your task is to write a Jest test suite that demonstrates how to intercept and mock an imported module. Specifically, you will be testing a function that depends on another module. You need to ensure that when the function under test is executed, it calls the mocked version of the imported function, not the actual implementation.

What Needs to be Achieved:

You will create a scenario where a module (moduleA.ts) exports a function (functionA) which is imported and used by another module (moduleB.ts). You will then write a Jest test for a function within moduleB.ts (functionB) that intercepts the import of functionA from moduleA.ts and provides a mock implementation.

Key Requirements:

  1. Create two TypeScript modules: moduleA.ts and moduleB.ts.
    • moduleA.ts should export a simple function (e.g., getExternalData) that returns some data.
    • moduleB.ts should export a function (e.g., processData) that imports and uses getExternalData from moduleA.ts.
  2. Write a Jest test file (moduleB.test.ts) for functionB.
  3. Within the test file, use Jest's mocking capabilities to intercept the import of getExternalData from moduleA.ts.
  4. Provide a mock implementation for getExternalData that returns a controlled value.
  5. Assert that functionB correctly uses the mocked getExternalData and produces the expected output based on the mock.

Expected Behavior:

When functionB is called in the test, it should:

  • Call the mocked getExternalData function.
  • Use the return value from the mock to perform its logic.
  • Return a predictable result that depends on the mocked data.

Edge Cases:

  • Consider how the mock would behave if getExternalData was an asynchronous function (though for this challenge, a synchronous function is sufficient).
  • Ensure your mocking approach works even if moduleA has multiple exports.

Examples

Example 1:

moduleA.ts:

export function getExternalData(): string {
  console.log("This is the real getExternalData");
  return "real data";
}

moduleB.ts:

import { getExternalData } from "./moduleA";

export function processData(): string {
  const data = getExternalData();
  return `Processed: ${data.toUpperCase()}`;
}

moduleB.test.ts:

import { processData } from "./moduleB";
import * as moduleAMocks from "./moduleA"; // Import to access its exports for mocking

// Mocking the moduleA
jest.mock("./moduleA", () => ({
  getExternalData: jest.fn(),
}));

describe("processData", () => {
  it("should process data using the mocked getExternalData", () => {
    // Cast the mocked function for type safety and to access mock methods
    const mockedGetExternalData = moduleAMocks.getExternalData as jest.Mock;

    // Set the mock implementation
    mockedGetExternalData.mockReturnValue("mocked data");

    const result = processData();

    expect(mockedGetExternalData).toHaveBeenCalledTimes(1);
    expect(result).toBe("Processed: MOCKED DATA");
  });
});

Output of processData() in the test:

"Processed: MOCKED DATA"

Explanation: The test intercepts the import of ./moduleA. The jest.mock call replaces the actual moduleA with a mock object. We then specifically target getExternalData within that mock and use mockReturnValue to specify what it should return when called. The processData function, when executed, now calls this mocked version, leading to the "Processed: MOCKED DATA" output. The console.log("This is the real getExternalData") from the original moduleA should not appear in the test output.

Constraints

  • The solution must be implemented in TypeScript.
  • Jest must be used as the testing framework.
  • jest-mock features (e.g., jest.mock, .mockReturnValue, .toHaveBeenCalledTimes) should be utilized.
  • The mocked module (moduleA.ts) should be imported from a relative path.

Notes

  • Consider how you might structure your mock object if moduleA had multiple exports you needed to mock.
  • Think about the difference between mocking a whole module and mocking specific functions within a module. This challenge focuses on mocking specific exports.
  • Ensure your Jest configuration (e.g., jest.config.js or package.json) is set up correctly to handle TypeScript.
Loading editor...
typescript