Skip to content

Commit df6d750

Browse files
authored
fix(vitest): don't fail if the working directory starts with a lowercase drive letter (#6779)
1 parent 169028f commit df6d750

File tree

20 files changed

+64
-24
lines changed

20 files changed

+64
-24
lines changed

packages/browser/src/client/public/error-catcher.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,9 @@ async function reportUnexpectedError(
5656
error,
5757
) {
5858
const processedError = serializeError(error)
59-
await client.rpc.onUnhandledError(processedError, type)
59+
await client.waitForConnection().then(() => {
60+
return client.rpc.onUnhandledError(processedError, type)
61+
}).catch(console.error)
6062
const state = __vitest_browser_runner__
6163

6264
if (state.type === 'orchestrator') {

packages/browser/src/node/serverTester.ts

+1
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ export async function resolveTester(
6060
try {
6161
const indexhtml = await server.vite.transformIndexHtml(url.pathname, testerHtml)
6262
return replacer(indexhtml, {
63+
__VITEST_FAVICON__: server.faviconUrl,
6364
__VITEST_INJECTOR__: injector,
6465
__VITEST_APPEND__: `
6566
__vitest_browser_runner__.runningFiles = ${tests}

packages/ui/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@
7676
"codemirror-theme-vars": "^0.1.2",
7777
"d3-graph-controller": "^3.0.11",
7878
"floating-vue": "^5.2.2",
79+
"rollup": "^4.24.0",
7980
"splitpanes": "^3.1.5",
8081
"unocss": "^0.63.6",
8182
"unplugin-auto-import": "^0.18.3",

packages/vite-node/src/client.ts

+1-3
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
import type { HotContext, ModuleCache, ViteNodeRunnerOptions } from './types'
22

33
import { createRequire } from 'node:module'
4-
// we need native dirname, because windows __dirname has \\
5-
import { dirname } from 'node:path'
4+
import { dirname, resolve } from 'node:path'
65
import { fileURLToPath, pathToFileURL } from 'node:url'
76
import vm from 'node:vm'
87
import createDebug from 'debug'
9-
import { resolve } from 'pathe'
108
import { extractSourceMap } from './source-map'
119
import {
1210
cleanUrl,

packages/vite-node/src/utils.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@ export function normalizeRequestId(id: string, base?: string): string {
2828
id = `/${id.slice(base.length)}`
2929
}
3030

31-
// keep drive the same as in process cwd
31+
// keep drive the same as in process cwd. ideally, this should be resolved on Vite side
32+
// Vite always resolves drive letters to the upper case because of the use of `realpathSync`
33+
// https://github.com/vitejs/vite/blob/0ab20a3ee26eacf302415b3087732497d0a2f358/packages/vite/src/node/utils.ts#L635
3234
if (driveRegexp && !driveRegexp?.test(id) && driveOppositeRegext?.test(id)) {
3335
id = id.replace(driveOppositeRegext, `${drive}$1`)
3436
}

packages/vitest/src/node/plugins/mocks.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
import type { Plugin } from 'vite'
22
import { automockPlugin, hoistMocksPlugin } from '@vitest/mocker/node'
3+
import { normalize } from 'pathe'
34
import { distDir } from '../../paths'
45
import { generateCodeFrame } from '../error'
56

67
export function MocksPlugins(): Plugin[] {
8+
const normalizedDistDir = normalize(distDir)
79
return [
810
hoistMocksPlugin({
911
filter(id) {
10-
if (id.includes(distDir)) {
12+
if (id.includes(normalizedDistDir)) {
1113
return false
1214
}
1315
return true

packages/vitest/src/node/pools/forks.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ import type { SerializedConfig } from '../types/config'
77
import type { WorkspaceProject } from '../workspace'
88
import EventEmitter from 'node:events'
99
import * as nodeos from 'node:os'
10+
import { resolve } from 'node:path'
1011
import v8 from 'node:v8'
1112
import { createBirpc } from 'birpc'
12-
import { resolve } from 'pathe'
1313
import { Tinypool } from 'tinypool'
1414
import { groupBy } from '../../utils/base'
1515
import { wrapSerializableConfig } from '../../utils/config-helpers'

packages/vitest/src/node/pools/threads.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ import type { SerializedConfig } from '../types/config'
77
import type { WorkerContext } from '../types/worker'
88
import type { WorkspaceProject } from '../workspace'
99
import * as nodeos from 'node:os'
10+
import { resolve } from 'node:path'
1011
import { MessageChannel } from 'node:worker_threads'
1112
import { createBirpc } from 'birpc'
12-
import { resolve } from 'pathe'
1313
import Tinypool from 'tinypool'
1414
import { groupBy } from '../../utils/base'
1515
import { envsOrder, groupFilesByEnv } from '../../utils/test-helpers'

packages/vitest/src/node/pools/vmForks.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ import type { ResolvedConfig, SerializedConfig } from '../types/config'
77
import type { WorkspaceProject } from '../workspace'
88
import EventEmitter from 'node:events'
99
import * as nodeos from 'node:os'
10+
import { resolve } from 'node:path'
1011
import v8 from 'node:v8'
1112
import { createBirpc } from 'birpc'
12-
import { resolve } from 'pathe'
1313
import Tinypool from 'tinypool'
1414
import { rootDir } from '../../paths'
1515
import { wrapSerializableConfig } from '../../utils/config-helpers'

packages/vitest/src/node/pools/vmThreads.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ import type { ResolvedConfig, SerializedConfig } from '../types/config'
77
import type { WorkerContext } from '../types/worker'
88
import type { WorkspaceProject } from '../workspace'
99
import * as nodeos from 'node:os'
10+
import { resolve } from 'node:path'
1011
import { MessageChannel } from 'node:worker_threads'
1112
import { createBirpc } from 'birpc'
12-
import { resolve } from 'pathe'
1313
import Tinypool from 'tinypool'
1414
import { rootDir } from '../../paths'
1515
import { getWorkerMemoryLimit, stringToBytes } from '../../utils/memory-limit'

packages/vitest/src/node/workspace.ts

+7-4
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ import type {
1818
import { promises as fs } from 'node:fs'
1919
import { rm } from 'node:fs/promises'
2020
import { tmpdir } from 'node:os'
21-
import { deepMerge, nanoid } from '@vitest/utils'
21+
import path from 'node:path'
22+
import { deepMerge, nanoid, slash } from '@vitest/utils'
2223
import fg from 'fast-glob'
2324
import mm from 'micromatch'
2425
import {
@@ -27,7 +28,6 @@ import {
2728
join,
2829
relative,
2930
resolve,
30-
toNamespacedPath,
3131
} from 'pathe'
3232
import { ViteNodeRunner } from 'vite-node/client'
3333
import { ViteNodeServer } from 'vite-node/server'
@@ -302,7 +302,10 @@ export class WorkspaceProject {
302302
}
303303

304304
const files = await fg(include, globOptions)
305-
return files.map(file => resolve(cwd, file))
305+
// keep the slashes consistent with Vite
306+
// we are not using the pathe here because it normalizes the drive letter on Windows
307+
// and we want to keep it the same as working dir
308+
return files.map(file => slash(path.resolve(cwd, file)))
306309
}
307310

308311
async isTargetFile(id: string, source?: string): Promise<boolean> {
@@ -329,7 +332,7 @@ export class WorkspaceProject {
329332

330333
filterFiles(testFiles: string[], filters: string[], dir: string) {
331334
if (filters.length && process.platform === 'win32') {
332-
filters = filters.map(f => toNamespacedPath(f))
335+
filters = filters.map(f => slash(f))
333336
}
334337

335338
if (filters.length) {

packages/vitest/src/paths.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1+
import { resolve } from 'node:path'
12
import url from 'node:url'
2-
import { resolve } from 'pathe'
33

44
export const rootDir = resolve(url.fileURLToPath(import.meta.url), '../../')
55
export const distDir = resolve(

packages/vitest/src/runtime/execute.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ import {
1717
import { distDir } from '../paths'
1818
import { VitestMocker } from './mocker'
1919

20+
const normalizedDistDir = normalize(distDir)
21+
2022
const { readFileSync } = fs
2123

2224
export interface ExecuteOptions extends ViteNodeRunnerOptions {
@@ -112,7 +114,7 @@ export async function startVitestExecutor(options: ContextExecutorOptions) {
112114
}
113115
// always externalize Vitest because we import from there before running tests
114116
// so we already have it cached by Node.js
115-
if (id.includes(distDir)) {
117+
if (id.includes(distDir) || id.includes(normalizedDistDir)) {
116118
const { path } = toFilePath(id, state().config.root)
117119
const externalize = pathToFileURL(path).toString()
118120
externalizeMap.set(id, externalize)

packages/vitest/src/runtime/mocker.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import type { ManualMockedModule, MockedModuleType } from '@vitest/mocker'
22
import type { MockFactory, MockOptions, PendingSuiteMock } from '../types/mocker'
33
import type { VitestExecutor } from './execute'
4+
import { isAbsolute, resolve } from 'node:path'
45
import vm from 'node:vm'
56
import { AutomockedModule, MockerRegistry, mockObject, RedirectedModule } from '@vitest/mocker'
67
import { findMockRedirect } from '@vitest/mocker/redirect'
78
import { highlight } from '@vitest/utils'
8-
import { isAbsolute, resolve } from 'pathe'
99
import { distDir } from '../paths'
1010

1111
const spyModulePath = resolve(distDir, 'spy.js')

packages/vitest/src/runtime/runners/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type { VitestRunner, VitestRunnerConstructor } from '@vitest/runner'
22
import type { SerializedConfig } from '../config'
33
import type { VitestExecutor } from '../execute'
4-
import { resolve } from 'pathe'
4+
import { resolve } from 'node:path'
55
import { takeCoverageInsideWorker } from '../../integrations/coverage'
66
import { distDir } from '../../paths'
77
import { rpc } from '../rpc'

pnpm-lock.yaml

+3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/benchmark/test/reporter.test.ts

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { runVitest } from '../../test-utils'
55
it('summary', async () => {
66
const root = pathe.join(import.meta.dirname, '../fixtures/reporter')
77
const result = await runVitest({ root }, ['summary.bench.ts'], 'benchmark')
8+
expect(result.stderr).toBe('')
89
expect(result.stdout).not.toContain('NaNx')
910
expect(result.stdout.split('BENCH Summary')[1].replaceAll(/[0-9.]+x/g, '(?)')).toMatchSnapshot()
1011
})
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { expect, test } from 'vitest'
2+
3+
test('basic test', () => {
4+
expect(1).toBe(1)
5+
})

test/cli/test/public-api.test.ts

+7-6
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import type { File, TaskResultPack, UserConfig } from 'vitest'
1+
import type { RunnerTaskResultPack, RunnerTestFile } from 'vitest'
2+
import type { UserConfig } from 'vitest/node'
23
import { resolve } from 'pathe'
34
import { expect, it } from 'vitest'
45
import { runVitest } from '../../test-utils'
@@ -15,15 +16,15 @@ it.each([
1516
headless: true,
1617
},
1718
},
18-
] as UserConfig[])('passes down metadata when $name', { timeout: 60_000, retry: 3 }, async (config) => {
19-
const taskUpdate: TaskResultPack[] = []
20-
const finishedFiles: File[] = []
21-
const collectedFiles: File[] = []
19+
] as UserConfig[])('passes down metadata when $name', { timeout: 60_000, retry: 1 }, async (config) => {
20+
const taskUpdate: RunnerTaskResultPack[] = []
21+
const finishedFiles: RunnerTestFile[] = []
22+
const collectedFiles: RunnerTestFile[] = []
2223
const { ctx, stdout, stderr } = await runVitest({
2324
root: resolve(__dirname, '..', 'fixtures', 'public-api'),
2425
include: ['**/*.spec.ts'],
2526
reporters: [
26-
'verbose',
27+
['verbose', { isTTY: false }],
2728
{
2829
onTaskUpdate(packs) {
2930
taskUpdate.push(...packs.filter(i => i[1]?.state === 'pass'))
+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { join } from 'pathe'
2+
import { expect, test } from 'vitest'
3+
import { runVitestCli } from '../../test-utils'
4+
5+
const _DRIVE_LETTER_START_RE = /^[A-Z]:\//i
6+
const root = join(import.meta.dirname, '../fixtures/windows-drive-case')
7+
const cwd = root.replace(_DRIVE_LETTER_START_RE, r => r.toLowerCase())
8+
9+
test.runIf(process.platform === 'win32')(`works on windows with a lowercase drive: ${cwd}`, async () => {
10+
const { stderr, stdout } = await runVitestCli({
11+
nodeOptions: {
12+
cwd,
13+
},
14+
}, '--no-watch')
15+
16+
expect(cwd[0]).toEqual(cwd[0].toLowerCase())
17+
expect(stderr).toBe('')
18+
expect(stdout).toContain('1 passed')
19+
})

0 commit comments

Comments
 (0)