How to mock a typescript class with vitest
Asked Answered
A

1

8

I have a class A that imports class B from a different module and instantiates it. In my test for class A I'd like to stub/mock some of the methods of class B.

Some example code:

// Formatter.ts
export class Formatter {
   format(msg: string): string {
     return `--- [INFO] ${msg}\n`;
   }
}

// FormattedStore.ts
import {Formatter} from '@/Formatter'
export class FormattedStore implements Store {
   public store: string[];
   construct() {
     this.formatter = new Formatter();
     this.store = [];
   }

   write(msg: string): void {
      this.store.push(this.formatter.format(msg));
   }
}

// FormattedStore.spec.ts
import {FormattedStore} from '@/FormattedStore';
import {Formatter} from '@/Formatter'
import {vi, expect, test} from 'vitest';

vi.mock( '@/Formatter', () => ({ 
 Formatter: vi.fn() // What's the correct and type-safe way to mock this?
}));

test('it stores formatted message', () => {
   //  How do I mock the formatter here with the return 'formatted test message'?
   const store = new FormattedStore();
   store.write('TestMessage');

   expect(store.store[0]).toBe('formatted test message');
})

I know I could use constructor injection instead of mocking the module, but I have a case where that's not possible.

Attribution answered 30/3, 2023 at 17:33 Comment(0)
C
0

The package vitest-mock-extended solves this:

// FormattedStore.spec.ts
import {mock} from 'vitest-mock-extended';
import {FormattedStore} from '@/FormattedStore';
import {Formatter} from '@/Formatter'
import {vi, expect, test} from 'vitest';

vi.mock( '@/Formatter', () => ({ 
 Formatter: mock<Formatter>() // Mock class here
}));

test('it stores formatted message', () => {
   Formatter.format.mockReturnValue('formatted test message');  // provide return values here
   const store = new FormattedStore();
   store.write('TestMessage');

   expect(store.store[0]).toBe('formatted test message');
})
Caterer answered 27/2 at 20:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.