- 
          
- 
                Notifications
    You must be signed in to change notification settings 
- Fork 6.6k
Closed as not planned
Labels
Description
🚀 Feature Proposal
Add a utility jest.mockClass() for mocking a class.
Motivation
When testing classes in Jest, creating mocks is tedious and error-prone. You have to manually mock each method, which isn't type-safe and does not reflect source changes.
Pitch
Add a jest.mockClass() function that automatically creates a mock instance with all methods as jest.fn(). It should walk the prototype chain to include inherited methods.
Example
class SomeService {
  constructor(private logger: Logger) {}
  
  f() {
    this.logger.info("calling f");
  }
}
let someService: SomeService;
let logger: jest.Mocked<Logger>;
beforeEach(() => {
  // Current way (tedious)
  // This can expands to a hundred lines for a large test
  logger = {
    info: jest.fn(),
    warn: jest.fn(),
    error: jest.fn(),
  } as unknown as jest.Mocked<Logger>;
  // Proposed way (simple)
  logger = jest.mockClass(Logger);
  someService = new SomeService(logger);
});
test("should call logger.info", () => {
  someService.f();
  expect(logger.info).toHaveBeenCalled();
});Reference implementation
/** create a mock instance with each method being jest.fn() */
export function mockClass<T>(ctr: new (...args: never[]) => T): jest.Mocked<T> {
  const instance: Record<string, jest.Mock> = {};
  let currentProto = ctr.prototype;
  while (currentProto && currentProto !== Object.prototype) {
    for (const key of Object.getOwnPropertyNames(currentProto)) {
      if (key === 'constructor') {
        continue;
      }
      // Avoid overriding a method from a child class with one from a parent.
      if (Object.prototype.hasOwnProperty.call(instance, key)) {
        continue;
      }
      const prop = (currentProto as Record<string, unknown>)[key];
      if (typeof prop === 'function') {
        instance[key] = jest.fn();
      }
    }
    currentProto = Object.getPrototypeOf(currentProto);
  }
  return instance as jest.Mocked<T>;
}