diff --git a/examples/app-vitest-full/package.json b/examples/app-vitest-full/package.json index fe7c36c10..fbafe39ab 100644 --- a/examples/app-vitest-full/package.json +++ b/examples/app-vitest-full/package.json @@ -8,7 +8,7 @@ "dev:prepare": "nuxt prepare", "generate": "nuxt generate", "preview": "nuxt preview", - "test:dev": "NUXT_VITEST_DEV_TEST=true nuxt dev --no-fork", + "test:dev": "nuxt dev --no-fork", "test:unit": "vitest", "test:types": "nuxi prepare && vue-tsc --noEmit", "test:jsdom": "VITEST_DOM_ENV=jsdom pnpm test:unit --run", diff --git a/examples/app-vitest-full/tests/nuxt/render-suspended.spec.ts b/examples/app-vitest-full/tests/nuxt/render-suspended.spec.ts index 2bf902bdf..4464dd4f7 100644 --- a/examples/app-vitest-full/tests/nuxt/render-suspended.spec.ts +++ b/examples/app-vitest-full/tests/nuxt/render-suspended.spec.ts @@ -33,13 +33,7 @@ const formats = { describe('renderSuspended', () => { afterEach(() => { - // since we're not running with Vitest globals when running the tests - // from inside the test server. This means testing-library cannot - // auto-attach the cleanup go testing globals, and we have to do - // it here manually. - if (process.env.NUXT_VITEST_DEV_TEST) { - cleanup() - } + cleanup() }) it('can render components within nuxt suspense', async () => { diff --git a/examples/app-vitest-full/tests/resolved-files.spec.ts b/examples/app-vitest-full/tests/resolved-files.spec.ts index 5aef33143..824c617da 100644 --- a/examples/app-vitest-full/tests/resolved-files.spec.ts +++ b/examples/app-vitest-full/tests/resolved-files.spec.ts @@ -2,8 +2,7 @@ import { fileURLToPath } from 'node:url' import { test, expect } from 'vitest' import { createVitest } from 'vitest/node' -// TODO: Investigate why this test fails when executed by the dev server. Once it's fixed, we can reenable this test. -test.skipIf(process.env.NUXT_VITEST_DEV_TEST)('it should include nuxt spec files', { timeout: 30000 }, async () => { +test('it should include nuxt spec files', { timeout: 30000 }, async () => { const vitest = await createVitest('test', { config: fileURLToPath(new URL('../vitest.config.ts', import.meta.url)), dir: fileURLToPath(new URL('../', import.meta.url)), diff --git a/src/config.ts b/src/config.ts index 7a410f574..3186bb2d9 100644 --- a/src/config.ts +++ b/src/config.ts @@ -6,7 +6,7 @@ import { defineConfig } from 'vite' import type { TestProjectInlineConfiguration } from 'vitest/config' import { setupDotenv } from 'c12' import type { DotenvOptions } from 'c12' -import type { UserConfig as ViteUserConfig } from 'vite' +import type { UserConfigFnPromise, UserConfig as ViteUserConfig } from 'vite' import type { DateString } from 'compatx' import { defu } from 'defu' import { createResolver, findPath } from '@nuxt/kit' @@ -119,7 +119,6 @@ export async function getVitestConfigFromNuxt( noDiscovery: true, }, test: { - dir: process.cwd(), environmentOptions: { nuxtRuntimeConfig: applyEnv(structuredClone(options.nuxt.options.runtimeConfig), { prefix: 'NUXT_', @@ -224,10 +223,7 @@ export async function getVitestConfigFromNuxt( return resolvedConfig } -export async function defineVitestProject(config: TestProjectInlineConfiguration) { - // When Nuxt module calls `startVitest`, we don't need to call `getVitestConfigFromNuxt` again - if (process.env.__NUXT_VITEST_RESOLVED__) return config - +export async function defineVitestProject(config: TestProjectInlineConfiguration): Promise { const resolvedConfig = await resolveConfig(config) resolvedConfig.test.environment = 'nuxt' @@ -235,11 +231,8 @@ export async function defineVitestProject(config: TestProjectInlineConfiguration return resolvedConfig } -export function defineVitestConfig(config: ViteUserConfig & { test?: VitestConfig } = {}) { +export function defineVitestConfig(config: ViteUserConfig & { test?: VitestConfig } = {}): UserConfigFnPromise { return defineConfig(async () => { - // When Nuxt module calls `startVitest`, we don't need to call `getVitestConfigFromNuxt` again - if (process.env.__NUXT_VITEST_RESOLVED__) return config - const resolvedConfig = await resolveConfig(config) if (resolvedConfig.test.browser?.enabled) { diff --git a/src/module.ts b/src/module.ts index ce977b45b..e8715f977 100644 --- a/src/module.ts +++ b/src/module.ts @@ -1,19 +1,16 @@ /// import { pathToFileURL } from 'node:url' -import { createResolver, defineNuxtModule, logger, resolvePath, importModule } from '@nuxt/kit' +import { createResolver, defineNuxtModule, logger, resolvePath } from '@nuxt/kit' import type { Vitest, UserConfig as VitestConfig } from 'vitest/node' import type { Reporter } from 'vitest/reporters' import type { RunnerTestFile } from 'vitest' -import type { InlineConfig as ViteConfig } from 'vite' import { getPort } from 'get-port-please' import { h } from 'vue' import { debounce } from 'perfect-debounce' import { isCI } from 'std-env' -import { defu } from 'defu' import { join, relative } from 'pathe' -import { getVitestConfigFromNuxt } from './config' import { setupImportMocking } from './module/mock' import { NuxtRootStubPlugin } from './module/plugins/entry' import { loadKit } from './utils' @@ -24,12 +21,6 @@ export interface NuxtVitestOptions { vitestConfig?: VitestConfig } -/** - * List of plugins that are not compatible with test env. - * Hard-coded for now, should remove by PR to upstream. - */ -const vitePluginBlocklist = ['vite-plugin-vue-inspector', 'vite-plugin-vue-inspector:post', 'vite-plugin-inspect', 'nuxt:type-check'] - export default defineNuxtModule({ meta: { name: '@nuxt/test-utils', @@ -44,7 +35,7 @@ export default defineNuxtModule({ await setupImportMocking(nuxt) } - const { addVitePlugin } = await loadKit(nuxt.options.rootDir) + const { addVitePlugin, loadNuxt } = await loadKit(nuxt.options.rootDir) const resolver = createResolver(import.meta.url) if (nuxt.options.test || nuxt.options.dev) { @@ -76,15 +67,6 @@ export default defineNuxtModule({ // the nuxt instance is used by a standalone Vitest env, we skip this module if (process.env.TEST || process.env.VITE_TEST) return - const rawViteConfigPromise = new Promise((resolve) => { - // Wrap with app:resolve to ensure we got the final vite config - nuxt.hook('app:resolve', () => { - nuxt.hook('vite:configResolved', (config, { isClient }) => { - if (isClient) resolve(config) - }) - }) - }) - let loaded = false let promise: Promise | undefined let ctx: Vitest = undefined! @@ -97,23 +79,6 @@ export default defineNuxtModule({ let URL: string async function start() { - const { mergeConfig } = await importModule('vite', { paths: nuxt.options.modulesDir }) - const rawViteConfig = mergeConfig({}, await rawViteConfigPromise) - - const viteConfig = await getVitestConfigFromNuxt({ nuxt, viteConfig: defu({ test: options.vitestConfig }, rawViteConfig) }) - - viteConfig.plugins = (viteConfig.plugins || []).filter((p) => { - return !p || !('name' in p) || !vitePluginBlocklist.includes(p.name) - }) - - // TODO: investigate why this is needed - viteConfig.test.environmentMatchGlobs ||= [] - viteConfig.test.environmentMatchGlobs.push( - ['**/*.nuxt.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}', 'nuxt'], - ['{test,tests}/nuxt/**.*', 'nuxt'], - ) - - process.env.__NUXT_VITEST_RESOLVED__ = 'true' const { startVitest } = (await import(pathToFileURL(await resolvePath('vitest/node')).href)) as typeof import('vitest/node') const customReporter: Reporter = { @@ -130,34 +95,32 @@ export default defineNuxtModule({ }, } - const watchMode = !process.env.NUXT_VITEST_DEV_TEST && !isCI + const watchMode = !isCI // We resolve the path here to ensure the dev server is already running with the correct protocol const PORT = await getPort({ port: 15555 }) const PROTOCOL = nuxt.options.devServer.https ? 'https' : 'http' URL = `${PROTOCOL}://localhost:${PORT}/__vitest__/` - // For testing dev mode in CI, maybe expose an option to user later - const overrides: VitestConfig = watchMode - ? { - passWithNoTests: true, - reporters: options.logToConsole - ? [ - ...toArray(options.vitestConfig?.reporters ?? ['default']), - customReporter, - ] - : [customReporter], // do not report to console - watch: true, - ui: true, - open: false, - api: { - port: PORT, - }, - } - : { watch: false } - // Start Vitest - const promise = startVitest('test', [], defu(overrides, viteConfig.test), viteConfig) + const promise = loadNuxt({ cwd: nuxt.options.rootDir }).then(nuxt => nuxt.runWithContext( + () => startVitest('test', [], { ...watchMode + ? { + passWithNoTests: true, + reporters: options.logToConsole + ? [ + ...toArray(options.vitestConfig?.reporters ?? ['default']), + customReporter, + ] + : [customReporter], // do not report to console + watch: true, + ui: true, + open: false, + api: { + port: PORT, + }, + } + : { watch: false }, root: nuxt.options.rootDir }))) promise.catch(() => process.exit(1)) if (watchMode) {