@nuxt/test-utils 3.8.1 → 3.9.0-alpha.2

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.
package/README.md CHANGED
@@ -1,68 +1,18 @@
1
- [![Nuxt banner](./.github/assets/banner.svg)](https://nuxt.com)
1
+ # Nuxt Test Utils
2
2
 
3
- # Nuxt
3
+ 🧪 [Nuxt](https://nuxt.com/) Test Utils
4
4
 
5
- <p>
6
- <a href="https://www.npmjs.com/package/nuxt"><img src="https://img.shields.io/npm/v/nuxt.svg?style=flat&colorA=18181B&colorB=28CF8D" alt="Version"></a>
7
- <a href="https://www.npmjs.com/package/nuxt"><img src="https://img.shields.io/npm/dm/nuxt.svg?style=flat&colorA=18181B&colorB=28CF8D" alt="Downloads"></a>
8
- <a href="./LICENSE"><img src="https://img.shields.io/github/license/nuxt/nuxt.svg?style=flat&colorA=18181B&colorB=28CF8D" alt="License"></a>
9
- <a href="https://nuxt.com"><img src="https://img.shields.io/badge/Nuxt%20Docs-18181B?logo=nuxt.js" alt="Website"></a>
10
- <a href="https://chat.nuxt.dev"><img src="https://img.shields.io/badge/Nuxt%20Discord-18181B?logo=discord" alt="Discord"></a>
11
- </p>
5
+ ## Overview
12
6
 
13
- Nuxt is a free and open-source framework with an intuitive and extendable way to create type-safe, performant and production-grade full-stack web applications and websites with Vue.js.
7
+ Nuxt offers first-class support for e2e and unit testing of your Nuxt applications.
14
8
 
15
- It provides a number of features that make it easy to build fast, SEO-friendly, and scalable web applications, including:
16
- - Server-side rendering, Static Site Generation or Hybrid Rendering
17
- - Automatic routing with code-splitting
18
- - State management
19
- - SEO Optimization
20
- - Extensible with [100+ modules](https://nuxt.com/modules)
21
- - Deployment to a variety of hosting platforms
22
- - ...[and much more](https://nuxt.com) 🚀
9
+ Nuxt Test Utils is currently powering [the tests we use on Nuxt itself](https://github.com/nuxt/nuxt/tree/main/test), as well as tests used throughout the module ecosystem.
23
10
 
24
- ## Getting Started
11
+ You can find out more about how to use Nuxt Test Utils:
25
12
 
26
- Use the following command to create a new starter project. This will create a starter project with all the necessary files and dependencies:
27
-
28
- ```bash
29
- npx nuxi@latest init <my-project>
30
- ```
31
-
32
- Discover also [nuxt.new](https://nuxt.new): Open a Nuxt starter on CodeSandbox, StackBlitz or locally to get up and running in a few seconds.
33
-
34
- ## Documentation
35
-
36
- We highly recommend you take a look at the [Nuxt documentation](https://nuxt.com/docs) to level up. It’s a great resource for learning more about the framework. It covers everything from getting started to advanced topics.
37
-
38
- ## Modules
39
-
40
- Discover our [list of modules](https://nuxt.com/modules) to supercharge your Nuxt project, created by the Nuxt team and community.
41
-
42
- ## Contribute
43
-
44
- We invite you to contribute and help improve Nuxt 💚
45
-
46
- Here are a few ways you can get involved:
47
- - **Reporting Bugs:** If you come across any bugs or issues, please check out the [reporting bugs guide](https://nuxt.com/docs/community/reporting-bugs) to learn how to submit a bug report.
48
- - **Suggestions:** Have ideas to enhance Nuxt? We'd love to hear them! Check out the [contribution guide](https://nuxt.com/docs/community/contribution#creating-an-issue) to share your suggestions.
49
- - **Questions:** If you have questions or need assistance, the [getting help guide](https://nuxt.com/docs/community/getting-help) provides resources to help you out.
50
-
51
- ## Local Development
52
-
53
- Follow the docs to [Set Up Your Local Development Environment](https://nuxt.com/docs/community/framework-contribution#setup) to contribute to the framework and documentation.
54
-
55
- ## Nuxt 2
56
-
57
- You can find the code for Nuxt 2 on the [`2.x` branch](https://github.com/nuxt/nuxt/tree/2.x) and the documentation at [v2.nuxt.com](https://v2.nuxt.com).
58
-
59
- ## Follow us
60
-
61
- <p valign="center">
62
- <a href="https://chat.nuxt.dev"><img width="20px" src="./.github/assets/discord.svg" alt="Discord"></a>&nbsp;&nbsp;<a href="https://twitter.nuxt.dev"><img width="20px" src="./.github/assets/twitter.svg" alt="Twitter"></a>&nbsp;&nbsp;<a href="https://github.nuxt.dev"><img width="20px" src="./.github/assets/github.svg" alt="GitHub"></a>
63
- </p>
13
+ - in [a general overview](https://nuxt.com/docs/getting-started/testing)
14
+ - in [an in-depth guide for module authors](https://nuxt.com/docs/guide/going-further/modules/#testing)
64
15
 
65
16
  ## License
66
17
 
67
18
  [MIT](./LICENSE)
68
-
package/config.d.ts ADDED
@@ -0,0 +1 @@
1
+ export * from './dist/config'
@@ -0,0 +1,58 @@
1
+ import * as vite from 'vite';
2
+ import { InlineConfig } from 'vite';
3
+ import { NuxtConfig, Nuxt } from '@nuxt/schema';
4
+ import { InlineConfig as InlineConfig$1 } from 'vitest';
5
+ import { DotenvOptions } from 'c12';
6
+
7
+ interface GetVitestConfigOptions {
8
+ nuxt: Nuxt;
9
+ viteConfig: InlineConfig;
10
+ }
11
+ interface LoadNuxtOptions {
12
+ dotenv?: Partial<DotenvOptions>;
13
+ overrides?: Partial<NuxtConfig>;
14
+ }
15
+ declare function getVitestConfigFromNuxt(options?: GetVitestConfigOptions, loadNuxtOptions?: LoadNuxtOptions): Promise<InlineConfig & {
16
+ test: InlineConfig$1;
17
+ }>;
18
+ declare function defineVitestConfig(config?: InlineConfig & {
19
+ test?: InlineConfig$1;
20
+ }): vite.UserConfig & Promise<vite.UserConfig> & vite.UserConfigFnObject & vite.UserConfigExport;
21
+ declare module 'vitest' {
22
+ interface EnvironmentOptions {
23
+ nuxt?: {
24
+ rootDir?: string;
25
+ /**
26
+ * The starting URL for your Nuxt window environment
27
+ * @default {http://localhost:3000}
28
+ */
29
+ url?: string;
30
+ /**
31
+ * You can define how environment options are read when loading the Nuxt configuration.
32
+ */
33
+ dotenv?: Partial<DotenvOptions>;
34
+ /**
35
+ * Configuration that will override the values in your `nuxt.config` file.
36
+ */
37
+ overrides?: NuxtConfig;
38
+ /**
39
+ * The id of the root div to which the app should be mounted. You should also set `app.rootId` to the same value.
40
+ * @default {nuxt-test}
41
+ */
42
+ rootId?: string;
43
+ /**
44
+ * The name of the DOM environment to use.
45
+ *
46
+ * It also needs to be installed as a dev dependency in your project.
47
+ * @default {happy-dom}
48
+ */
49
+ domEnvironment?: 'happy-dom' | 'jsdom';
50
+ mock?: {
51
+ intersectionObserver?: boolean;
52
+ indexedDb?: boolean;
53
+ };
54
+ };
55
+ }
56
+ }
57
+
58
+ export { defineVitestConfig, getVitestConfigFromNuxt };
@@ -0,0 +1,58 @@
1
+ import * as vite from 'vite';
2
+ import { InlineConfig } from 'vite';
3
+ import { NuxtConfig, Nuxt } from '@nuxt/schema';
4
+ import { InlineConfig as InlineConfig$1 } from 'vitest';
5
+ import { DotenvOptions } from 'c12';
6
+
7
+ interface GetVitestConfigOptions {
8
+ nuxt: Nuxt;
9
+ viteConfig: InlineConfig;
10
+ }
11
+ interface LoadNuxtOptions {
12
+ dotenv?: Partial<DotenvOptions>;
13
+ overrides?: Partial<NuxtConfig>;
14
+ }
15
+ declare function getVitestConfigFromNuxt(options?: GetVitestConfigOptions, loadNuxtOptions?: LoadNuxtOptions): Promise<InlineConfig & {
16
+ test: InlineConfig$1;
17
+ }>;
18
+ declare function defineVitestConfig(config?: InlineConfig & {
19
+ test?: InlineConfig$1;
20
+ }): vite.UserConfig & Promise<vite.UserConfig> & vite.UserConfigFnObject & vite.UserConfigExport;
21
+ declare module 'vitest' {
22
+ interface EnvironmentOptions {
23
+ nuxt?: {
24
+ rootDir?: string;
25
+ /**
26
+ * The starting URL for your Nuxt window environment
27
+ * @default {http://localhost:3000}
28
+ */
29
+ url?: string;
30
+ /**
31
+ * You can define how environment options are read when loading the Nuxt configuration.
32
+ */
33
+ dotenv?: Partial<DotenvOptions>;
34
+ /**
35
+ * Configuration that will override the values in your `nuxt.config` file.
36
+ */
37
+ overrides?: NuxtConfig;
38
+ /**
39
+ * The id of the root div to which the app should be mounted. You should also set `app.rootId` to the same value.
40
+ * @default {nuxt-test}
41
+ */
42
+ rootId?: string;
43
+ /**
44
+ * The name of the DOM environment to use.
45
+ *
46
+ * It also needs to be installed as a dev dependency in your project.
47
+ * @default {happy-dom}
48
+ */
49
+ domEnvironment?: 'happy-dom' | 'jsdom';
50
+ mock?: {
51
+ intersectionObserver?: boolean;
52
+ indexedDb?: boolean;
53
+ };
54
+ };
55
+ }
56
+ }
57
+
58
+ export { defineVitestConfig, getVitestConfigFromNuxt };
@@ -0,0 +1,205 @@
1
+ import { defineConfig } from 'vite';
2
+ import { setupDotenv } from 'c12';
3
+ import { defu } from 'defu';
4
+ import { createResolver } from '@nuxt/kit';
5
+ import destr from 'destr';
6
+ import { snakeCase } from 'scule';
7
+
8
+ function getEnv(key, opts) {
9
+ const env = opts.env ?? process.env;
10
+ const envKey = snakeCase(key).toUpperCase();
11
+ return destr(
12
+ env[opts.prefix + envKey] ?? env[opts.altPrefix + envKey]
13
+ );
14
+ }
15
+ function _isObject(input) {
16
+ return typeof input === "object" && !Array.isArray(input);
17
+ }
18
+ function applyEnv(obj, opts, parentKey = "") {
19
+ for (const key in obj) {
20
+ const subKey = parentKey ? `${parentKey}_${key}` : key;
21
+ const envValue = getEnv(subKey, opts);
22
+ if (_isObject(obj[key])) {
23
+ if (_isObject(envValue)) {
24
+ obj[key] = { ...obj[key], ...envValue };
25
+ applyEnv(obj[key], opts, subKey);
26
+ } else if (envValue === void 0) {
27
+ applyEnv(obj[key], opts, subKey);
28
+ } else {
29
+ obj[key] = envValue ?? obj[key];
30
+ }
31
+ } else {
32
+ obj[key] = envValue ?? obj[key];
33
+ }
34
+ }
35
+ return obj;
36
+ }
37
+
38
+ async function startNuxtAndGetViteConfig(rootDir = process.cwd(), options = {}) {
39
+ const { loadNuxt, buildNuxt } = await import('@nuxt/kit');
40
+ const nuxt = await loadNuxt({
41
+ cwd: rootDir,
42
+ dev: false,
43
+ dotenv: defu(options.dotenv, {
44
+ cwd: rootDir,
45
+ fileName: ".env.test"
46
+ }),
47
+ overrides: defu(
48
+ {
49
+ ssr: false,
50
+ test: true,
51
+ modules: ["@nuxt/test-utils/module"]
52
+ },
53
+ options.overrides
54
+ )
55
+ });
56
+ if (!nuxt.options._installedModules.find((i) => i?.meta?.name === "@nuxt/test-utils")) {
57
+ throw new Error(
58
+ "Failed to load `@nuxt/test-utils/module`. You may need to add it to your nuxt.config."
59
+ );
60
+ }
61
+ const promise = new Promise((resolve, reject) => {
62
+ nuxt.hook("vite:configResolved", (viteConfig, { isClient }) => {
63
+ if (isClient) {
64
+ resolve({ nuxt, viteConfig });
65
+ throw new Error("_stop_");
66
+ }
67
+ });
68
+ buildNuxt(nuxt).catch((err) => {
69
+ if (!err.toString().includes("_stop_")) {
70
+ reject(err);
71
+ }
72
+ });
73
+ }).finally(() => nuxt.close());
74
+ return promise;
75
+ }
76
+ const excludedPlugins = [
77
+ "nuxt:import-protection",
78
+ "vite-plugin-checker"
79
+ ];
80
+ async function getVitestConfigFromNuxt(options, loadNuxtOptions = {}) {
81
+ const { rootDir = process.cwd(), ..._overrides } = loadNuxtOptions.overrides || {};
82
+ if (!options) {
83
+ options = await startNuxtAndGetViteConfig(rootDir, {
84
+ dotenv: loadNuxtOptions.dotenv,
85
+ overrides: {
86
+ test: true,
87
+ ..._overrides
88
+ }
89
+ });
90
+ }
91
+ options.viteConfig.plugins = (options.viteConfig.plugins || []).filter((p) => !excludedPlugins.includes(p?.name));
92
+ const resolvedConfig = defu(
93
+ // overrides
94
+ {
95
+ define: {
96
+ ["process.env.NODE_ENV"]: "process.env.NODE_ENV"
97
+ },
98
+ test: {
99
+ dir: process.cwd(),
100
+ environmentOptions: {
101
+ nuxtRuntimeConfig: applyEnv(structuredClone(options.nuxt.options.runtimeConfig), {
102
+ prefix: "NUXT_",
103
+ env: await setupDotenv(defu(loadNuxtOptions.dotenv, {
104
+ cwd: rootDir,
105
+ fileName: ".env.test"
106
+ }))
107
+ }),
108
+ nuxtRouteRules: defu(
109
+ {},
110
+ options.nuxt.options.routeRules,
111
+ options.nuxt.options.nitro?.routeRules
112
+ )
113
+ },
114
+ environmentMatchGlobs: [
115
+ ["**/*.nuxt.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}", "nuxt"],
116
+ ["{test,tests}/nuxt/**.*", "nuxt"]
117
+ ],
118
+ server: {
119
+ deps: {
120
+ inline: [
121
+ // vite-node defaults
122
+ /\/node_modules\/(.*\/)?(nuxt|nuxt3|nuxt-nightly)\//,
123
+ /^#/,
124
+ // additional deps
125
+ "@nuxt/test-utils",
126
+ "@nuxt/test-utils-nightly",
127
+ "@nuxt/test-utils-edge",
128
+ "vitest-environment-nuxt",
129
+ ...options.nuxt.options.build.transpile.filter(
130
+ (r) => typeof r === "string" || r instanceof RegExp
131
+ )
132
+ ]
133
+ }
134
+ },
135
+ deps: {
136
+ optimizer: {
137
+ web: {
138
+ enabled: false
139
+ }
140
+ }
141
+ }
142
+ }
143
+ },
144
+ {
145
+ server: { middlewareMode: false },
146
+ plugins: [
147
+ {
148
+ name: "disable-auto-execute",
149
+ enforce: "pre",
150
+ transform(code, id) {
151
+ if (id.match(/nuxt(3|-nightly)?\/.*\/entry\./)) {
152
+ return code.replace(
153
+ /(?<!vueAppPromise = )entry\(\)/,
154
+ "Promise.resolve()"
155
+ );
156
+ }
157
+ }
158
+ }
159
+ ]
160
+ },
161
+ // resolved vite config
162
+ options.viteConfig,
163
+ // (overrideable) defaults
164
+ {
165
+ test: {
166
+ environmentOptions: {
167
+ nuxt: {
168
+ rootId: options.nuxt.options.app.rootId || void 0,
169
+ mock: {
170
+ intersectionObserver: true,
171
+ indexedDb: false
172
+ }
173
+ }
174
+ }
175
+ }
176
+ }
177
+ );
178
+ delete resolvedConfig.define["process.browser"];
179
+ if (!Array.isArray(resolvedConfig.test.setupFiles)) {
180
+ resolvedConfig.test.setupFiles = [resolvedConfig.test.setupFiles].filter(Boolean);
181
+ }
182
+ const resolver = createResolver(import.meta.url);
183
+ resolvedConfig.test.setupFiles.unshift(resolver.resolve("./runtime/entry"));
184
+ return resolvedConfig;
185
+ }
186
+ function defineVitestConfig(config = {}) {
187
+ return defineConfig(async () => {
188
+ if (process.env.__NUXT_VITEST_RESOLVED__)
189
+ return config;
190
+ const overrides = config.test?.environmentOptions?.nuxt?.overrides || {};
191
+ overrides.rootDir = config.test?.environmentOptions?.nuxt?.rootDir;
192
+ if (config.test?.setupFiles && !Array.isArray(config.test.setupFiles)) {
193
+ config.test.setupFiles = [config.test.setupFiles].filter(Boolean);
194
+ }
195
+ return defu(
196
+ config,
197
+ await getVitestConfigFromNuxt(void 0, {
198
+ dotenv: config.test?.environmentOptions?.nuxt?.dotenv,
199
+ overrides: structuredClone(overrides)
200
+ })
201
+ );
202
+ });
203
+ }
204
+
205
+ export { defineVitestConfig, getVitestConfigFromNuxt };
@@ -37,6 +37,11 @@ interface TestContext {
37
37
  url?: string;
38
38
  serverProcess?: ExecaChildProcess;
39
39
  mockFn?: Function;
40
+ /**
41
+ * Functions to run on the vitest `afterAll` hook.
42
+ * Useful for removing anything created during the test.
43
+ */
44
+ teardown?: (() => void)[];
40
45
  }
41
46
  interface TestHooks {
42
47
  beforeEach: () => void;
@@ -37,6 +37,11 @@ interface TestContext {
37
37
  url?: string;
38
38
  serverProcess?: ExecaChildProcess;
39
39
  mockFn?: Function;
40
+ /**
41
+ * Functions to run on the vitest `afterAll` hook.
42
+ * Useful for removing anything created during the test.
43
+ */
44
+ teardown?: (() => void)[];
40
45
  }
41
46
  interface TestHooks {
42
47
  beforeEach: () => void;
@@ -1,7 +1,7 @@
1
- import { u as useTestContext, a as url, c as createTestContext, s as setTestContext, b as stopServer, d as startServer } from './shared/test-utils.8f432eb9.mjs';
2
- export { $ as $fetch, e as exposeContextToEnv, f as fetch, i as isDev, r as recoverContextFromEnv } from './shared/test-utils.8f432eb9.mjs';
1
+ import { u as useTestContext, a as url, c as createTestContext, s as setTestContext, b as stopServer, d as startServer } from './shared/test-utils.B1uaYm8K.mjs';
2
+ export { $ as $fetch, e as exposeContextToEnv, f as fetch, i as isDev, r as recoverContextFromEnv } from './shared/test-utils.B1uaYm8K.mjs';
3
3
  import { consola } from 'consola';
4
- import { promises, existsSync } from 'node:fs';
4
+ import { existsSync, promises } from 'node:fs';
5
5
  import { resolve } from 'node:path';
6
6
  import { defu } from 'defu';
7
7
  import * as _kit from '@nuxt/kit';
@@ -15,7 +15,10 @@ async function createBrowser() {
15
15
  const ctx = useTestContext();
16
16
  let playwright;
17
17
  try {
18
- playwright = await import(String("playwright-core"));
18
+ playwright = await import(
19
+ /* vite-ignore */
20
+ 'playwright-core'
21
+ );
19
22
  } catch {
20
23
  throw new Error(`
21
24
  The dependency 'playwright-core' not found.
@@ -80,12 +83,12 @@ async function loadFixture() {
80
83
  ctx.options.rootDir = resolveRootDir();
81
84
  if (!ctx.options.dev) {
82
85
  const randomId = Math.random().toString(36).slice(2, 8);
83
- const buildDir = resolve(ctx.options.rootDir, ".nuxt", randomId);
86
+ const buildDir2 = ctx.options.buildDir || resolve(ctx.options.rootDir, ".nuxt", "test", randomId);
84
87
  ctx.options.nuxtConfig = defu(ctx.options.nuxtConfig, {
85
- buildDir,
88
+ buildDir: buildDir2,
86
89
  nitro: {
87
90
  output: {
88
- dir: resolve(buildDir, "output")
91
+ dir: resolve(buildDir2, "output")
89
92
  }
90
93
  }
91
94
  });
@@ -96,7 +99,12 @@ async function loadFixture() {
96
99
  overrides: ctx.options.nuxtConfig,
97
100
  configFile: ctx.options.configFile
98
101
  });
99
- await promises.mkdir(ctx.nuxt.options.buildDir, { recursive: true });
102
+ const buildDir = ctx.nuxt.options.buildDir;
103
+ if (!existsSync(buildDir)) {
104
+ await promises.mkdir(buildDir, { recursive: true });
105
+ ctx.teardown = ctx.teardown || [];
106
+ ctx.teardown.push(() => promises.rm(buildDir, { recursive: true, force: true }));
107
+ }
100
108
  }
101
109
  async function buildFixture() {
102
110
  const ctx = useTestContext();
@@ -148,6 +156,7 @@ function createTest(options) {
148
156
  if (ctx.browser) {
149
157
  await ctx.browser.close();
150
158
  }
159
+ await Promise.all((ctx.teardown || []).map((fn) => fn()));
151
160
  };
152
161
  const setup2 = async () => {
153
162
  if (ctx.options.fixture) {
@@ -218,6 +227,7 @@ async function runTests(opts) {
218
227
  inline: [
219
228
  distDir,
220
229
  "@nuxt/test-utils",
230
+ "@nuxt/test-utils-nightly",
221
231
  "@nuxt/test-utils-edge"
222
232
  ]
223
233
  },
@@ -1,6 +1,6 @@
1
1
  import { resolve } from 'pathe';
2
2
  import { stringifyQuery } from 'ufo';
3
- import { $ as $fetch, u as useTestContext } from './shared/test-utils.8f432eb9.mjs';
3
+ import { $ as $fetch, u as useTestContext } from './shared/test-utils.B1uaYm8K.mjs';
4
4
  import 'execa';
5
5
  import 'get-port-please';
6
6
  import 'ofetch';
@@ -0,0 +1,11 @@
1
+ import * as _nuxt_schema from '@nuxt/schema';
2
+ import { UserConfig } from 'vitest';
3
+
4
+ interface NuxtVitestOptions {
5
+ startOnBoot?: boolean;
6
+ logToConsole?: boolean;
7
+ vitestConfig?: UserConfig;
8
+ }
9
+ declare const _default: _nuxt_schema.NuxtModule<NuxtVitestOptions>;
10
+
11
+ export { type NuxtVitestOptions, _default as default };
@@ -0,0 +1,11 @@
1
+ import * as _nuxt_schema from '@nuxt/schema';
2
+ import { UserConfig } from 'vitest';
3
+
4
+ interface NuxtVitestOptions {
5
+ startOnBoot?: boolean;
6
+ logToConsole?: boolean;
7
+ vitestConfig?: UserConfig;
8
+ }
9
+ declare const _default: _nuxt_schema.NuxtModule<NuxtVitestOptions>;
10
+
11
+ export { type NuxtVitestOptions, _default as default };