Skip to content

Expect mock factories to have a return type compatible with the original module #6089

@acidoxee

Description

@acidoxee

Clear and concise description of the problem

Currently, when using mock factories, the expected return type is any. This makes it possible to return broken mocks that do not comply with the original module's signature.

// @filename: src/basic.ts
export const squared = (n: number) => n * n

// @filename: test/mocks.test.ts
import { expect, test, vi } from 'vitest';

test('Mocked module with broken contract', async () => {
  vi.doMock(import('../src/basic.js'), () => ({
    // When not manually typing the result, we can return a broken mock from the factory, as its expected return type is `any`
    sqrd: () => 1,
  }));

  // This throws the following error: Error: [vitest] No "squared" export is defined on the "../src/basic.js" mock. Did you forget to return it from "vi.mock"?
  const { squared } = await import('../src/basic.js');
  expect(squared(2)).toBe(1);
});

Suggested solution

It would be great if the mock factory's return type was expected to be the same as the original module's, instead of using any.

Alternative

Meanwhile, we've got hundreds of return type overrides in our codebase for each mock with satisfies Awaited<ReturnType<typeof importOriginal>> to ensure the mock's type is correct, but this is tedious and error-prone.

// @filename: src/basic.ts
export const squared = (n: number) => n * n

// @filename: test/mocks.test.ts
import { expect, test, vi } from 'vitest';

test('Mocked module', async () => {
  vi.doMock(
    import('../src/basic.js'),
    (importOriginal) =>
      // This ensures the value returned from the factory is compatible with the original module.
      // I would like for the whole `satisfies` statement to not be necessary
      ({ squared: () => 1 } satisfies Awaited<
        ReturnType<typeof importOriginal>
      >)
  );

  const { squared } = await import('../src/basic.js');
  expect(squared(2)).toBe(1);
});

Additional context

Here's a reproduction: https://stackblitz.com/edit/vitest-dev-vitest-fkhseh?file=test%2Fmocks.test.ts

Validations

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions