From 7deea688e95d8f79a82d633ad70e5c5bd70f484c Mon Sep 17 00:00:00 2001 From: Vladimir Sheremet Date: Fri, 6 Oct 2023 10:42:25 +0200 Subject: [PATCH] fix(vitest): support assets in new URL in Vite 5 --- .eslintrc | 3 +- packages/vitest/src/node/plugins/index.ts | 2 + .../vitest/src/node/plugins/normalizeURL.ts | 38 +++++++++++++++++++ .../vitest/src/node/plugins/ssrReplacer.ts | 2 +- packages/vitest/src/node/plugins/workspace.ts | 2 + 5 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 packages/vitest/src/node/plugins/normalizeURL.ts diff --git a/.eslintrc b/.eslintrc index f4630ff4e979..4d3e8020fdbb 100644 --- a/.eslintrc +++ b/.eslintrc @@ -14,7 +14,8 @@ "paths": ["path"] } ], - "import/no-named-as-default": "off" + "import/no-named-as-default": "off", + "no-cond-assign": "off" }, "overrides": [ { diff --git a/packages/vitest/src/node/plugins/index.ts b/packages/vitest/src/node/plugins/index.ts index d7c8fc7f7047..e4348c9e5f4d 100644 --- a/packages/vitest/src/node/plugins/index.ts +++ b/packages/vitest/src/node/plugins/index.ts @@ -14,6 +14,7 @@ import { MocksPlugin } from './mocks' import { deleteDefineConfig, hijackVitePluginInject, resolveFsAllow } from './utils' import { VitestResolver } from './vitestResolver' import { VitestOptimizer } from './optimizer' +import { NormalizeURLPlugin } from './normalizeURL' export async function VitestPlugin(options: UserConfig = {}, ctx = new Vitest('test')): Promise { const userConfig = deepMerge({}, options) as UserConfig @@ -185,6 +186,7 @@ export async function VitestPlugin(options: UserConfig = {}, ctx = new Vitest('t MocksPlugin(), VitestResolver(ctx), VitestOptimizer(), + NormalizeURLPlugin(), ] .filter(notNullish) } diff --git a/packages/vitest/src/node/plugins/normalizeURL.ts b/packages/vitest/src/node/plugins/normalizeURL.ts new file mode 100644 index 000000000000..89e44b8c6819 --- /dev/null +++ b/packages/vitest/src/node/plugins/normalizeURL.ts @@ -0,0 +1,38 @@ +import { stripLiteral } from 'strip-literal' +import type { Plugin } from 'vite' + +const metaUrlLength = 'import.meta.url'.length +const locationString = 'self.location'.padEnd(metaUrlLength, ' ') + +// Vite transforms new URL('./path', import.meta.url) to new URL('/path.js', import.meta.url) +// This makes "href" equal to "http://localhost:3000/path.js" in the browser, but if we keep it like this, +// then in tests the URL will become "file:///path.js". +// To battle this, we replace "import.meta.url" with "self.location" in the code to keep the browser behavior. +export function NormalizeURLPlugin(): Plugin { + return { + name: 'vitest:normalize-url', + enforce: 'post', + transform(code, id, options) { + const ssr = options?.ssr === true + if (ssr || !code.includes('new URL') || !code.includes('import.meta.url')) + return + + const cleanString = stripLiteral(code) + const assetImportMetaUrlRE + = /\bnew\s+URL\s*\(\s*('[^']+'|"[^"]+"|`[^`]+`)\s*,\s*import\.meta\.url\s*(?:,\s*)?\)/g + + let updatedCode = code + let match: RegExpExecArray | null + while ((match = assetImportMetaUrlRE.exec(cleanString))) { + const { 0: exp, index } = match + const metaUrlIndex = index + exp.indexOf('import.meta.url') + updatedCode = updatedCode.slice(0, metaUrlIndex) + locationString + updatedCode.slice(metaUrlIndex + metaUrlLength) + } + + return { + code: updatedCode, + map: null, + } + }, + } +} diff --git a/packages/vitest/src/node/plugins/ssrReplacer.ts b/packages/vitest/src/node/plugins/ssrReplacer.ts index 01792969962a..0df70d5fb189 100644 --- a/packages/vitest/src/node/plugins/ssrReplacer.ts +++ b/packages/vitest/src/node/plugins/ssrReplacer.ts @@ -10,7 +10,7 @@ export function SsrReplacerPlugin(): Plugin { name: 'vitest:ssr-replacer', enforce: 'pre', transform(code, id) { - if (!/\bimport\.meta\.env\b/.test(code) && !/\bimport\.meta\.url\b/.test(code)) + if (!/\bimport\.meta\.env\b/.test(code)) return null let s: MagicString | null = null diff --git a/packages/vitest/src/node/plugins/workspace.ts b/packages/vitest/src/node/plugins/workspace.ts index 119b7c453941..46c6bccb9627 100644 --- a/packages/vitest/src/node/plugins/workspace.ts +++ b/packages/vitest/src/node/plugins/workspace.ts @@ -12,6 +12,7 @@ import { MocksPlugin } from './mocks' import { deleteDefineConfig, hijackVitePluginInject, resolveFsAllow } from './utils' import { VitestResolver } from './vitestResolver' import { VitestOptimizer } from './optimizer' +import { NormalizeURLPlugin } from './normalizeURL' interface WorkspaceOptions extends UserWorkspaceConfig { root?: string @@ -125,5 +126,6 @@ export function WorkspaceVitestPlugin(project: WorkspaceProject, options: Worksp MocksPlugin(), VitestResolver(project.ctx), VitestOptimizer(), + NormalizeURLPlugin(), ] }