Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(vm): improve error when module is not found #5053

Merged
merged 5 commits into from
Feb 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion packages/vitest/src/runtime/external-executor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import vm from 'node:vm'
import { fileURLToPath, pathToFileURL } from 'node:url'
import { dirname } from 'node:path'
import { statSync } from 'node:fs'
import { existsSync, statSync } from 'node:fs'
import { extname, join, normalize } from 'pathe'
import { getCachedData, isNodeBuiltin, setCacheData } from 'vite-node/utils'
import type { RuntimeRPC } from '../types/rpc'
Expand Down Expand Up @@ -188,6 +188,14 @@ export class ExternalModulesExecutor {
private async createModule(identifier: string): Promise<VMModule> {
const { type, url, path } = this.getModuleInformation(identifier)

// create ERR_MODULE_NOT_FOUND on our own since latest NodeJS's import.meta.resolve doesn't throw on non-existing namespace or path
// https://github.com/nodejs/node/pull/49038
if ((type === 'module' || type === 'commonjs') && !existsSync(path)) {
const error = new Error(`Cannot find module '${path}'`)
;(error as any).code = 'ERR_MODULE_NOT_FOUND'
throw error
}

switch (type) {
case 'data':
return this.esm.createDataModule(identifier)
Expand Down
15 changes: 15 additions & 0 deletions test/vm-threads/src/external/not-found.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
export async function importPackage() {
await import('@vitest/non-existing-package')
}

export async function importPath() {
await import('./non-existing-path')
}

export async function importBuiltin() {
await import('node:non-existing-builtin')
}

export async function importNamespace() {
await import('non-existing-namespace:xyz')
}
36 changes: 36 additions & 0 deletions test/vm-threads/test/not-found.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { expect, it } from 'vitest'

// @ts-expect-error untyped
import * as notFound from '../src/external/not-found.js'

it('path', async () => {
await expect(() => notFound.importPath()).rejects.toMatchObject({
code: 'ERR_MODULE_NOT_FOUND',
message: expect.stringMatching(/Cannot find module '.*?non-existing-path'/),
})
})

// NodeJs's import.meta.resolve throws ERR_MODULE_NOT_FOUND error only this case.
// For other cases, similar errors are fabricated by Vitest to mimic NodeJs's behavior.
it('package', async () => {
await expect(() => notFound.importPackage()).rejects.toMatchObject({
code: 'ERR_MODULE_NOT_FOUND',
message: expect.stringContaining('Cannot find package \'@vitest/non-existing-package\''),
})
})

it('builtin', async () => {
await expect(() => notFound.importBuiltin()).rejects.toMatchObject({
code: 'ERR_MODULE_NOT_FOUND',
message: 'Cannot find module \'node:non-existing-builtin\'',
})
})

// this test fails before node 20.3.0 since it throws a different error (cf. https://github.com/nodejs/node/pull/47824)
// > Only URLs with a scheme in: file and data are supported by the default ESM loader. Received protocol 'non-existing-namespace:'
it('namespace', async () => {
await expect(() => notFound.importNamespace()).rejects.toMatchObject({
code: 'ERR_MODULE_NOT_FOUND',
message: 'Cannot find module \'non-existing-namespace:xyz\'',
})
})
Loading