Skip to content

Commit

Permalink
fix(browser): correctly mock optimized cjs dependencies (#6035)
Browse files Browse the repository at this point in the history
  • Loading branch information
sheremet-va authored Jul 4, 2024
1 parent 42bd4a2 commit 057b4f3
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 11 deletions.
23 changes: 18 additions & 5 deletions packages/browser/src/client/tester/mocker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,16 +138,24 @@ export class VitestBrowserClientMocker {
public queueMock(id: string, importer: string, factory?: () => any) {
const promise = rpc()
.resolveMock(id, importer, !!factory)
.then(async ({ mockPath, resolvedId }) => {
.then(async ({ mockPath, resolvedId, needsInterop }) => {
this.ids.add(resolvedId)
const urlPaths = resolveMockPaths(resolvedId)
const urlPaths = resolveMockPaths(cleanVersion(resolvedId))
const resolvedMock
= typeof mockPath === 'string'
? new URL(resolvedMockedPath(mockPath), location.href).toString()
? new URL(resolvedMockedPath(cleanVersion(mockPath)), location.href).toString()
: mockPath
const _factory = factory && needsInterop
? async () => {
const data = await factory()
return { default: data }
}
: factory
urlPaths.forEach((url) => {
this.mocks[url] = resolvedMock
this.factories[url] = factory!
if (_factory) {
this.factories[url] = _factory
}
})
channel.postMessage({
type: 'mock',
Expand All @@ -170,7 +178,7 @@ export class VitestBrowserClientMocker {
return
}
this.ids.delete(resolved.id)
const urlPaths = resolveMockPaths(resolved.id)
const urlPaths = resolveMockPaths(cleanVersion(resolved.id))
urlPaths.forEach((url) => {
delete this.mocks[url]
delete this.factories[url]
Expand Down Expand Up @@ -445,3 +453,8 @@ function resolveMockPaths(path: string) {

return paths
}

const versionRegexp = /(\?|&)v=\w{8}/
function cleanVersion(url: string) {
return url.replace(versionRegexp, '')
}
8 changes: 4 additions & 4 deletions packages/browser/src/client/tester/msw.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export function createModuleMocker() {

const worker = setupWorker(
http.get(/.+/, async ({ request }) => {
const path = removeTimestamp(request.url.slice(location.origin.length))
const path = cleanQuery(request.url.slice(location.origin.length))
if (!mocks.has(path)) {
return passthrough()
}
Expand Down Expand Up @@ -112,9 +112,9 @@ function getFactoryExports(id: string) {
}

const timestampRegexp = /(\?|&)t=\d{13}/

function removeTimestamp(url: string) {
return url.replace(timestampRegexp, '')
const versionRegexp = /(\?|&)v=\w{8}/
function cleanQuery(url: string) {
return url.replace(timestampRegexp, '').replace(versionRegexp, '')
}

function passthrough() {
Expand Down
33 changes: 31 additions & 2 deletions packages/browser/src/node/resolveMock.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { existsSync, readdirSync } from 'node:fs'
import { existsSync, readFileSync, readdirSync } from 'node:fs'
import { builtinModules } from 'node:module'
import { basename, dirname, extname, isAbsolute, join, resolve } from 'pathe'
import type { PartialResolvedId } from 'rollup'
import type { ResolvedConfig } from 'vitest'
import type { ResolvedConfig as ViteConfig } from 'vite'
import type { WorkspaceProject } from 'vitest/node'

export async function resolveMock(
Expand All @@ -14,7 +15,9 @@ export async function resolveMock(
const { id, fsPath, external } = await resolveId(project, rawId, importer)

if (hasFactory) {
return { type: 'factory' as const, resolvedId: id }
const needsInteropMap = viteDepsInteropMap(project.browser!.vite.config)
const needsInterop = needsInteropMap?.get(fsPath) ?? false
return { type: 'factory' as const, resolvedId: id, needsInterop }
}

const mockPath = resolveMockPath(project.config.root, fsPath, external)
Expand Down Expand Up @@ -126,3 +129,29 @@ const postfixRE = /[?#].*$/
export function cleanUrl(url: string): string {
return url.replace(postfixRE, '')
}

const metadata = new WeakMap<ViteConfig, Map<string, boolean>>()

function viteDepsInteropMap(config: ViteConfig) {
if (metadata.has(config)) {
return metadata.get(config)!
}
const cacheDirPath = getDepsCacheDir(config)
const metadataPath = resolve(cacheDirPath, '_metadata.json')
if (!existsSync(metadataPath)) {
return null
}
const { optimized } = JSON.parse(readFileSync(metadataPath, 'utf-8'))
const needsInteropMap = new Map()
for (const name in optimized) {
const dep = optimized[name]
const file = resolve(cacheDirPath, dep.file)
needsInteropMap.set(file, dep.needsInterop)
}
metadata.set(config, needsInteropMap)
return needsInteropMap
}

function getDepsCacheDir(config: ViteConfig): string {
return resolve(config.cacheDir, 'deps')
}
1 change: 1 addition & 0 deletions packages/browser/src/node/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export interface WebSocketBrowserHandlers {
type: 'factory' | 'redirect' | 'automock'
mockPath?: string | null
resolvedId: string
needsInterop?: boolean
}>
invalidate: (ids: string[]) => void
getBrowserFileSourceMap: (
Expand Down
12 changes: 12 additions & 0 deletions test/browser/fixtures/mocking/mocking-dep.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { a } from '@vitest/cjs-lib'
import { expect, test, vi } from 'vitest'

vi.mock(import('@vitest/cjs-lib'), () => {
return {
a: 'mocked',
}
})

test('mocking works correctly', () => {
expect(a).toBe('mocked')
})
4 changes: 4 additions & 0 deletions test/browser/fixtures/mocking/vitest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ const name =
process.env.BROWSER || (provider === 'playwright' ? 'chromium' : 'chrome')

export default defineConfig({
optimizeDeps: {
include: ['@vitest/cjs-lib'],
needsInterop: ['@vitest/cjs-lib'],
},
test: {
browser: {
enabled: true,
Expand Down

0 comments on commit 057b4f3

Please sign in to comment.