How to test a method which uses `instanceof ` on a mocked dependency

Viewed 3324

I have a typeguard which checks the instance of a dependency.

  private isObjectOfA(obj: A | B ): obj is A {
    return obj instanceof A;
  }

In the spec file, I have mocked the class A.

jest.mock('./my-package/a', () => {
  return {
    A: jest.fn().mockImplementation(() => {
      return {
        someMethod: jest.fn()
      };
    })
  };
});

import { A } from './my-package/a';

Now during testing, isObjectOfA always returns false ( because in tests the instance of obj is returned as 'Object' instead of 'A'. Maybe due to the mock ??). Is there anyway to overcome this issue? The code for the object creation looks like,

this.myObj = someCondition ? new A() : new B();
3 Answers

In order to pass instanceof check, prototype chain needs to be established, e.g. with Object.create:

jest.mock('./my-package/a', () => {
  const ActualA = jest.requireActual('./my-package/a');

  return {
    A: jest.fn().mockImplementation(() => {
      const a = Object.create(ActualA.prototype);
      return Object.assign(a, { someMethod: jest.fn() });
    })
  };
});

Class auto-mock will provide correct prototype chain for a mock as well.

The instanceof operator tests whether the prototype property of a constructor appears anywhere in the prototype chain of an object.

This means that you can change the prototype of your mock to be A.

As I didn't want to rely on anything but the mock, my solution based on @estus-flask's is as follows:

jest.mock('./module-to-mock', () => {
    const mockClass: jest.MockedClass<any> = jest.fn((...args) => {
        const instance = Object.create(mockClass.prototype);

        return Object.assign(instance, { args });
    })

    return {
        MyClass: mockClass
    }
});
Related