Jest and Typescript: the recommended approach to override the default mock implementation

Viewed 1150

I'm using Jest with Typescript and I want to override the default mock implementation in some tests.

Suppose I have the following Foo class:

// foo.ts
export class Foo {
    do(param?: string): string {
        return param ?? 'default';
    }
}

And its related tests:

// foo.spec.ts
import {Foo} from './foo';
import {mocked} from "ts-jest/utils";
jest.mock('./foo', () => ({
    Foo: jest.fn(() => {
        return {
            do: jest.fn().mockReturnValue("bar"),
        };
    })
}));

describe('foo tests', function () {
    
    // Test 1
    it('test default mock', function () {
        const foo = new Foo();
        expect(foo.do()).toEqual('bar');
    });

    // Test 2
    it('test override default mock - ok 1', function () {
        const mockedFoo = mocked(Foo, true);
        expect(mockedFoo).toBeTruthy();

        mockedFoo.mockImplementationOnce(() => new class extends Foo {
            do = jest.fn().mockImplementationOnce(() => "override ok");
        });

        const foo = new Foo();
        expect(foo.do()).toEqual('override ok');
    });

    // Test 3
    it('test override default mock - ok 2', function () {
        const mockedFoo = mocked(Foo, true);
        expect(mockedFoo).toBeTruthy();

        mockedFoo.mockImplementationOnce(jest.fn<Foo, []>(
            () => {
                // eslint-disable-next-line @typescript-eslint/ban-ts-comment
                // @ts-ignore
                const self = this as Foo;
                self.do = jest.fn().mockImplementationOnce(() => "override ok 2");
                return self;
            }
        ));

        const foo = new Foo();
        expect(foo.do()).toEqual('override ok 2');
    });

    // Test 4
    it('test override default mock - not working', function () {
        const mockedFoo = mocked(Foo, true);
        expect(mockedFoo).toBeTruthy();

        mockedFoo.prototype.do = jest.fn().mockImplementationOnce(() => "override not working");

        const foo = new Foo();
        expect(foo.do()).toEqual('bar');
    });
});

As shown, the following tests work as expected:

  • 'test default mock' (Test 1)
  • 'test override default mock - ok 1' (Test 2)
  • 'test override default mock - ok 2' (Test 3)

The test 'test override default mock - not working' (Test 4) doesn't work as expected (the default mock is not overridden).

Therefore, my questions are:

  1. why Test 4 does not override the default mock implementation?
  2. Is Test 2's implementation the recommended way of doing it (anonymous class) versus Test 3's approach (ignore typescript checks)?
  3. Is there a "better" way to override the default mock implementation?
0 Answers
Related