Hone logo
Hone
Problems

Jest Module Mocking System Implementation

This challenge focuses on building a simplified module mocking system within Jest. Module mocking is a crucial technique for isolating units of code during testing, allowing you to control dependencies and verify interactions without relying on external resources or complex setups. You'll implement a basic mocking mechanism that intercepts module imports and allows you to replace them with mock implementations.

Problem Description

You are tasked with creating a function createMock that takes a module name (string) as input and returns an object. This object should have a mockImplementation method. When mockImplementation is called with a function, that function becomes the mock implementation for the specified module. When the module is imported and used in a test, the mock implementation should be executed instead of the original module. The mock should also track how many times it was called.

Key Requirements:

  • Module Interception: The createMock function should effectively "intercept" imports of the specified module name.
  • Mock Implementation: The mockImplementation method should allow setting a custom function to be executed when the module is imported and used.
  • Call Tracking: The mock implementation should internally track the number of times it has been called.
  • Jest Integration: The solution should be compatible with Jest's testing environment. You don't need to modify Jest itself, but your mock should work seamlessly within Jest tests.
  • No External Dependencies: The solution should only use built-in JavaScript/TypeScript features and Jest's core functionalities.

Expected Behavior:

  1. Calling createMock('myModule') returns an object with a mockImplementation method.
  2. Calling mockImplementation with a function sets the mock implementation for 'myModule'.
  3. In a Jest test, importing 'myModule' should result in the mock implementation being executed.
  4. The mock implementation should maintain a callCount property that reflects the number of times it was invoked.

Edge Cases to Consider:

  • What happens if createMock is called with an empty string or a non-string value? (Should throw an error or handle gracefully)
  • What happens if mockImplementation is called without a function? (Should throw an error or handle gracefully)
  • How to ensure the mock implementation is truly replacing the original module during import within the test environment? (This is the core challenge and requires understanding Jest's module resolution).

Examples

Example 1:

Input:
const mock = createMock('myModule');
mock.mockImplementation(() => {
  mock.callCount++;
  return 'Mocked Value';
});

// In a Jest test:
import { myModule } from './myModule'; // Assuming myModule.ts exists

expect(myModule()).toBe('Mocked Value');
expect(mock.callCount).toBe(1);

Output: mock.callCount will be 1 after the test runs. The test will pass because myModule() returns 'Mocked Value'. Explanation: The createMock function intercepts the import of 'myModule' and replaces it with the provided mock implementation. The mock implementation increments callCount and returns 'Mocked Value'.

Example 2:

Input:
const mock = createMock('myModule');
mock.mockImplementation(() => {
  mock.callCount++;
  return 'Mocked Value';
});

// In a Jest test:
import { myModule } from './myModule';

expect(myModule()).toBe('Mocked Value');
expect(mock.callCount).toBe(1);
myModule();
expect(mock.callCount).toBe(2);

Output: mock.callCount will be 2 after the second call to myModule(). Explanation: Each call to myModule() within the test executes the mock implementation, incrementing callCount.

Example 3: (Edge Case)

Input:
const mock = createMock(''); // Empty module name

// Expected Behavior:
// An error should be thrown or the function should handle the empty string gracefully.

Output: An error is thrown indicating an invalid module name. Explanation: The function should validate the module name and handle invalid inputs appropriately.

Constraints

  • Module Name: The module name (string) should not exceed 255 characters.
  • Mock Implementation: The function passed to mockImplementation can be any valid JavaScript function.
  • Error Handling: The createMock function should throw an error if the module name is invalid (e.g., empty string, non-string). mockImplementation should throw an error if no function is provided.
  • Performance: The mocking mechanism should not introduce significant performance overhead during test execution. Avoid complex data structures or operations that could slow down tests.

Notes

  • This is a simplified mocking system. Real-world mocking libraries offer more advanced features like argument matching, return value customization, and more.
  • Focus on the core functionality of intercepting module imports and providing a mock implementation.
  • Consider how Jest resolves modules and how you can influence that resolution to use your mock. You might need to leverage Jest's jest.mock function or similar mechanisms.
  • Think about how to ensure that the mock implementation is truly isolated from the original module.
Loading editor...
typescript