Skip to content

Mock package in monorepo #3265

@fooddilsn

Description

@fooddilsn

Describe the bug

I am facing an issue mocking a package in a monorepo.

When I use vi.mock('whatever') without specifying an inline factory, I would expect vitest to look for the mock in the app's __mocks__ folder in the monorepo, but if I mock a package of the monorepo, that does not happen.
I have added some logs here and here to gather more information.

When I mock a node module (e.g. undici), the output is as follows:

resolvePath {
  rawId: 'undici',
  id: '[...]/monorepo-vi-mock-resolver/node_modules/.pnpm/undici@5.22.0/node_modules/undici/index.js',
  fsPath: '[...]/monorepo-vi-mock-resolver/node_modules/.pnpm/undici@5.22.0/node_modules/undici/index.js'
}
const external = !isAbsolute(fsPath) || fsPath.includes("/node_modules/") ? rawId : null
{
  'isAbsolute(fsPath)': true,
  'fsPath.includes("/node_modules/")': true,
  external: 'undici'
}

resolveMockPath {
  mockPath: '[...]/monorepo-vi-mock-resolver/node_modules/.pnpm/undici@5.22.0/node_modules/undici/index.js',
  external: 'undici',
  path: 'undici',
  'isNodeBuiltin(mockPath)': false,
  'existsSync(mockPath)': true
}
=> enter the if (external || isNodeBuiltin(mockPath) || !existsSync(mockPath))
{
  mockDirname: '.',
  mockFolder: '[...]/monorepo-vi-mock-resolver/apps/foo/__mocks__',
  'existsSync(mockFolder)': true
}
__mocks__ content { files: [ 'sample.ts', 'undici.ts' ], baseOriginal: 'undici' }
return [...]/monorepo-vi-mock-resolver/apps/foo/__mocks__/undici.ts

If I mock a monorepo package instead, the output looks like this:

resolvePath {
  rawId: 'sample',
  id: '[...]/monorepo-vi-mock-resolver/packages/sample/dist/index.js',
  fsPath: '[...]/monorepo-vi-mock-resolver/packages/sample/dist/index.js'
}
const external = !isAbsolute(fsPath) || fsPath.includes("/node_modules/") ? rawId : null
{
  'isAbsolute(fsPath)': true,
  'fsPath.includes("/node_modules/")': false,
  external: null
}

resolveMockPath {
  mockPath: '[...]/monorepo-vi-mock-resolver/packages/sample/dist/index.js',
  external: null,
  path: '[...]/monorepo-vi-mock-resolver/packages/sample/dist/index.js',
  'isNodeBuiltin(mockPath)': false,
  'existsSync(mockPath)': true
}
=> skip the if (external || isNodeBuiltin(mockPath) || !existsSync(mockPath))
{
  dir: '[...]/monorepo-vi-mock-resolver/packages/sample/dist',
  baseId: 'index.js',
  fullPath: '[...]/monorepo-vi-mock-resolver/packages/sample/dist/__mocks__/index.js'
}
return null // because the mock file (fullPath) does not exist

And the final map is:

mockMap {
  '[...]/monorepo-vi-mock-resolver/apps/foo/src/index.test.ts' => {
    '[...]/monorepo-vi-mock-resolver/node_modules/.pnpm/undici@5.22.0/node_modules/undici/index.js': '[...]/monorepo-vi-mock-resolver/apps/foo/__mocks__/undici.ts',
    '[...]/monorepo-vi-mock-resolver/packages/sample/dist/index.js': null
  }
}

In the second case, since the fsPath is an absolute path and does not contain /node_modules/, the dependency is not marked as "external" and the mock file is searched for in the dist/__mocks__ folder of the package itself.

Is this an intended behaviour?

Reproduction

https://github.com/fooddilsn/monorepo-vi-mock-resolver

System Info

System:
  OS: macOS 13.2.1
  CPU: (10) arm64 Apple M1 Max
  Memory: 72.38 MB / 32.00 GB
  Shell: 5.8.1 - /bin/zsh
Binaries:
  Node: 16.17.1 - ~/.nvm/versions/node/v16.17.1/bin/node
  Yarn: 1.22.19 - ~/.nvm/versions/node/v16.17.1/bin/yarn
  npm: 8.15.0 - ~/.nvm/versions/node/v16.17.1/bin/npm
Browsers:
  Chrome: 112.0.5615.137
  Safari: 16.3

Used Package Manager

pnpm

Validations

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions