UNPKG

@nuxt/test-utils

Version:
295 lines (294 loc) 11.5 kB
import { n as deepCopy, r as loadKit, t as applyEnv } from "./utils-whMnUpQ0.mjs"; import { createDefu, defu as defu$1 } from "defu"; import { resolveModulePath } from "exsolve"; import process from "node:process"; import { version } from "vitest/node"; import { setupDotenv } from "c12"; import { createResolver, findPath } from "@nuxt/kit"; import { getPackageInfoSync } from "local-pkg"; //#region src/module/plugins/options.ts const PLUGIN_NAME = "nuxt:vitest:nuxt-environment-options"; const STUB_ID = "nuxt-vitest-environment-options"; function NuxtVitestEnvironmentOptionsPlugin(environmentOptions = {}) { return { name: PLUGIN_NAME, enforce: "pre", resolveId(id) { if (id.endsWith(STUB_ID)) return STUB_ID; }, load(id) { if (id.endsWith(STUB_ID)) return `export default ${JSON.stringify(environmentOptions || {})}`; } }; } //#endregion //#region src/config.ts async function startNuxtAndGetViteConfig(rootDir = process.cwd(), options = {}) { const { buildNuxt, loadNuxt } = await loadKit(rootDir); const nuxt = await loadNuxt({ cwd: rootDir, dev: options.nitroEnvironment || (options.overrides?.dev ?? false), dotenv: defu$1(options.dotenv, { cwd: rootDir, fileName: ".env.test" }), defaults: { compatibilityDate: "2024-04-03" }, overrides: defu$1({ appId: "nuxt-app", buildId: "test", ssr: false, test: true, modules: ["@nuxt/test-utils/module"] }, options.overrides, options.nitroEnvironment ? {} : DISABLE_NITRO_ENVIRONMENT) }); if (!nuxt.options._installedModules.find((i) => i?.meta?.name === "@nuxt/test-utils")) throw new Error("Failed to load `@nuxt/test-utils/module`. You may need to add it to your nuxt.config."); const nitro = options.nitroEnvironment ? {} : void 0; if (nitro) nuxt.hook("nitro:init", (instance) => { nitro.current = instance; }); return new Promise((resolve, reject) => { nuxt.hook("vite:configResolved", (viteConfig, { isClient }) => { if (isClient) { resolve({ nuxt, viteConfig, nitro }); throw new Error("_stop_"); } }); buildNuxt(nuxt).catch((err) => { if (!err.toString().includes("_stop_")) reject(err); }); }).finally(() => nuxt.close()); } const DISABLE_NITRO_ENVIRONMENT = { experimental: { nitroViteEnvironment: false } }; function nitroTeardownPlugin(nitro) { let closed; return { name: "nuxt:test-utils:nitro-teardown", async closeBundle() { closed ||= nitro.current?.hooks.callHook("close") ?? Promise.resolve(); await closed; } }; } const excludedPlugins = [ "nuxt:import-protection", "nuxt:import-conditions", "nuxt:devtools:rpc", "nuxt:devtools:config-retriever", "vite-plugin-checker", "vite-plugin-inspect", "vite-plugin-vue-tracer" ]; async function getVitestConfigFromNuxt(options, loadNuxtOptions = {}) { const { rootDir = process.cwd(), ..._overrides } = loadNuxtOptions.overrides || {}; if (!options) options = await startNuxtAndGetViteConfig(rootDir, { dotenv: loadNuxtOptions.dotenv, nitroEnvironment: loadNuxtOptions.nitroEnvironment, overrides: { test: true, ..._overrides } }); delete options.viteConfig.root; options.viteConfig.plugins = (options.viteConfig.plugins || []).filter((p) => !p || !("name" in p) || !excludedPlugins.includes(p.name)); const nuxtServerIntegration = getPackageInfoSync("@nuxt/nitro-server", { paths: [options.nuxt.options.appDir] }); let nitroPath; for (const nitroCandidate of [...nuxtServerIntegration?.packageJson.dependencies?.nitro ? ["nitro", "nitro-nightly"] : ["nitropack", "nitropack-nightly"]]) { nitroPath = resolveModulePath(nitroCandidate, { from: nuxtServerIntegration?.rootPath || options.nuxt.options.appDir, try: true }); if (nitroPath) break; } const projectH3Path = resolveModulePath("h3/package.json", { from: rootDir, try: true }); const h3Info = (projectH3Path ? getPackageInfoSync("h3", { paths: [projectH3Path] }) : void 0) || getPackageInfoSync("h3", { paths: nitroPath ? [nitroPath] : options.nuxt.options.modulesDir }); const resolver = createResolver(import.meta.url); const resolvedConfig = defu$1({ define: { "process.env.NODE_ENV": "\"test\"", "__NUXT_VITEST_RESOLVED__": "true" }, resolve: { alias: { "@vue/devtools-kit": resolver.resolve("./runtime/mocks/vue-devtools"), "@vue/devtools-core": resolver.resolve("./runtime/mocks/vue-devtools") } }, optimizeDeps: { noDiscovery: true }, test: { environmentOptions: { nuxtRuntimeConfig: applyEnv(deepCopy(options.nuxt.options.runtimeConfig), { prefix: "NUXT_", env: await setupDotenv(defu$1(loadNuxtOptions.dotenv, { cwd: rootDir, fileName: ".env.test" })) }), nuxtRouteRules: defu$1({}, options.nuxt.options.routeRules, options.nuxt.options.nitro?.routeRules), nuxtAppConfig: { rootAttrs: options.nuxt.options.app.rootAttrs, rootTag: options.nuxt.options.app.rootTag, teleportAttrs: options.nuxt.options.app.teleportAttrs, teleportTag: options.nuxt.options.app.teleportTag } }, server: { deps: { inline: [ /\/node_modules\/(.*\/)?(nuxt|nuxt3|nuxt-nightly)\//, /^#/, "@nuxt/test-utils", "@nuxt/test-utils-nightly", "@nuxt/test-utils-edge", "vitest-environment-nuxt", ...options.nuxt.options.build.transpile.filter((r) => typeof r === "string" || r instanceof RegExp) ] } }, deps: { optimizer: { client: { enabled: false } } } } }, { server: { middlewareMode: false }, plugins: [ { name: "disable-auto-execute", enforce: "pre", transform(code, id) { if (id.match(/nuxt(3|-nightly)?\/.*\/entry\./)) return code.replace(/(?<!vueAppPromise = )entry\(\)/, "Promise.resolve()"); } }, ...options.nitro ? [nitroTeardownPlugin(options.nitro)] : [], { name: "nuxt:test-utils:browser-conditions", enforce: "pre", config() { return { resolve: { conditions: [ "web", "import", "module", "default" ] } }; }, configResolved(config) { if (config.ssr.resolve?.conditions) config.ssr.resolve.conditions = config.ssr.resolve.conditions.filter((x) => x !== "import"); } } ] }, options.viteConfig, { test: { environmentOptions: { nuxt: { rootId: options.nuxt.options.app.rootAttrs?.id || void 0, h3Version: h3Info?.version?.startsWith("2.") ? 2 : 1, mock: { intersectionObserver: true, indexedDb: false } } } } }); delete resolvedConfig.define["process.browser"]; delete resolvedConfig.customLogger; delete resolvedConfig.ssr; if (!Array.isArray(resolvedConfig.test.setupFiles)) resolvedConfig.test.setupFiles = [resolvedConfig.test.setupFiles].filter(Boolean); const entryPath = resolver.resolve("./runtime/entry"); resolvedConfig.test.setupFiles.unshift(await findPath(entryPath) ?? entryPath); return resolvedConfig; } const vitestMajor = Number(version.split(".")[0]); const optOutOfExtends = false; async function defineVitestProject(config) { const resolvedConfig = await resolveConfig(defu$1({ test: { environment: "nuxt" } }, config)); resolvedConfig.extends ??= optOutOfExtends; return resolvedConfig; } const defineViteConfig = (config) => config; function defineVitestConfig(config = {}) { return defineViteConfig(async () => { const resolvedConfig = await resolveConfig(config); if (resolvedConfig.test.browser?.enabled) return resolvedConfig; if ("workspace" in resolvedConfig.test || "projects" in resolvedConfig.test) throw new Error("The `projects` option is not supported with `defineVitestConfig`. Instead, use `defineVitestProject` to define each workspace project that uses the Nuxt environment."); const defaultEnvironment = resolvedConfig.test.environment || "node"; if (defaultEnvironment !== "nuxt") { const merge = createDefu((obj, key, value) => { if (Array.isArray(value) && Array.isArray(obj[key])) { obj[key] = [.../* @__PURE__ */ new Set([...value, ...obj[key]])]; return true; } }); const nuxtProject = merge({ ...resolvedConfig, extends: optOutOfExtends, test: { ...resolvedConfig.test, name: "nuxt", environment: "nuxt", include: [] } }, resolvedConfig); nuxtProject.test.include = ["**/*.nuxt.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}", "{test,tests}/nuxt/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"]; const defaultProject = merge({ ...resolvedConfig, extends: optOutOfExtends, test: { ...resolvedConfig.test, name: defaultEnvironment, environment: defaultEnvironment, exclude: [ "**/node_modules/**", "**/dist/**", "**/cypress/**", "**/.{idea,git,cache,output,temp}/**", "**/{karma,rollup,webpack,vite,vitest,jest,ava,babel,nyc,cypress,tsup,build,eslint,prettier}.config.*", ...nuxtProject.test.include ] } }, resolvedConfig); delete resolvedConfig.test.name; delete resolvedConfig.test.environment; delete resolvedConfig.test.include; delete resolvedConfig.test.exclude; delete resolvedConfig.test.includeSource; delete defaultProject.test.includeSource; resolvedConfig.test.projects = [nuxtProject, defaultProject]; } return resolvedConfig; }); } function isCoverageEnabled(config) { if (config.test && "coverage" in config.test && config.test.coverage?.enabled) return true; return process.argv.some((arg) => arg === "--coverage" || arg === "--coverage.enabled" || arg === "--coverage=true" || arg === "--coverage.enabled=true"); } async function resolveConfig(config) { const overrides = config.test?.environmentOptions?.nuxt?.overrides || {}; overrides.rootDir = config.test?.environmentOptions?.nuxt?.rootDir; if (isCoverageEnabled(config)) { if (overrides.sourcemap === void 0) overrides.sourcemap = { client: true }; else if (typeof overrides.sourcemap === "object" && overrides.sourcemap.client === void 0) overrides.sourcemap.client = true; } if (config.test?.setupFiles && !Array.isArray(config.test.setupFiles)) config.test.setupFiles = [config.test.setupFiles].filter(Boolean); const resolvedConfig = defu$1(config, await getVitestConfigFromNuxt(void 0, { dotenv: config.test?.environmentOptions?.nuxt?.dotenv, nitroEnvironment: config.test?.environmentOptions?.nuxt?.nitroEnvironment, overrides: deepCopy(overrides) })); resolvedConfig.plugins.push(NuxtVitestEnvironmentOptionsPlugin(resolvedConfig.test.environmentOptions)); if (resolvedConfig.test.browser?.enabled) { if (vitestMajor >= 5) { delete resolvedConfig.optimizeDeps?.noDiscovery; resolvedConfig.optimizeDeps ??= {}; resolvedConfig.optimizeDeps.include ??= []; resolvedConfig.optimizeDeps.include.push("@testing-library/vue", "h3-next/generic"); } resolvedConfig.plugins.push({ name: "nuxt:test-utils:browser-client-environment", configEnvironment(name) { if (name === "client") return { dev: { moduleRunnerTransform: false } }; } }); if (resolvedConfig.test.environment === "nuxt") { resolvedConfig.test.setupFiles = Array.isArray(resolvedConfig.test.setupFiles) ? resolvedConfig.test.setupFiles : [resolvedConfig.test.setupFiles].filter(Boolean); const resolver = createResolver(import.meta.url); const browserEntry = await findPath(resolver.resolve("./runtime/browser-entry")) || resolver.resolve("./runtime/browser-entry"); resolvedConfig.test.setupFiles.unshift(browserEntry); } } return resolvedConfig; } //#endregion export { defineVitestConfig, defineVitestProject, getVitestConfigFromNuxt };