Skip to content

Commit 804ff2f

Browse files
authoredJul 25, 2024··
fix(browser): correctly import optimized module in vi.importActual (#6219)
1 parent 9069bdc commit 804ff2f

File tree

5 files changed

+69
-8
lines changed

5 files changed

+69
-8
lines changed
 

‎packages/browser/src/client/tester/mocker.ts

+10-3
Original file line numberDiff line numberDiff line change
@@ -59,12 +59,19 @@ export class VitestBrowserClientMocker {
5959
)
6060
}
6161
const ext = extname(resolved.id)
62-
const url = new URL(`/@id/${resolved.id}`, location.href)
63-
const query = `_vitest_original&ext.${ext}`
62+
const url = new URL(resolved.url, location.href)
63+
const query = `_vitest_original&ext${ext}`
6464
const actualUrl = `${url.pathname}${
6565
url.search ? `${url.search}&${query}` : `?${query}`
6666
}${url.hash}`
67-
return getBrowserState().wrapModule(() => import(/* @vite-ignore */ actualUrl))
67+
return getBrowserState().wrapModule(() => import(/* @vite-ignore */ actualUrl)).then((mod) => {
68+
if (!resolved.optimized || typeof mod.default === 'undefined') {
69+
return mod
70+
}
71+
// vite injects this helper for optimized modules, so we try to follow the same behavior
72+
const m = mod.default
73+
return m?.__esModule ? m : { ...((typeof m === 'object' && !Array.isArray(m)) || typeof m === 'function' ? m : {}), default: m }
74+
})
6875
}
6976

7077
public async importMock(rawId: string, importer: string) {

‎packages/browser/src/node/rpc.ts

+43-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { existsSync, promises as fs } from 'node:fs'
2-
import { dirname } from 'pathe'
2+
import { dirname, isAbsolute, join } from 'pathe'
33
import { createBirpc } from 'birpc'
44
import { parse, stringify } from 'flatted'
55
import type { WebSocket } from 'ws'
@@ -8,11 +8,12 @@ import type { BrowserCommandContext } from 'vitest/node'
88
import { createDebugger, isFileServingAllowed } from 'vitest/node'
99
import type { WebSocketBrowserEvents, WebSocketBrowserHandlers } from './types'
1010
import type { BrowserServer } from './server'
11-
import { resolveMock } from './resolveMock'
11+
import { cleanUrl, resolveMock } from './resolveMock'
1212

1313
const debug = createDebugger('vitest:browser:api')
1414

1515
const BROWSER_API_PATH = '/__vitest_browser_api__'
16+
const VALID_ID_PREFIX = '/@id/'
1617

1718
export function setupBrowserRpc(
1819
server: BrowserServer,
@@ -118,14 +119,44 @@ export function setupBrowserRpc(
118119
ctx.cancelCurrentRun(reason)
119120
},
120121
async resolveId(id, importer) {
121-
const result = await project.server.pluginContainer.resolveId(
122+
const resolved = await vite.pluginContainer.resolveId(
122123
id,
123124
importer,
124125
{
125126
ssr: false,
126127
},
127128
)
128-
return result
129+
if (!resolved) {
130+
return null
131+
}
132+
const isOptimized = resolved.id.startsWith(withTrailingSlash(vite.config.cacheDir))
133+
let url: string
134+
// normalise the URL to be acceptible by the browser
135+
// https://github.com/vitejs/vite/blob/e833edf026d495609558fd4fb471cf46809dc369/packages/vite/src/node/plugins/importAnalysis.ts#L335
136+
const root = vite.config.root
137+
if (resolved.id.startsWith(withTrailingSlash(root))) {
138+
url = resolved.id.slice(root.length)
139+
}
140+
else if (
141+
resolved.id !== '/@react-refresh'
142+
&& isAbsolute(resolved.id)
143+
&& existsSync(cleanUrl(resolved.id))
144+
) {
145+
url = join('/@fs/', resolved.id)
146+
}
147+
else {
148+
url = resolved.id
149+
}
150+
if (url[0] !== '.' && url[0] !== '/') {
151+
url = id.startsWith(VALID_ID_PREFIX)
152+
? id
153+
: VALID_ID_PREFIX + id.replace('\0', '__x00__')
154+
}
155+
return {
156+
id: resolved.id,
157+
url,
158+
optimized: isOptimized,
159+
}
129160
},
130161
debug(...args) {
131162
ctx.logger.console.debug(...args)
@@ -242,3 +273,11 @@ export function stringifyReplace(key: string, value: any) {
242273
return value
243274
}
244275
}
276+
277+
function withTrailingSlash(path: string): string {
278+
if (path[path.length - 1] !== '/') {
279+
return `${path}/`
280+
}
281+
282+
return path
283+
}

‎packages/browser/src/node/types.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export interface WebSocketBrowserHandlers {
2020
resolveId: (
2121
id: string,
2222
importer?: string
23-
) => Promise<{ id: string } | null>
23+
) => Promise<{ id: string; url: string; optimized: boolean } | null>
2424
triggerCommand: <T>(
2525
contextId: string,
2626
command: string,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { a, b } from '@vitest/cjs-lib'
2+
import { expect, test, vi } from 'vitest'
3+
4+
vi.mock(import('@vitest/cjs-lib'), async (importOriginal) => {
5+
const original = await importOriginal()
6+
return {
7+
...await importOriginal(),
8+
}
9+
})
10+
11+
test('mocking works correctly', () => {
12+
expect(a).toBe('a')
13+
expect(b).toBe('b')
14+
})

‎test/browser/specs/mocking.test.ts

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ test.each([true, false])('mocking works correctly - isolated %s', async (isolate
2424
expect(result.stdout).toContain('import-actual-query.test.ts')
2525
expect(result.stdout).toContain('import-mock.test.ts')
2626
expect(result.stdout).toContain('mocked-do-mock-factory.test.ts')
27+
expect(result.stdout).toContain('import-actual-dep.test.ts')
2728
expect(result.exitCode).toBe(0)
2829
})
2930

0 commit comments

Comments
 (0)
Please sign in to comment.