10

I have the following typescript class which I want to test in Jest.

//MyClass.ts
import { foo } from './somewhere/FooFactory';
export class MyClass {
  private _state : number;
  constructor( arg : string ) {
    this._state = foo( arg );
  }

  public getState() : string {
    return this._state;
  }
}

This is my test:

//MyClass.spec.ts
import { MyClass } from './MyClass';
describe( 'test MyClass', () => {
  test( 'construct' => {
    const c = new MyClass( 'test' );
    expect( c ).toBeDefined();
    expect( c.getState() ).toEqual( 'TEST' );
  } );
} );

How do I mock the foo function used inside MyClass so that this test passes?

skyboyer
  • 19,620
  • 7
  • 50
  • 62
Marek Krzeminski
  • 1,066
  • 3
  • 13
  • 34
  • looks like the same as https://stackoverflow.com/questions/40465047/how-can-i-mock-an-es6-module-import-using-jest – Alesj Nov 11 '18 at 12:49

1 Answers1

37

There are a few different ways to approach it.


You can mock only foo using jest.spyOn and something like mockImplementation:

import { MyClass } from './MyClass';
import * as FooFactory from './somewhere/FooFactory';

describe('test MyClass', () => {
  test('construct', () => {
    const mock = jest.spyOn(FooFactory, 'foo');  // spy on foo
    mock.mockImplementation((arg: string) => 'TEST');  // replace implementation

    const c = new MyClass('test');
    expect(c).toBeDefined();
    expect(c.getState()).toEqual('TEST');  // SUCCESS

    mock.mockRestore();  // restore original implementation
  });
});

Similarly, you can auto-mock FooFactory with jest.mock, then provide an implementation for foo:

import { MyClass } from './MyClass';
import * as FooFactory from './somewhere/FooFactory';

jest.mock('./somewhere/FooFactory');  // auto-mock FooFactory

describe('test MyClass', () => {
  test('construct', () => {
    const mockFooFactory = FooFactory as jest.Mocked<typeof FooFactory>;  // get correct type for mocked FooFactory
    mockFooFactory.foo.mockImplementation(() => 'TEST');  // provide implementation for foo

    const c = new MyClass('test');
    expect(c).toBeDefined();
    expect(c.getState()).toEqual('TEST');  // SUCCESS
  });
});

You can also mock FooFactory using a module factory passed to jest.mock:

import { MyClass } from './MyClass';

jest.mock('./somewhere/FooFactory', () => ({
  foo: () => 'TEST'
}));

describe('test MyClass', () => {
  test('construct', () => {
    const c = new MyClass('test');
    expect(c).toBeDefined();
    expect(c.getState()).toEqual('TEST');  // SUCCESS
  });
});

And finally, if you plan to use the same mock across multiple test files you can mock the user module by creating a mock at ./somewhere/__mocks__/FooFactory.ts:

export function foo(arg: string) {
  return 'TEST';
}

...then call jest.mock('./somewhere/FooFactory'); to use the mock in the test:

import { MyClass } from './MyClass';

jest.mock('./somewhere/FooFactory');  // use the mock

describe('test MyClass', () => {
  test('construct', () => {
    const c = new MyClass('test');
    expect(c).toBeDefined();
    expect(c.getState()).toEqual('TEST');  // SUCCESS
  });
});
Brian Adams
  • 36,719
  • 6
  • 95
  • 103