@untestutils/nuxt 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/LICENSE +21 -0
  2. package/dist/config/index.d.mts +58 -0
  3. package/dist/config/index.d.ts +59 -0
  4. package/dist/config/index.d.ts.map +1 -0
  5. package/dist/config/index.mjs +323 -0
  6. package/dist/config/utils.d.mts +12 -0
  7. package/dist/config/utils.d.ts +13 -0
  8. package/dist/config/utils.d.ts.map +1 -0
  9. package/dist/config/utils.mjs +79 -0
  10. package/dist/environment/index.d.mts +22 -0
  11. package/dist/environment/index.d.ts +23 -0
  12. package/dist/environment/index.d.ts.map +1 -0
  13. package/dist/environment/index.mjs +129 -0
  14. package/dist/index.d.mts +36 -0
  15. package/dist/index.d.ts +65 -0
  16. package/dist/index.d.ts.map +1 -0
  17. package/dist/index.mjs +355 -0
  18. package/dist/module/index.d.mts +3 -0
  19. package/dist/module/index.d.ts +4 -0
  20. package/dist/module/index.d.ts.map +1 -0
  21. package/dist/module/index.mjs +294 -0
  22. package/dist/runtime/browser-entry.d.mts +5 -0
  23. package/dist/runtime/browser-entry.d.ts +6 -0
  24. package/dist/runtime/browser-entry.d.ts.map +1 -0
  25. package/dist/runtime/browser-entry.mjs +2 -0
  26. package/dist/runtime/entry.d.mts +1 -0
  27. package/dist/runtime/entry.d.ts +2 -0
  28. package/dist/runtime/entry.d.ts.map +1 -0
  29. package/dist/runtime/entry.mjs +9 -0
  30. package/dist/runtime/index.d.mts +81 -0
  31. package/dist/runtime/index.d.ts +82 -0
  32. package/dist/runtime/index.d.ts.map +1 -0
  33. package/dist/runtime/index.mjs +156 -0
  34. package/dist/runtime/mocks/vue-devtools.d.mts +12 -0
  35. package/dist/runtime/mocks/vue-devtools.d.ts +13 -0
  36. package/dist/runtime/mocks/vue-devtools.d.ts.map +1 -0
  37. package/dist/runtime/mocks/vue-devtools.mjs +12 -0
  38. package/dist/runtime/nuxt-root.d.mts +3 -0
  39. package/dist/runtime/nuxt-root.d.ts +4 -0
  40. package/dist/runtime/nuxt-root.d.ts.map +1 -0
  41. package/dist/runtime/nuxt-root.mjs +29 -0
  42. package/dist/runtime/shared/environment.d.mts +52 -0
  43. package/dist/runtime/shared/environment.d.ts +53 -0
  44. package/dist/runtime/shared/environment.d.ts.map +1 -0
  45. package/dist/runtime/shared/environment.mjs +79 -0
  46. package/dist/runtime/shared/h3-v1.d.mts +7 -0
  47. package/dist/runtime/shared/h3-v1.d.ts +8 -0
  48. package/dist/runtime/shared/h3-v1.d.ts.map +1 -0
  49. package/dist/runtime/shared/h3-v1.mjs +50 -0
  50. package/dist/runtime/shared/h3-v2.d.mts +7 -0
  51. package/dist/runtime/shared/h3-v2.d.ts +8 -0
  52. package/dist/runtime/shared/h3-v2.d.ts.map +1 -0
  53. package/dist/runtime/shared/h3-v2.mjs +32 -0
  54. package/dist/runtime/shared/h3.d.mts +4 -0
  55. package/dist/runtime/shared/h3.d.ts +5 -0
  56. package/dist/runtime/shared/h3.d.ts.map +1 -0
  57. package/dist/runtime/shared/h3.mjs +3 -0
  58. package/dist/runtime/shared/nuxt.d.mts +2 -0
  59. package/dist/runtime/shared/nuxt.d.ts +3 -0
  60. package/dist/runtime/shared/nuxt.d.ts.map +1 -0
  61. package/dist/runtime/shared/nuxt.mjs +17 -0
  62. package/dist/runtime/shared/vue-wrapper-plugin.d.mts +12 -0
  63. package/dist/runtime/shared/vue-wrapper-plugin.d.ts +13 -0
  64. package/dist/runtime/shared/vue-wrapper-plugin.d.ts.map +1 -0
  65. package/dist/runtime/shared/vue-wrapper-plugin.mjs +42 -0
  66. package/dist/runtime/suspended.d.mts +45 -0
  67. package/dist/runtime/suspended.d.ts +46 -0
  68. package/dist/runtime/suspended.d.ts.map +1 -0
  69. package/dist/runtime/suspended.mjs +259 -0
  70. package/package.json +150 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 s00d
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,58 @@
1
+ import type { Nuxt, NuxtConfig, ViteConfig as NuxtViteConfig } from "@nuxt/schema";
2
+ import type { DotenvOptions } from "c12";
3
+ import type { InlineConfig as VitestConfig } from "vitest/node";
4
+ import type { Plugin, UserConfig as ViteUserConfig } from "vite";
5
+ type NitroRef = {
6
+ current?: {
7
+ hooks: {
8
+ callHook: (name: "close") => Promise<void>;
9
+ };
10
+ };
11
+ };
12
+ type LoadedNuxtViteConfig = {
13
+ nuxt: Nuxt;
14
+ viteConfig: NuxtViteConfig;
15
+ nitro?: NitroRef;
16
+ };
17
+ type StartNuxtOptions = {
18
+ dotenv?: Partial<DotenvOptions>;
19
+ nitroEnvironment?: boolean;
20
+ overrides?: Partial<NuxtConfig>;
21
+ };
22
+ type ResolvedVitestConfig = ViteUserConfig & {
23
+ extends?: false;
24
+ test: VitestConfig;
25
+ plugins: Plugin[];
26
+ optimizeDeps?: {
27
+ noDiscovery?: boolean;
28
+ include?: string[];
29
+ };
30
+ define?: Record<string, unknown>;
31
+ ssr?: {
32
+ resolve?: {
33
+ conditions?: string[];
34
+ };
35
+ };
36
+ customLogger?: unknown;
37
+ };
38
+ export interface NuxtConfigOptions {
39
+ rootDir?: string;
40
+ domEnvironment?: "happy-dom" | "jsdom";
41
+ overrides?: Partial<NuxtConfig>;
42
+ dotenv?: Partial<DotenvOptions>;
43
+ nitroEnvironment?: boolean;
44
+ [key: string]: unknown;
45
+ }
46
+ export interface DefineVitestConfigInput extends ViteUserConfig {
47
+ test?: VitestConfig & {
48
+ environment?: string;
49
+ environmentOptions?: {
50
+ nuxt?: NuxtConfigOptions;
51
+ [key: string]: unknown;
52
+ };
53
+ };
54
+ }
55
+ export declare function getVitestConfigFromNuxt(options?: LoadedNuxtViteConfig, loadNuxtOptions?: StartNuxtOptions): Promise<ResolvedVitestConfig>;
56
+ export declare function defineVitestProject(config?: DefineVitestConfigInput): Promise<ResolvedVitestConfig>;
57
+ export declare function defineVitestConfig(config?: DefineVitestConfigInput): () => Promise<ResolvedVitestConfig>;
58
+ export {};
@@ -0,0 +1,59 @@
1
+ import type { Nuxt, NuxtConfig, ViteConfig as NuxtViteConfig } from '@nuxt/schema';
2
+ import type { DotenvOptions } from 'c12';
3
+ import type { InlineConfig as VitestConfig } from 'vitest/node';
4
+ import type { Plugin, UserConfig as ViteUserConfig } from 'vite';
5
+ type NitroRef = {
6
+ current?: {
7
+ hooks: {
8
+ callHook: (name: 'close') => Promise<void>;
9
+ };
10
+ };
11
+ };
12
+ type LoadedNuxtViteConfig = {
13
+ nuxt: Nuxt;
14
+ viteConfig: NuxtViteConfig;
15
+ nitro?: NitroRef;
16
+ };
17
+ type StartNuxtOptions = {
18
+ dotenv?: Partial<DotenvOptions>;
19
+ nitroEnvironment?: boolean;
20
+ overrides?: Partial<NuxtConfig>;
21
+ };
22
+ type ResolvedVitestConfig = ViteUserConfig & {
23
+ extends?: false;
24
+ test: VitestConfig;
25
+ plugins: Plugin[];
26
+ optimizeDeps?: {
27
+ noDiscovery?: boolean;
28
+ include?: string[];
29
+ };
30
+ define?: Record<string, unknown>;
31
+ ssr?: {
32
+ resolve?: {
33
+ conditions?: string[];
34
+ };
35
+ };
36
+ customLogger?: unknown;
37
+ };
38
+ export interface NuxtConfigOptions {
39
+ rootDir?: string;
40
+ domEnvironment?: 'happy-dom' | 'jsdom';
41
+ overrides?: Partial<NuxtConfig>;
42
+ dotenv?: Partial<DotenvOptions>;
43
+ nitroEnvironment?: boolean;
44
+ [key: string]: unknown;
45
+ }
46
+ export interface DefineVitestConfigInput extends ViteUserConfig {
47
+ test?: VitestConfig & {
48
+ environment?: string;
49
+ environmentOptions?: {
50
+ nuxt?: NuxtConfigOptions;
51
+ [key: string]: unknown;
52
+ };
53
+ };
54
+ }
55
+ export declare function getVitestConfigFromNuxt(options?: LoadedNuxtViteConfig, loadNuxtOptions?: StartNuxtOptions): Promise<ResolvedVitestConfig>;
56
+ export declare function defineVitestProject(config?: DefineVitestConfigInput): Promise<ResolvedVitestConfig>;
57
+ export declare function defineVitestConfig(config?: DefineVitestConfigInput): () => Promise<ResolvedVitestConfig>;
58
+ export {};
59
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,UAAU,IAAI,cAAc,EAAE,MAAM,cAAc,CAAC;AACnF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AACzC,OAAO,KAAK,EAAE,YAAY,IAAI,YAAY,EAAE,MAAM,aAAa,CAAC;AAChE,OAAO,KAAK,EAAE,MAAM,EAAE,UAAU,IAAI,cAAc,EAAkB,MAAM,MAAM,CAAC;AAWjF,KAAK,QAAQ,GAAG;IAAE,OAAO,CAAC,EAAE;QAAE,KAAK,EAAE;YAAE,QAAQ,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;SAAE,CAAA;KAAE,CAAA;CAAE,CAAC;AACxF,KAAK,oBAAoB,GAAG;IAC1B,IAAI,EAAE,IAAI,CAAC;IACX,UAAU,EAAE,cAAc,CAAC;IAC3B,KAAK,CAAC,EAAE,QAAQ,CAAC;CAClB,CAAC;AACF,KAAK,gBAAgB,GAAG;IACtB,MAAM,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;IAChC,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,SAAS,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;CACjC,CAAC;AACF,KAAK,oBAAoB,GAAG,cAAc,GAAG;IAC3C,OAAO,CAAC,EAAE,KAAK,CAAC;IAChB,IAAI,EAAE,YAAY,CAAC;IACnB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,YAAY,CAAC,EAAE;QAAE,WAAW,CAAC,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IAC7D,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,GAAG,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE;YAAE,UAAU,CAAC,EAAE,MAAM,EAAE,CAAA;SAAE,CAAA;KAAE,CAAC;IAC9C,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB,CAAC;AA6GF,MAAM,WAAW,iBAAiB;IAChC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC;IACvC,SAAS,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;IAChC,MAAM,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;IAChC,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,uBAAwB,SAAQ,cAAc;IAC7D,IAAI,CAAC,EAAE,YAAY,GAAG;QACpB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,kBAAkB,CAAC,EAAE;YAAE,IAAI,CAAC,EAAE,iBAAiB,CAAC;YAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;SAAE,CAAC;KAC3E,CAAC;CACH;AAED,wBAAsB,uBAAuB,CAC3C,OAAO,CAAC,EAAE,oBAAoB,EAC9B,eAAe,GAAE,gBAAqB,GACrC,OAAO,CAAC,oBAAoB,CAAC,CAuJ/B;AAKD,wBAAsB,mBAAmB,CAAC,MAAM,CAAC,EAAE,uBAAuB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAKzG;AAED,wBAAgB,kBAAkB,CAAC,MAAM,GAAE,uBAA4B,GAAG,MAAM,OAAO,CAAC,oBAAoB,CAAC,CAqE5G"}
@@ -0,0 +1,323 @@
1
+
2
+ import { deepCopy, loadKit, applyEnv } from "./utils.mjs";
3
+ import { createDefu, defu } from "defu";
4
+ import { resolveModulePath } from "exsolve";
5
+ import process from "node:process";
6
+ import { version } from "vitest/node";
7
+ import { setupDotenv } from "c12";
8
+ import { getPackageInfoSync } from "local-pkg";
9
+ import { fileURLToPath } from "node:url";
10
+
11
+ function runtimeFile(rel) {
12
+ return fileURLToPath(new URL(`../runtime/${rel}.mjs`, import.meta.url));
13
+ }
14
+ function isUnitEnvironmentName(env) {
15
+ return env === "untestutils" || env === "nuxt";
16
+ }
17
+ function isNamedPlugin(plugin) {
18
+ return typeof plugin === "object" && plugin !== null && "name" in plugin;
19
+ }
20
+ function warnIfE2ePluginMixed(config) {
21
+ const plugins = config.plugins || [];
22
+ const hasE2e = plugins.some((p) => isNamedPlugin(p) && p.name === "untestutils");
23
+ const env = config.test?.environment;
24
+ if (hasE2e && isUnitEnvironmentName(env)) {
25
+ console.warn("[untestutils] Do not mix `untestutils/vitest/plugin` (e2e) with `environment: 'untestutils'` (unit). Use separate projects.");
26
+ }
27
+ }
28
+ const PLUGIN_NAME = "untestutils:vitest:environment-options";
29
+ const STUB_ID = "untestutils-vitest-environment-options";
30
+ function NuxtVitestEnvironmentOptionsPlugin(environmentOptions = {}) {
31
+ return {
32
+ name: PLUGIN_NAME,
33
+ enforce: "pre",
34
+ resolveId(id) {
35
+ if (id.endsWith(STUB_ID)) return STUB_ID;
36
+ },
37
+ load(id) {
38
+ if (id.endsWith(STUB_ID)) return `export default ${JSON.stringify(environmentOptions || {})}`;
39
+ }
40
+ };
41
+ }
42
+ const DISABLE_NITRO_ENVIRONMENT = { experimental: { nitroViteEnvironment: false } };
43
+ async function startNuxtAndGetViteConfig(rootDir = process.cwd(), options = {}) {
44
+ const { buildNuxt, loadNuxt } = await loadKit(rootDir);
45
+ const nuxt = await loadNuxt({
46
+ cwd: rootDir,
47
+ dev: options.nitroEnvironment || (options.overrides?.dev ?? false),
48
+ dotenv: defu(options.dotenv, {
49
+ cwd: rootDir,
50
+ fileName: ".env.test"
51
+ }),
52
+ defaults: { compatibilityDate: "2024-04-03" },
53
+ overrides: defu({
54
+ appId: "nuxt-app",
55
+ buildId: "test",
56
+ ssr: false,
57
+ test: true,
58
+ modules: ["@untestutils/nuxt/module"],
59
+ experimental: { appManifest: false }
60
+ }, options.overrides, options.nitroEnvironment ? {} : DISABLE_NITRO_ENVIRONMENT)
61
+ });
62
+ if (!nuxt.options._installedModules.find((i) => i?.meta?.name === "untestutils")) throw new Error("Failed to load `@untestutils/nuxt/module`. Add it to your nuxt.config modules.");
63
+ const nitro = options.nitroEnvironment ? {} : undefined;
64
+ if (nitro) nuxt.hook("nitro:init", (instance) => {
65
+ nitro.current = instance;
66
+ });
67
+ return new Promise((resolve, reject) => {
68
+ nuxt.hook("vite:configResolved", (viteConfig, { isClient }) => {
69
+ if (isClient) {
70
+ resolve({
71
+ nuxt,
72
+ viteConfig,
73
+ nitro
74
+ });
75
+ throw new Error("_stop_");
76
+ }
77
+ });
78
+ buildNuxt(nuxt).catch((err) => {
79
+ if (!String(err).includes("_stop_")) reject(err);
80
+ });
81
+ }).finally(() => nuxt.close());
82
+ }
83
+ function nitroTeardownPlugin(nitro) {
84
+ let closed;
85
+ return {
86
+ name: "untestutils:nitro-teardown",
87
+ async closeBundle() {
88
+ closed ||= nitro.current?.hooks.callHook("close") ?? Promise.resolve();
89
+ await closed;
90
+ }
91
+ };
92
+ }
93
+ const excludedPlugins = [
94
+ "nuxt:import-protection",
95
+ "nuxt:import-conditions",
96
+ "nuxt:devtools:rpc",
97
+ "nuxt:devtools:config-retriever",
98
+ "vite-plugin-checker",
99
+ "vite-plugin-inspect",
100
+ "vite-plugin-vue-tracer"
101
+ ];
102
+ export async function getVitestConfigFromNuxt(options, loadNuxtOptions = {}) {
103
+ const { rootDir: rawRootDir = process.cwd(), ..._overrides } = loadNuxtOptions.overrides || {};
104
+ const rootDir = typeof rawRootDir === "string" ? rawRootDir : process.cwd();
105
+ if (!options) options = await startNuxtAndGetViteConfig(rootDir, {
106
+ dotenv: loadNuxtOptions.dotenv,
107
+ nitroEnvironment: loadNuxtOptions.nitroEnvironment,
108
+ overrides: {
109
+ test: true,
110
+ ..._overrides
111
+ }
112
+ });
113
+ const viteConfig = {
114
+ ...options.viteConfig,
115
+ root: undefined,
116
+ plugins: [...options.viteConfig.plugins || []].filter((p) => !isNamedPlugin(p) || !excludedPlugins.includes(p.name))
117
+ };
118
+ const nuxtServerIntegration = getPackageInfoSync("@nuxt/nitro-server", { paths: [options.nuxt.options.appDir] });
119
+ let nitroPath;
120
+ for (const nitroCandidate of [...nuxtServerIntegration?.packageJson.dependencies?.nitro ? ["nitro", "nitro-nightly"] : ["nitropack", "nitropack-nightly"]]) {
121
+ nitroPath = resolveModulePath(nitroCandidate, {
122
+ from: nuxtServerIntegration?.rootPath || options.nuxt.options.appDir,
123
+ try: true
124
+ });
125
+ if (nitroPath) break;
126
+ }
127
+ const projectH3Path = resolveModulePath("h3/package.json", {
128
+ from: rootDir,
129
+ try: true
130
+ });
131
+ const h3Info = (projectH3Path ? getPackageInfoSync("h3", { paths: [projectH3Path] }) : undefined) || getPackageInfoSync("h3", { paths: nitroPath ? [nitroPath] : options.nuxt.options.modulesDir });
132
+ const routeRules = "routeRules" in options.nuxt.options && isObjectRecord(options.nuxt.options.routeRules) ? options.nuxt.options.routeRules : undefined;
133
+ const nitroOptions = "nitro" in options.nuxt.options && isObjectRecord(options.nuxt.options.nitro) ? options.nuxt.options.nitro : undefined;
134
+ const resolvedConfig = defu({
135
+ define: {
136
+ "process.env.NODE_ENV": "\"test\"",
137
+ __NUXT_VITEST_RESOLVED__: "true"
138
+ },
139
+ resolve: { alias: {
140
+ "@vue/devtools-kit": runtimeFile("mocks/vue-devtools"),
141
+ "@vue/devtools-core": runtimeFile("mocks/vue-devtools")
142
+ } },
143
+ optimizeDeps: { noDiscovery: true },
144
+ test: {
145
+ environmentOptions: {
146
+ nuxtRuntimeConfig: applyEnv(deepCopy(options.nuxt.options.runtimeConfig), {
147
+ prefix: "NUXT_",
148
+ env: await setupDotenv(defu(loadNuxtOptions.dotenv, {
149
+ cwd: rootDir,
150
+ fileName: ".env.test"
151
+ }))
152
+ }),
153
+ nuxtRouteRules: defu({}, routeRules, isObjectRecord(nitroOptions?.routeRules) ? nitroOptions.routeRules : undefined),
154
+ nuxtAppConfig: {
155
+ rootAttrs: options.nuxt.options.app.rootAttrs,
156
+ rootTag: options.nuxt.options.app.rootTag,
157
+ teleportAttrs: options.nuxt.options.app.teleportAttrs,
158
+ teleportTag: options.nuxt.options.app.teleportTag
159
+ }
160
+ },
161
+ server: { deps: { inline: [
162
+ /\/node_modules\/(.*\/)?(nuxt|nuxt3|nuxt-nightly)\//,
163
+ /^#/,
164
+ "untestutils",
165
+ "@untestutils/nuxt",
166
+ "vitest-environment-untestutils",
167
+ ...options.nuxt.options.build.transpile.filter((r) => typeof r === "string" || r instanceof RegExp)
168
+ ] } },
169
+ deps: { optimizer: { client: { enabled: false } } }
170
+ }
171
+ }, {
172
+ server: { middlewareMode: false },
173
+ plugins: [
174
+ {
175
+ name: "disable-auto-execute",
176
+ enforce: "pre",
177
+ transform(code, id) {
178
+ if (id.match(/nuxt(3|-nightly)?\/.*\/entry\./)) return code.replace(/(?<!vueAppPromise = )entry\(\)/, "Promise.resolve()");
179
+ }
180
+ },
181
+ ...options.nitro ? [nitroTeardownPlugin(options.nitro)] : [],
182
+ {
183
+ name: "untestutils:browser-conditions",
184
+ enforce: "pre",
185
+ config() {
186
+ return { resolve: { conditions: [
187
+ "web",
188
+ "import",
189
+ "module",
190
+ "default"
191
+ ] } };
192
+ },
193
+ configResolved(config) {
194
+ if (config.ssr.resolve?.conditions) config.ssr.resolve.conditions = config.ssr.resolve.conditions.filter((x) => x !== "import");
195
+ }
196
+ }
197
+ ]
198
+ }, viteConfig, { test: { environmentOptions: { nuxt: {
199
+ rootId: options.nuxt.options.app.rootAttrs?.id || undefined,
200
+ h3Version: h3Info?.version?.startsWith("2.") ? 2 : 1,
201
+ mock: {
202
+ intersectionObserver: true,
203
+ indexedDb: false
204
+ }
205
+ } } } });
206
+ resolvedConfig.define ??= {};
207
+ delete resolvedConfig.define["process.browser"];
208
+ delete resolvedConfig.customLogger;
209
+ delete resolvedConfig.ssr;
210
+ resolvedConfig.test.setupFiles = normalizeSetupFiles(resolvedConfig.test.setupFiles);
211
+ resolvedConfig.test.setupFiles.unshift(runtimeFile("entry"));
212
+ return resolvedConfig;
213
+ }
214
+ const vitestMajor = Number(version.split(".")[0]);
215
+ const UNIT_ENVIRONMENT = "untestutils";
216
+ export async function defineVitestProject(config) {
217
+ const resolvedConfig = await resolveConfig(defu({ test: { environment: UNIT_ENVIRONMENT } }, config));
218
+ resolvedConfig.extends ??= false;
219
+ warnIfE2ePluginMixed(resolvedConfig);
220
+ return resolvedConfig;
221
+ }
222
+ export function defineVitestConfig(config = {}) {
223
+ return async () => {
224
+ const resolvedConfig = await resolveConfig(config);
225
+ if (resolvedConfig.test.browser?.enabled) return resolvedConfig;
226
+ if ("workspace" in resolvedConfig.test || "projects" in resolvedConfig.test) throw new Error("The `projects` option is not supported with `defineVitestConfig`. Use `defineVitestProject` per project.");
227
+ const defaultEnvironment = resolvedConfig.test.environment || "node";
228
+ const isUnitEnv = isUnitEnvironmentName(defaultEnvironment);
229
+ if (!isUnitEnv) {
230
+ const merge = createDefu((obj, key, value) => {
231
+ if (Array.isArray(value) && Array.isArray(obj[key])) {
232
+ const target = obj;
233
+ const stringKey = String(key);
234
+ target[stringKey] = [...new Set([...value, ...target[stringKey]])];
235
+ return true;
236
+ }
237
+ });
238
+ const nuxtProject = merge({
239
+ ...resolvedConfig,
240
+ extends: false,
241
+ test: {
242
+ ...resolvedConfig.test,
243
+ name: "untestutils",
244
+ environment: UNIT_ENVIRONMENT,
245
+ include: []
246
+ }
247
+ }, resolvedConfig);
248
+ nuxtProject.test.include = ["**/*.{nuxt,untestutils}.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}", "{test,tests}/{nuxt,untestutils}/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"];
249
+ const defaultProject = merge({
250
+ ...resolvedConfig,
251
+ extends: false,
252
+ test: {
253
+ ...resolvedConfig.test,
254
+ name: defaultEnvironment,
255
+ environment: defaultEnvironment,
256
+ exclude: [
257
+ "**/node_modules/**",
258
+ "**/dist/**",
259
+ "**/cypress/**",
260
+ "**/.{idea,git,cache,output,temp}/**",
261
+ "**/{karma,rollup,webpack,vite,vitest,jest,ava,babel,nyc,cypress,tsup,build,eslint,prettier}.config.*",
262
+ ...nuxtProject.test.include
263
+ ]
264
+ }
265
+ }, resolvedConfig);
266
+ delete resolvedConfig.test.name;
267
+ delete resolvedConfig.test.environment;
268
+ delete resolvedConfig.test.include;
269
+ delete resolvedConfig.test.exclude;
270
+ delete resolvedConfig.test.includeSource;
271
+ delete defaultProject.test.includeSource;
272
+ resolvedConfig.test.projects = [nuxtProject, defaultProject];
273
+ } else {
274
+ resolvedConfig.test.environment = UNIT_ENVIRONMENT;
275
+ }
276
+ warnIfE2ePluginMixed(resolvedConfig);
277
+ return resolvedConfig;
278
+ };
279
+ }
280
+ function isCoverageEnabled(config) {
281
+ if (config.test && "coverage" in config.test && config.test.coverage?.enabled) return true;
282
+ return process.argv.some((arg) => arg === "--coverage" || arg === "--coverage.enabled" || arg === "--coverage=true" || arg === "--coverage.enabled=true");
283
+ }
284
+ async function resolveConfig(config) {
285
+ const overrides = config.test?.environmentOptions?.nuxt?.overrides || {};
286
+ overrides.rootDir = config.test?.environmentOptions?.nuxt?.rootDir;
287
+ if (isCoverageEnabled(config)) {
288
+ if (overrides.sourcemap === undefined) overrides.sourcemap = { client: true };
289
+ else if (isObjectRecord(overrides.sourcemap) && overrides.sourcemap.client === undefined) overrides.sourcemap.client = true;
290
+ }
291
+ if (config.test?.setupFiles && !Array.isArray(config.test.setupFiles)) config.test.setupFiles = normalizeSetupFiles(config.test.setupFiles);
292
+ const resolvedConfig = defu(config, await getVitestConfigFromNuxt(undefined, {
293
+ dotenv: config.test?.environmentOptions?.nuxt?.dotenv,
294
+ nitroEnvironment: config.test?.environmentOptions?.nuxt?.nitroEnvironment,
295
+ overrides: deepCopy(overrides)
296
+ }));
297
+ resolvedConfig.plugins.push(NuxtVitestEnvironmentOptionsPlugin(resolvedConfig.test.environmentOptions));
298
+ if (resolvedConfig.test.browser?.enabled) {
299
+ if (vitestMajor >= 5) {
300
+ delete resolvedConfig.optimizeDeps?.noDiscovery;
301
+ resolvedConfig.optimizeDeps ??= {};
302
+ resolvedConfig.optimizeDeps.include ??= [];
303
+ resolvedConfig.optimizeDeps.include.push("@testing-library/vue", "h3-next/generic");
304
+ }
305
+ resolvedConfig.plugins.push({
306
+ name: "untestutils:browser-client-environment",
307
+ configEnvironment(name) {
308
+ if (name === "client") return { dev: { moduleRunnerTransform: false } };
309
+ }
310
+ });
311
+ if (resolvedConfig.test.environment === "untestutils") {
312
+ resolvedConfig.test.setupFiles = normalizeSetupFiles(resolvedConfig.test.setupFiles);
313
+ resolvedConfig.test.setupFiles.unshift(runtimeFile("browser-entry"));
314
+ }
315
+ }
316
+ return resolvedConfig;
317
+ }
318
+ function normalizeSetupFiles(setupFiles) {
319
+ return Array.isArray(setupFiles) ? setupFiles : [setupFiles].filter((file) => Boolean(file));
320
+ }
321
+ function isObjectRecord(value) {
322
+ return typeof value === "object" && value !== null;
323
+ }
@@ -0,0 +1,12 @@
1
+ export interface ApplyEnvOptions {
2
+ prefix: string;
3
+ altPrefix?: string;
4
+ env?: NodeJS.ProcessEnv;
5
+ }
6
+ export declare function applyEnv(obj: Record<string, unknown>, opts: ApplyEnvOptions, parentKey?: string): Record<string, unknown>;
7
+ /**
8
+ * Deep-copy plain objects and arrays, passing anything else through by reference.
9
+ * `structuredClone` throws on proxies/functions common in `nuxt.options`.
10
+ */
11
+ export declare function deepCopy<T>(input: T, seen?: WeakMap<object, unknown>): T;
12
+ export declare function loadKit(rootDir: string): Promise<typeof import("@nuxt/kit")>;
@@ -0,0 +1,13 @@
1
+ export interface ApplyEnvOptions {
2
+ prefix: string;
3
+ altPrefix?: string;
4
+ env?: NodeJS.ProcessEnv;
5
+ }
6
+ export declare function applyEnv(obj: Record<string, unknown>, opts: ApplyEnvOptions, parentKey?: string): Record<string, unknown>;
7
+ /**
8
+ * Deep-copy plain objects and arrays, passing anything else through by reference.
9
+ * `structuredClone` throws on proxies/functions common in `nuxt.options`.
10
+ */
11
+ export declare function deepCopy<T>(input: T, seen?: WeakMap<object, unknown>): T;
12
+ export declare function loadKit(rootDir: string): Promise<typeof import('@nuxt/kit')>;
13
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/config/utils.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CACzB;AAcD,wBAAgB,QAAQ,CACtB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC5B,IAAI,EAAE,eAAe,EACrB,SAAS,SAAK,GACb,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAczB;AAED;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,GAAE,OAAO,CAAC,MAAM,EAAE,OAAO,CAAkC,GAAG,CAAC,CAiBxG;AAED,wBAAsB,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,WAAW,CAAC,CAAC,CAsBlF"}
@@ -0,0 +1,79 @@
1
+ import { destr } from "destr";
2
+ import { snakeCase } from "scule";
3
+ import { pathToFileURL } from "node:url";
4
+ import { resolveModulePath } from "exsolve";
5
+ function getEnv(key, opts) {
6
+ const env = opts.env ?? process.env;
7
+ const envKey = snakeCase(key).toUpperCase();
8
+ return destr(env[opts.prefix + envKey] ?? (opts.altPrefix ? env[opts.altPrefix + envKey] : undefined));
9
+ }
10
+ function isPlainObject(input) {
11
+ return typeof input === "object" && input !== null && !Array.isArray(input);
12
+ }
13
+ export function applyEnv(obj, opts, parentKey = "") {
14
+ for (const key in obj) {
15
+ const subKey = parentKey ? `${parentKey}_${key}` : key;
16
+ const envValue = getEnv(subKey, opts);
17
+ if (isPlainObject(obj[key])) {
18
+ const child = obj[key];
19
+ if (isPlainObject(envValue)) {
20
+ obj[key] = {
21
+ ...child,
22
+ ...envValue
23
+ };
24
+ applyEnv(obj[key], opts, subKey);
25
+ } else if (envValue === undefined) applyEnv(child, opts, subKey);
26
+ else obj[key] = envValue ?? obj[key];
27
+ } else obj[key] = envValue ?? obj[key];
28
+ }
29
+ return obj;
30
+ }
31
+
32
+ export function deepCopy(input, seen = new WeakMap()) {
33
+ if (typeof input !== "object" || input === null) return input;
34
+ const proto = Object.getPrototypeOf(input);
35
+ if (proto !== Object.prototype && proto !== Array.prototype && proto !== null) return input;
36
+ const existing = seen.get(input);
37
+ if (existing) return existing;
38
+ if (Array.isArray(input)) {
39
+ const copy = [];
40
+ seen.set(input, copy);
41
+ for (const item of input) copy.push(deepCopy(item, seen));
42
+ return copy;
43
+ }
44
+ const copy = {};
45
+ seen.set(input, copy);
46
+ for (const key in input) copy[key] = deepCopy(input[key], seen);
47
+ return copy;
48
+ }
49
+ export async function loadKit(rootDir) {
50
+ try {
51
+ const kitPath = resolveModulePath("@nuxt/kit", { from: tryResolveNuxt(rootDir) || rootDir });
52
+ let kit = await import(pathToFileURL(kitPath).href);
53
+ if (!kit.writeTypes) kit = {
54
+ ...kit,
55
+ writeTypes: () => {
56
+ throw new Error("`writeTypes` is not available in this version of `@nuxt/kit`. Please upgrade to v3.7 or newer.");
57
+ }
58
+ };
59
+ return kit;
60
+ } catch (e) {
61
+ if (String(e).includes("Cannot find module '@nuxt/kit'")) throw new Error("`@untestutils/nuxt/config` requires `@nuxt/kit`. Install `nuxt` v3+ first.", { cause: e });
62
+ throw e;
63
+ }
64
+ }
65
+ function tryResolveNuxt(rootDir) {
66
+ for (const pkg of [
67
+ "nuxt-nightly",
68
+ "nuxt",
69
+ "nuxt3",
70
+ "nuxt-edge"
71
+ ]) {
72
+ const path = resolveModulePath(pkg, {
73
+ from: rootDir,
74
+ try: true
75
+ });
76
+ if (path) return path;
77
+ }
78
+ return null;
79
+ }
@@ -0,0 +1,22 @@
1
+ import { type EnvironmentOptions } from "../runtime/shared/environment.mjs";
2
+ type VitestGlobal = typeof globalThis & {
3
+ console: Console;
4
+ IntersectionObserver?: typeof IntersectionObserver;
5
+ };
6
+ type DomEnvironmentOptions = EnvironmentOptions & {
7
+ happyDom?: ConstructorParameters<typeof import("happy-dom").Window>[0];
8
+ jsdom?: ConstructorParameters<typeof import("jsdom").JSDOM>[1] & {
9
+ html?: string;
10
+ userAgent?: string;
11
+ console?: boolean;
12
+ cookieJar?: boolean;
13
+ };
14
+ };
15
+ declare const environment: {
16
+ name: string;
17
+ viteEnvironment: "client";
18
+ setup(global: VitestGlobal, environmentOptions: DomEnvironmentOptions): Promise<{
19
+ teardown: () => void;
20
+ }>;
21
+ };
22
+ export default environment;
@@ -0,0 +1,23 @@
1
+ import { type EnvironmentOptions } from '../runtime/shared/environment';
2
+ type VitestGlobal = typeof globalThis & {
3
+ console: Console;
4
+ IntersectionObserver?: typeof IntersectionObserver;
5
+ };
6
+ type DomEnvironmentOptions = EnvironmentOptions & {
7
+ happyDom?: ConstructorParameters<typeof import('happy-dom').Window>[0];
8
+ jsdom?: ConstructorParameters<typeof import('jsdom').JSDOM>[1] & {
9
+ html?: string;
10
+ userAgent?: string;
11
+ console?: boolean;
12
+ cookieJar?: boolean;
13
+ };
14
+ };
15
+ declare const environment: {
16
+ name: string;
17
+ viteEnvironment: "client";
18
+ setup(global: VitestGlobal, environmentOptions: DomEnvironmentOptions): Promise<{
19
+ teardown: () => void;
20
+ }>;
21
+ };
22
+ export default environment;
23
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/environment/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAEL,KAAK,kBAAkB,EAExB,MAAM,+BAA+B,CAAC;AAEvC,KAAK,YAAY,GAAG,OAAO,UAAU,GAAG;IACtC,OAAO,EAAE,OAAO,CAAC;IACjB,oBAAoB,CAAC,EAAE,OAAO,oBAAoB,CAAC;CACpD,CAAC;AACF,KAAK,qBAAqB,GAAG,kBAAkB,GAAG;IAChD,QAAQ,CAAC,EAAE,qBAAqB,CAAC,cAAc,WAAW,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IACvE,KAAK,CAAC,EAAE,qBAAqB,CAAC,cAAc,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG;QAC/D,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,SAAS,CAAC,EAAE,OAAO,CAAC;KACrB,CAAC;CACH,CAAC;AA6GF,QAAA,MAAM,WAAW;;;kBAIL,YAAY,sBACA,qBAAqB,GACxC,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,IAAI,CAAA;KAAE,CAAC;CAyDrC,CAAC;AAEF,eAAe,WAAW,CAAC"}