diff --git a/packages/vitest/src/runtime/moduleRunner/utils.ts b/packages/vitest/src/runtime/moduleRunner/utils.ts index 83c58a4a1485..daf4b446bd3d 100644 --- a/packages/vitest/src/runtime/moduleRunner/utils.ts +++ b/packages/vitest/src/runtime/moduleRunner/utils.ts @@ -1,5 +1,8 @@ -// copied from vite/src/shared/utils.ts +// copied from vite +// https://github.com/vitejs/vite/blob/4417b4f305623b2850bd6ae6553834c017694672/packages/vite/src/shared/utils.ts +// https://github.com/vitejs/vite/blob/4417b4f305623b2850bd6ae6553834c017694672/packages/vite/src/node/utils.ts const postfixRE = /[?#].*$/ +const trailingSeparatorRE = /[?&]$/ function cleanUrl(url: string): string { return url.replace(postfixRE, '') @@ -16,6 +19,6 @@ export function injectQuery(url: string, queryToInject: string): string { export function removeQuery(url: string, queryToRemove: string): string { return url - .replace(new RegExp(`[?&]${queryToRemove}(?=[&#]|$)`), '') - .replace(/\?$/, '') + .replace(new RegExp(`([?&])${queryToRemove}(?:&|$)`), '$1') + .replace(trailingSeparatorRE, '') } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 54e94b6256a8..f2f27fe76d2f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1393,6 +1393,9 @@ importers: test-dep-simple: specifier: file:./deps/dep-simple version: file:test/e2e/deps/dep-simple + test-dep-simple2: + specifier: file:./deps/dep-simple2 + version: file:test/e2e/deps/dep-simple2 tinyexec: specifier: ^1.0.2 version: 1.0.2 @@ -9666,6 +9669,9 @@ packages: test-dep-error@file:test/browser/deps/test-dep-error: resolution: {directory: test/browser/deps/test-dep-error, type: directory} + test-dep-simple2@file:test/e2e/deps/dep-simple2: + resolution: {directory: test/e2e/deps/dep-simple2, type: directory} + test-dep-simple@file:test/e2e/deps/dep-simple: resolution: {directory: test/e2e/deps/dep-simple, type: directory} @@ -19001,6 +19007,8 @@ snapshots: test-dep-error@file:test/browser/deps/test-dep-error: {} + test-dep-simple2@file:test/e2e/deps/dep-simple2: {} + test-dep-simple@file:test/e2e/deps/dep-simple: {} text-decoder@1.1.1: diff --git a/test/e2e/deps/dep-simple2/index.js b/test/e2e/deps/dep-simple2/index.js new file mode 100644 index 000000000000..02a729f2b66a --- /dev/null +++ b/test/e2e/deps/dep-simple2/index.js @@ -0,0 +1 @@ +export default 'test-dep-simple2' diff --git a/test/e2e/deps/dep-simple2/package.json b/test/e2e/deps/dep-simple2/package.json new file mode 100644 index 000000000000..a86653f7c5c6 --- /dev/null +++ b/test/e2e/deps/dep-simple2/package.json @@ -0,0 +1,6 @@ +{ + "name": "test-dep-simple2", + "type": "module", + "private": true, + "exports": "./index.js" +} diff --git a/test/e2e/fixtures/optimize-deps-mock/basic.test.ts b/test/e2e/fixtures/optimize-deps-mock/basic.test.ts new file mode 100644 index 000000000000..1da930c31284 --- /dev/null +++ b/test/e2e/fixtures/optimize-deps-mock/basic.test.ts @@ -0,0 +1,40 @@ +import { expect, test, vi } from 'vitest' +// @ts-expect-error no type +import * as dep from "@test/test-dep-url" +// @ts-expect-error no type +import * as simple from "test-dep-simple" +// @ts-expect-error no type +import * as simple2 from "test-dep-simple2" + +// mock + optimized +vi.mock('@test/test-dep-url', async (importOriginal) => { + const original = await importOriginal() + return { ...original, mocked: "ok" }; +}) + +// mock + not optimized + no external +vi.mock('test-dep-simple', async (importOriginal) => { + const original = await importOriginal() + return { ...original, mocked: "ok" }; +}) + +// mock + not optimized + external +vi.mock('test-dep-simple2', async (importOriginal) => { + const original = await importOriginal() + return { ...original, mocked: "ok" }; +}) + +test('basic', () => { + expect.soft({...dep}).toEqual({ + mocked: 'ok', + importMetaUrl: expect.stringContaining('/node_modules/.vite/vitest/') + }) + expect({...simple}).toEqual({ + mocked: 'ok', + default: 'test-dep-simple', + }) + expect({...simple2}).toEqual({ + mocked: 'ok', + default: 'test-dep-simple2', + }) +}) diff --git a/test/e2e/fixtures/optimize-deps-mock/vitest.config.ts b/test/e2e/fixtures/optimize-deps-mock/vitest.config.ts new file mode 100644 index 000000000000..316fd79f326d --- /dev/null +++ b/test/e2e/fixtures/optimize-deps-mock/vitest.config.ts @@ -0,0 +1,19 @@ +import { defineConfig } from 'vitest/config' + +export default defineConfig({ + ssr: { + noExternal: ["test-dep-simple"], + optimizeDeps: { + include: ["@test/test-dep-url"], + }, + }, + test: { + deps: { + optimizer: { + ssr: { + enabled: true, + }, + }, + }, + }, +}) diff --git a/test/e2e/package.json b/test/e2e/package.json index 28755550a2c3..e54520272d1c 100644 --- a/test/e2e/package.json +++ b/test/e2e/package.json @@ -40,6 +40,7 @@ "test-dep-conditions": "file:./deps/test-dep-conditions", "test-dep-invalid": "link:./deps/dep-invalid", "test-dep-simple": "file:./deps/dep-simple", + "test-dep-simple2": "file:./deps/dep-simple2", "tinyexec": "^1.0.2", "tinyspy": "catalog:", "typescript": "catalog:", diff --git a/test/e2e/test/optimize-deps-mock.test.ts b/test/e2e/test/optimize-deps-mock.test.ts new file mode 100644 index 000000000000..8578fe0174af --- /dev/null +++ b/test/e2e/test/optimize-deps-mock.test.ts @@ -0,0 +1,21 @@ +import { expect, test } from 'vitest' +import { runVitest } from '../../test-utils' + +test.for(['forks', 'threads', 'vmThreads', 'vmForks'])( + 'optimize deps and mock - %s', + async (pool) => { + const { errorTree, stderr } = await runVitest({ + root: './fixtures/optimize-deps-mock', + pool, + }) + + expect(stderr).toBe('') + expect(errorTree()).toMatchInlineSnapshot(` + { + "basic.test.ts": { + "basic": "passed", + }, + } + `) + }, +) diff --git a/test/tsconfig.json b/test/tsconfig.json index fa940a1dbe10..21d0ae210923 100644 --- a/test/tsconfig.json +++ b/test/tsconfig.json @@ -2,7 +2,8 @@ "extends": "../tsconfig.base.json", "compilerOptions": { "types": [ - "node" + "node", + "vite/client" ] }, "include": [ diff --git a/test/unit/test/mocking/import-actual-query-target.ts b/test/unit/test/mocking/import-actual-query-target.ts new file mode 100644 index 000000000000..adf5d0bb8b78 --- /dev/null +++ b/test/unit/test/mocking/import-actual-query-target.ts @@ -0,0 +1 @@ +export default 'import-actual-query-target' diff --git a/test/unit/test/mocking/import-actual-query.test.ts b/test/unit/test/mocking/import-actual-query.test.ts new file mode 100644 index 000000000000..cb6e96d79299 --- /dev/null +++ b/test/unit/test/mocking/import-actual-query.test.ts @@ -0,0 +1,20 @@ +import { expect, test, vi } from 'vitest' +import * as target from './import-actual-query-target?raw' + +vi.mock(import('./import-actual-query-target?raw'), async (importOriginal) => { + const original = await importOriginal() + return { + ...original, + mocked: 'ok', + } +}) + +test('importOriginal preserves query parameters', () => { + expect({ ...target }).toMatchInlineSnapshot(` + { + "default": "export default 'import-actual-query-target' + ", + "mocked": "ok", + } + `) +})