Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to mock a function in Jest

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?

like image 870
Marek Krzeminski Avatar asked Nov 06 '18 14:11

Marek Krzeminski


People also ask

How do I mock a function in Jest?

There are two ways to mock functions: Either by creating a mock function to use in test code, or writing a manual mock to override a module dependency.

How do you mock a function in react Jest?

Let's refactor the test to use this approach: test("Should render character name", async () => { const mock = jest. spyOn(data, "getCharacter"). mockResolvedValue("Bob"); render(<Hello id={1} />); expect(await screen.

How does Jest fn () work?

fn method allows us to create a new mock function directly. If you are mocking an object method, you can use jest. spyOn . And if you want to mock a whole module, you can use jest.

How do you mock data in Jest?

In Jest, Node. js modules are automatically mocked in your tests when you place the mock files in a __mocks__ folder that's next to the node_modules folder. For example, if you a file called __mock__/fs. js , then every time the fs module is called in your test, Jest will automatically use the mocks.


1 Answers

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
  });
});
like image 93
Brian Adams Avatar answered Oct 25 '22 22:10

Brian Adams