Skip to content
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/moduleRunner/cachedResolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@ const normalizedDistDir = normalize(distDir)
const relativeIds: Record<string, string> = {}
const externalizeMap = new Map<string, string>()

function getRelativeDistDir(root: string): string {
const normalizedRoot = normalize(root).replace(/\/+$/, '') || '/'
const rootPrefix = normalizedRoot === '/' ? normalizedRoot : `${normalizedRoot}/`
return normalizedDistDir.startsWith(rootPrefix)
? normalizedDistDir.slice(normalizedRoot.length)
: ''
}

// all Vitest imports always need to be externalized
export function getCachedVitestImport(
id: string,
Expand All @@ -24,7 +32,7 @@ export function getCachedVitestImport(
// always externalize Vitest because we import from there before running tests
// so we already have it cached by Node.js
const root = state().config.root
const relativeRoot = relativeIds[root] ?? (relativeIds[root] = normalizedDistDir.slice(root.length))
const relativeRoot = relativeIds[root] ?? (relativeIds[root] = getRelativeDistDir(root))
if (id.includes(distDir) || id.includes(normalizedDistDir)) {
const { file, postfix } = splitFileAndPostfix(id)
const externalize = id.startsWith('file://')
Expand Down
63 changes: 63 additions & 0 deletions test/unit/test/cached-resolver.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import type { WorkerGlobalState } from '../../../packages/vitest/src/types/worker'
import { pathToFileURL } from 'node:url'
import { dirname, normalize } from 'pathe'
import { describe, expect, test } from 'vitest'
import { distDir } from '../../../packages/vitest/src/paths'
import { getCachedVitestImport } from '../../../packages/vitest/src/runtime/moduleRunner/cachedResolver'

const normalizedDistDir = normalize(distDir)

function stateWithRoot(root: string): () => WorkerGlobalState {
return () => ({ config: { root } }) as WorkerGlobalState
}

function unrelatedRootForSuffix(suffix: string, fill: string): string {
return `/${fill.repeat(normalizedDistDir.length - suffix.length - 1)}`
}

describe('getCachedVitestImport', () => {
test('does not resolve a bare builtin relative to an unrelated root', () => {
const root = unrelatedRootForSuffix('t', 'a')
expect(normalizedDistDir.slice(root.length)).toBe('t')

expect(getCachedVitestImport('timers', stateWithRoot(root))).toBeNull()
})

test('does not resolve a builtin subpath relative to an unrelated root', () => {
const root = unrelatedRootForSuffix('st', 'b')
expect(normalizedDistDir.slice(root.length)).toBe('st')

expect(getCachedVitestImport('stream/promises', stateWithRoot(root))).toBeNull()
})

test('does not derive a relative path from a sibling root prefix', () => {
const root = normalizedDistDir.slice(0, -'st/dist'.length)
expect(normalizedDistDir.slice(root.length)).toBe('st/dist')

expect(getCachedVitestImport('st/dist/index.js', stateWithRoot(root))).toBeNull()
})

test('resolves a dist path relative to an ancestor root', () => {
const root = dirname(normalizedDistDir)
const id = `${normalizedDistDir.slice(root.length)}/index.js?relative`

expect(getCachedVitestImport(id, stateWithRoot(root))).toEqual({
externalize: `${pathToFileURL(`${normalizedDistDir}/index.js`)}?relative`,
type: 'module',
})
})

test('still resolves absolute and bare Vitest imports', () => {
const root = unrelatedRootForSuffix('test', 'c')
const id = `${normalizedDistDir}/index.js?absolute`

expect(getCachedVitestImport(id, stateWithRoot(root))).toEqual({
externalize: `${pathToFileURL(`${normalizedDistDir}/index.js`)}?absolute`,
type: 'module',
})
expect(getCachedVitestImport('vitest/config', stateWithRoot(root))).toEqual({
externalize: 'vitest/config',
type: 'module',
})
})
})
Loading