@nuxt/test-utils 3.17.2 → 3.19.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.
- package/README.md +1 -1
- package/dist/config.d.mts +13 -10
- package/dist/config.mjs +95 -25
- package/dist/e2e.d.mts +7 -3
- package/dist/e2e.mjs +3 -3
- package/dist/experimental.mjs +1 -1
- package/dist/module.d.mts +2 -1
- package/dist/module.mjs +7 -0
- package/dist/playwright.d.mts +3 -2
- package/dist/playwright.mjs +3 -3
- package/dist/runtime/browser-entry.d.ts +1 -0
- package/dist/runtime/browser-entry.mjs +8 -0
- package/dist/runtime/entry.mjs +2 -5
- package/dist/runtime/global-setup.mjs +1 -1
- package/dist/runtime/shared/environment.d.ts +7 -0
- package/dist/runtime/shared/environment.mjs +123 -0
- package/dist/runtime/shared/nuxt.d.ts +1 -0
- package/dist/runtime/shared/nuxt.mjs +7 -0
- package/dist/runtime-utils/index.mjs +62 -59
- package/dist/shared/{test-utils.CHPAu7TP.mjs → test-utils.B8qEdk9k.mjs} +3 -1
- package/dist/shared/{test-utils.BIDY1MqP.mjs → test-utils.CT3RJOY3.mjs} +17 -6
- package/dist/shared/{test-utils.DgnIK8xl.d.mts → test-utils.DtJCg4f3.d.mts} +8 -3
- package/dist/vitest-environment.d.mts +2 -1
- package/dist/vitest-environment.mjs +124 -107
- package/package.json +44 -40
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@ Nuxt Test Utils is currently powering [the tests we use on Nuxt itself](https://
|
|
|
11
11
|
You can find out more about how to use Nuxt Test Utils:
|
|
12
12
|
|
|
13
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
|
|
14
|
+
- in [an in-depth guide for module authors](https://nuxt.com/docs/guide/going-further/modules#testing)
|
|
15
15
|
|
|
16
16
|
## License
|
|
17
17
|
|
package/dist/config.d.mts
CHANGED
|
@@ -1,23 +1,25 @@
|
|
|
1
|
-
import * as
|
|
2
|
-
import { InlineConfig } from 'vite';
|
|
1
|
+
import * as vitest_config_js from 'vitest/config.js';
|
|
3
2
|
import { NuxtConfig, Nuxt } from '@nuxt/schema';
|
|
4
|
-
import { InlineConfig
|
|
3
|
+
import { InlineConfig } from 'vitest/node';
|
|
4
|
+
import { TestProjectInlineConfiguration } from 'vitest/config';
|
|
5
5
|
import { DotenvOptions } from 'c12';
|
|
6
|
+
import { UserConfig } from 'vite';
|
|
6
7
|
|
|
7
8
|
interface GetVitestConfigOptions {
|
|
8
9
|
nuxt: Nuxt;
|
|
9
|
-
viteConfig:
|
|
10
|
+
viteConfig: UserConfig;
|
|
10
11
|
}
|
|
11
12
|
interface LoadNuxtOptions {
|
|
12
13
|
dotenv?: Partial<DotenvOptions>;
|
|
13
14
|
overrides?: Partial<NuxtConfig>;
|
|
14
15
|
}
|
|
15
|
-
declare function getVitestConfigFromNuxt(options?: GetVitestConfigOptions, loadNuxtOptions?: LoadNuxtOptions): Promise<
|
|
16
|
-
test: InlineConfig
|
|
16
|
+
declare function getVitestConfigFromNuxt(options?: GetVitestConfigOptions, loadNuxtOptions?: LoadNuxtOptions): Promise<UserConfig & {
|
|
17
|
+
test: InlineConfig;
|
|
17
18
|
}>;
|
|
18
|
-
declare function
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
declare function defineVitestProject(config: TestProjectInlineConfiguration): Promise<TestProjectInlineConfiguration>;
|
|
20
|
+
declare function defineVitestConfig(config?: UserConfig & {
|
|
21
|
+
test?: InlineConfig;
|
|
22
|
+
}): vitest_config_js.UserConfigExport;
|
|
21
23
|
interface NuxtEnvironmentOptions {
|
|
22
24
|
rootDir?: string;
|
|
23
25
|
/**
|
|
@@ -61,4 +63,5 @@ declare module 'vitest' {
|
|
|
61
63
|
}
|
|
62
64
|
}
|
|
63
65
|
|
|
64
|
-
export { defineVitestConfig, getVitestConfigFromNuxt };
|
|
66
|
+
export { defineVitestConfig, defineVitestProject, getVitestConfigFromNuxt };
|
|
67
|
+
export type { NuxtEnvironmentOptions };
|
package/dist/config.mjs
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import
|
|
1
|
+
import process$1 from 'node:process';
|
|
2
|
+
import { defineConfig } from 'vitest/config';
|
|
2
3
|
import { setupDotenv } from 'c12';
|
|
3
4
|
import { defu } from 'defu';
|
|
4
|
-
import { createResolver } from '@nuxt/kit';
|
|
5
|
+
import { createResolver, findPath, loadNuxt, buildNuxt } from '@nuxt/kit';
|
|
5
6
|
import destr from 'destr';
|
|
6
7
|
import { snakeCase } from 'scule';
|
|
7
8
|
|
|
@@ -35,8 +36,7 @@ function applyEnv(obj, opts, parentKey = "") {
|
|
|
35
36
|
return obj;
|
|
36
37
|
}
|
|
37
38
|
|
|
38
|
-
async function startNuxtAndGetViteConfig(rootDir = process.cwd(), options = {}) {
|
|
39
|
-
const { loadNuxt, buildNuxt } = await import('@nuxt/kit');
|
|
39
|
+
async function startNuxtAndGetViteConfig(rootDir = process$1.cwd(), options = {}) {
|
|
40
40
|
const nuxt = await loadNuxt({
|
|
41
41
|
cwd: rootDir,
|
|
42
42
|
dev: false,
|
|
@@ -85,7 +85,7 @@ const excludedPlugins = [
|
|
|
85
85
|
"vite-plugin-checker"
|
|
86
86
|
];
|
|
87
87
|
async function getVitestConfigFromNuxt(options, loadNuxtOptions = {}) {
|
|
88
|
-
const { rootDir = process.cwd(), ..._overrides } = loadNuxtOptions.overrides || {};
|
|
88
|
+
const { rootDir = process$1.cwd(), ..._overrides } = loadNuxtOptions.overrides || {};
|
|
89
89
|
if (!options) {
|
|
90
90
|
options = await startNuxtAndGetViteConfig(rootDir, {
|
|
91
91
|
dotenv: loadNuxtOptions.dotenv,
|
|
@@ -100,10 +100,13 @@ async function getVitestConfigFromNuxt(options, loadNuxtOptions = {}) {
|
|
|
100
100
|
// overrides
|
|
101
101
|
{
|
|
102
102
|
define: {
|
|
103
|
-
|
|
103
|
+
"process.env.NODE_ENV": '"test"'
|
|
104
|
+
},
|
|
105
|
+
optimizeDeps: {
|
|
106
|
+
noDiscovery: true
|
|
104
107
|
},
|
|
105
108
|
test: {
|
|
106
|
-
dir: process.cwd(),
|
|
109
|
+
dir: process$1.cwd(),
|
|
107
110
|
environmentOptions: {
|
|
108
111
|
nuxtRuntimeConfig: applyEnv(structuredClone(options.nuxt.options.runtimeConfig), {
|
|
109
112
|
prefix: "NUXT_",
|
|
@@ -118,10 +121,6 @@ async function getVitestConfigFromNuxt(options, loadNuxtOptions = {}) {
|
|
|
118
121
|
options.nuxt.options.nitro?.routeRules
|
|
119
122
|
)
|
|
120
123
|
},
|
|
121
|
-
environmentMatchGlobs: [
|
|
122
|
-
["**/*.nuxt.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}", "nuxt"],
|
|
123
|
-
["{test,tests}/nuxt/**.*", "nuxt"]
|
|
124
|
-
],
|
|
125
124
|
server: {
|
|
126
125
|
deps: {
|
|
127
126
|
inline: [
|
|
@@ -152,6 +151,7 @@ async function getVitestConfigFromNuxt(options, loadNuxtOptions = {}) {
|
|
|
152
151
|
server: { middlewareMode: false },
|
|
153
152
|
plugins: [
|
|
154
153
|
{
|
|
154
|
+
// TODO: prefix with 'nuxt:test-utils:' in next major version
|
|
155
155
|
name: "disable-auto-execute",
|
|
156
156
|
enforce: "pre",
|
|
157
157
|
transform(code, id) {
|
|
@@ -162,6 +162,17 @@ async function getVitestConfigFromNuxt(options, loadNuxtOptions = {}) {
|
|
|
162
162
|
);
|
|
163
163
|
}
|
|
164
164
|
}
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
name: "nuxt:test-utils:browser-conditions",
|
|
168
|
+
enforce: "pre",
|
|
169
|
+
config() {
|
|
170
|
+
return {
|
|
171
|
+
resolve: {
|
|
172
|
+
conditions: ["web", "import", "module", "default"]
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
}
|
|
165
176
|
}
|
|
166
177
|
]
|
|
167
178
|
},
|
|
@@ -188,25 +199,84 @@ async function getVitestConfigFromNuxt(options, loadNuxtOptions = {}) {
|
|
|
188
199
|
resolvedConfig.test.setupFiles = [resolvedConfig.test.setupFiles].filter(Boolean);
|
|
189
200
|
}
|
|
190
201
|
const resolver = createResolver(import.meta.url);
|
|
191
|
-
|
|
202
|
+
const entryPath = resolver.resolve("./runtime/entry");
|
|
203
|
+
resolvedConfig.test.setupFiles.unshift(await findPath(entryPath) ?? entryPath);
|
|
204
|
+
return resolvedConfig;
|
|
205
|
+
}
|
|
206
|
+
async function defineVitestProject(config) {
|
|
207
|
+
if (process$1.env.__NUXT_VITEST_RESOLVED__) return config;
|
|
208
|
+
const resolvedConfig = await resolveConfig(config);
|
|
209
|
+
resolvedConfig.test.environment = "nuxt";
|
|
192
210
|
return resolvedConfig;
|
|
193
211
|
}
|
|
194
212
|
function defineVitestConfig(config = {}) {
|
|
195
213
|
return defineConfig(async () => {
|
|
196
|
-
if (process.env.__NUXT_VITEST_RESOLVED__) return config;
|
|
197
|
-
const
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
config.test.setupFiles = [config.test.setupFiles].filter(Boolean);
|
|
214
|
+
if (process$1.env.__NUXT_VITEST_RESOLVED__) return config;
|
|
215
|
+
const resolvedConfig = await resolveConfig(config);
|
|
216
|
+
if (resolvedConfig.test.browser?.enabled) {
|
|
217
|
+
return resolvedConfig;
|
|
201
218
|
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
)
|
|
219
|
+
if ("workspace" in resolvedConfig.test) {
|
|
220
|
+
throw new Error(
|
|
221
|
+
"The `workspace` option is not supported with `defineVitestConfig`. Instead, use `defineVitestProject` to define each workspace project that uses the Nuxt environment."
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
const defaultEnvironment = resolvedConfig.test.environment || "node";
|
|
225
|
+
if (defaultEnvironment !== "nuxt") {
|
|
226
|
+
resolvedConfig.test.workspace = [];
|
|
227
|
+
resolvedConfig.test.workspace.push({
|
|
228
|
+
extends: true,
|
|
229
|
+
test: {
|
|
230
|
+
name: "nuxt",
|
|
231
|
+
environment: "nuxt",
|
|
232
|
+
include: [
|
|
233
|
+
"**/*.nuxt.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}",
|
|
234
|
+
"{test,tests}/nuxt/**.*"
|
|
235
|
+
]
|
|
236
|
+
}
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
return resolvedConfig;
|
|
209
240
|
});
|
|
210
241
|
}
|
|
242
|
+
async function resolveConfig(config) {
|
|
243
|
+
const overrides = config.test?.environmentOptions?.nuxt?.overrides || {};
|
|
244
|
+
overrides.rootDir = config.test?.environmentOptions?.nuxt?.rootDir;
|
|
245
|
+
if (config.test?.setupFiles && !Array.isArray(config.test.setupFiles)) {
|
|
246
|
+
config.test.setupFiles = [config.test.setupFiles].filter(Boolean);
|
|
247
|
+
}
|
|
248
|
+
const resolvedConfig = defu(
|
|
249
|
+
config,
|
|
250
|
+
await getVitestConfigFromNuxt(void 0, {
|
|
251
|
+
dotenv: config.test?.environmentOptions?.nuxt?.dotenv,
|
|
252
|
+
overrides: structuredClone(overrides)
|
|
253
|
+
})
|
|
254
|
+
);
|
|
255
|
+
const PLUGIN_NAME = "nuxt:vitest:nuxt-environment-options";
|
|
256
|
+
const STUB_ID = "nuxt-vitest-environment-options";
|
|
257
|
+
resolvedConfig.plugins.push({
|
|
258
|
+
name: PLUGIN_NAME,
|
|
259
|
+
enforce: "pre",
|
|
260
|
+
resolveId(id) {
|
|
261
|
+
if (id.endsWith(STUB_ID)) {
|
|
262
|
+
return STUB_ID;
|
|
263
|
+
}
|
|
264
|
+
},
|
|
265
|
+
load(id) {
|
|
266
|
+
if (id.endsWith(STUB_ID)) {
|
|
267
|
+
return `export default ${JSON.stringify(resolvedConfig.test.environmentOptions || {})}`;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
});
|
|
271
|
+
if (resolvedConfig.test.browser?.enabled) {
|
|
272
|
+
if (resolvedConfig.test.environment === "nuxt") {
|
|
273
|
+
resolvedConfig.test.setupFiles = Array.isArray(resolvedConfig.test.setupFiles) ? resolvedConfig.test.setupFiles : [resolvedConfig.test.setupFiles].filter(Boolean);
|
|
274
|
+
const resolver = createResolver(import.meta.url);
|
|
275
|
+
const browserEntry = await findPath(resolver.resolve("./runtime/browser-entry")) || resolver.resolve("./runtime/browser-entry");
|
|
276
|
+
resolvedConfig.test.setupFiles.unshift(browserEntry);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
return resolvedConfig;
|
|
280
|
+
}
|
|
211
281
|
|
|
212
|
-
export { defineVitestConfig, getVitestConfigFromNuxt };
|
|
282
|
+
export { defineVitestConfig, defineVitestProject, getVitestConfigFromNuxt };
|
package/dist/e2e.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { T as TestOptions, a as TestContext, b as TestHooks } from './shared/test-utils.
|
|
2
|
-
export { $ as $fetch, G as GotoOptions, N as NuxtPage, S as StartServerOptions, h as TestRunner, c as createBrowser, d as createPage, f as fetch, g as getBrowser, s as startServer, e as stopServer, u as url, w as waitForHydration } from './shared/test-utils.
|
|
1
|
+
import { T as TestOptions, a as TestContext, b as TestHooks } from './shared/test-utils.DtJCg4f3.mjs';
|
|
2
|
+
export { $ as $fetch, G as GotoOptions, N as NuxtPage, S as StartServerOptions, h as TestRunner, c as createBrowser, d as createPage, f as fetch, g as getBrowser, s as startServer, e as stopServer, u as url, w as waitForHydration } from './shared/test-utils.DtJCg4f3.mjs';
|
|
3
3
|
import { LogType } from 'consola';
|
|
4
4
|
import 'playwright-core';
|
|
5
5
|
import '@nuxt/schema';
|
|
@@ -19,6 +19,8 @@ declare function mockLogger(): Record<LogType, (...args: unknown[]) => void>;
|
|
|
19
19
|
declare function loadFixture(): Promise<void>;
|
|
20
20
|
declare function buildFixture(): Promise<void>;
|
|
21
21
|
|
|
22
|
+
declare function setupBun(hooks: TestHooks): Promise<void>;
|
|
23
|
+
|
|
22
24
|
declare function setupCucumber(hooks: TestHooks): Promise<void>;
|
|
23
25
|
|
|
24
26
|
declare function setupJest(hooks: TestHooks): Promise<void>;
|
|
@@ -26,6 +28,7 @@ declare function setupJest(hooks: TestHooks): Promise<void>;
|
|
|
26
28
|
declare function setupVitest(hooks: TestHooks): Promise<void>;
|
|
27
29
|
|
|
28
30
|
declare const setupMaps: {
|
|
31
|
+
bun: typeof setupBun;
|
|
29
32
|
cucumber: typeof setupCucumber;
|
|
30
33
|
jest: typeof setupJest;
|
|
31
34
|
vitest: typeof setupVitest;
|
|
@@ -42,4 +45,5 @@ interface RunTestOptions {
|
|
|
42
45
|
}
|
|
43
46
|
declare function runTests(opts: RunTestOptions): Promise<void>;
|
|
44
47
|
|
|
45
|
-
export {
|
|
48
|
+
export { TestContext, TestHooks, TestOptions, buildFixture, createTest, createTestContext, exposeContextToEnv, isDev, loadFixture, mockFn, mockLogger, recoverContextFromEnv, runTests, setTestContext, setup, setupMaps, useTestContext };
|
|
49
|
+
export type { RunTestOptions };
|
package/dist/e2e.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export { b as buildFixture, c as createBrowser, a as createPage, d as createTest, g as getBrowser, l as loadFixture, e as setup, s as setupMaps, w as waitForHydration } from './shared/test-utils.
|
|
2
|
-
import { u as useTestContext } from './shared/test-utils.
|
|
3
|
-
export { $ as $fetch, c as createTestContext, e as exposeContextToEnv, f as fetch, i as isDev, r as recoverContextFromEnv, s as setTestContext, a as startServer, b as stopServer, d as url } from './shared/test-utils.
|
|
1
|
+
export { b as buildFixture, c as createBrowser, a as createPage, d as createTest, g as getBrowser, l as loadFixture, e as setup, s as setupMaps, w as waitForHydration } from './shared/test-utils.CT3RJOY3.mjs';
|
|
2
|
+
import { u as useTestContext } from './shared/test-utils.B8qEdk9k.mjs';
|
|
3
|
+
export { $ as $fetch, c as createTestContext, e as exposeContextToEnv, f as fetch, i as isDev, r as recoverContextFromEnv, s as setTestContext, a as startServer, b as stopServer, d as url } from './shared/test-utils.B8qEdk9k.mjs';
|
|
4
4
|
import { consola } from 'consola';
|
|
5
5
|
import { resolve } from 'pathe';
|
|
6
6
|
import { distDir } from '#dirs';
|
package/dist/experimental.mjs
CHANGED
|
@@ -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.
|
|
3
|
+
import { $ as $fetch, u as useTestContext } from './shared/test-utils.B8qEdk9k.mjs';
|
|
4
4
|
import 'tinyexec';
|
|
5
5
|
import 'get-port-please';
|
|
6
6
|
import 'ofetch';
|
package/dist/module.d.mts
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -12,6 +12,8 @@ import MagicString from 'magic-string';
|
|
|
12
12
|
import { createUnplugin } from 'unplugin';
|
|
13
13
|
import { readFileSync } from 'node:fs';
|
|
14
14
|
import { extname, join, dirname } from 'pathe';
|
|
15
|
+
import 'node:process';
|
|
16
|
+
import 'vitest/config';
|
|
15
17
|
import 'c12';
|
|
16
18
|
import 'destr';
|
|
17
19
|
import 'scule';
|
|
@@ -364,6 +366,11 @@ const module = defineNuxtModule({
|
|
|
364
366
|
viteConfig.plugins = (viteConfig.plugins || []).filter((p) => {
|
|
365
367
|
return !p || !("name" in p) || !vitePluginBlocklist.includes(p.name);
|
|
366
368
|
});
|
|
369
|
+
viteConfig.test.environmentMatchGlobs ||= [];
|
|
370
|
+
viteConfig.test.environmentMatchGlobs.push(
|
|
371
|
+
["**/*.nuxt.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}", "nuxt"],
|
|
372
|
+
["{test,tests}/nuxt/**.*", "nuxt"]
|
|
373
|
+
);
|
|
367
374
|
process.env.__NUXT_VITEST_RESOLVED__ = "true";
|
|
368
375
|
const { startVitest } = await import(pathToFileURL(await resolvePath("vitest/node")).href);
|
|
369
376
|
const customReporter = {
|
package/dist/playwright.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as _playwright_test from '@playwright/test';
|
|
2
2
|
export { expect } from '@playwright/test';
|
|
3
3
|
import { Response } from 'playwright-core';
|
|
4
|
-
import { T as TestOptions$1, G as GotoOptions, b as TestHooks } from './shared/test-utils.
|
|
4
|
+
import { T as TestOptions$1, G as GotoOptions, b as TestHooks } from './shared/test-utils.DtJCg4f3.mjs';
|
|
5
5
|
import '@nuxt/schema';
|
|
6
6
|
import 'tinyexec';
|
|
7
7
|
|
|
@@ -35,4 +35,5 @@ type TestOptions = {
|
|
|
35
35
|
*/
|
|
36
36
|
declare const test: _playwright_test.TestType<_playwright_test.PlaywrightTestArgs & _playwright_test.PlaywrightTestOptions & TestOptions, _playwright_test.PlaywrightWorkerArgs & _playwright_test.PlaywrightWorkerOptions & WorkerOptions & ConfigOptions>;
|
|
37
37
|
|
|
38
|
-
export {
|
|
38
|
+
export { test };
|
|
39
|
+
export type { ConfigOptions };
|
package/dist/playwright.mjs
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import defu from 'defu';
|
|
2
2
|
import { test as test$1 } from '@playwright/test';
|
|
3
3
|
export { expect } from '@playwright/test';
|
|
4
|
-
import { w as waitForHydration, d as createTest } from './shared/test-utils.
|
|
4
|
+
import { w as waitForHydration, d as createTest } from './shared/test-utils.CT3RJOY3.mjs';
|
|
5
5
|
import 'node:path';
|
|
6
6
|
import 'ufo';
|
|
7
7
|
import 'std-env';
|
|
8
8
|
import 'consola';
|
|
9
9
|
import 'node:fs';
|
|
10
10
|
import '@nuxt/kit';
|
|
11
|
-
import { d as url } from './shared/test-utils.
|
|
11
|
+
import { d as url } from './shared/test-utils.B8qEdk9k.mjs';
|
|
12
12
|
import 'pathe';
|
|
13
13
|
import '#dirs';
|
|
14
14
|
import 'tinyexec';
|
|
@@ -21,7 +21,7 @@ const test = test$1.extend({
|
|
|
21
21
|
_nuxtHooks: [
|
|
22
22
|
async ({ nuxt, defaults }, use) => {
|
|
23
23
|
const hooks = createTest(defu(nuxt || {}, defaults.nuxt || {}));
|
|
24
|
-
await hooks.
|
|
24
|
+
await hooks.beforeAll();
|
|
25
25
|
await use(hooks);
|
|
26
26
|
await hooks.afterAll();
|
|
27
27
|
},
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import environmentOptions from "nuxt-vitest-environment-options";
|
|
2
|
+
import { setupNuxt } from "./shared/nuxt.mjs";
|
|
3
|
+
import { setupWindow } from "./shared/environment.mjs";
|
|
4
|
+
const el = document.querySelector(environmentOptions.nuxt.rootId || "nuxt-test");
|
|
5
|
+
if (!el) {
|
|
6
|
+
await setupWindow(window, environmentOptions);
|
|
7
|
+
await setupNuxt();
|
|
8
|
+
}
|
package/dist/runtime/entry.mjs
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import { vi } from "vitest";
|
|
2
|
+
import { setupNuxt } from "./shared/nuxt.mjs";
|
|
2
3
|
if (typeof window !== "undefined" && window.__NUXT_VITEST_ENVIRONMENT__) {
|
|
3
|
-
|
|
4
|
-
await import("#app/nuxt-vitest-app-entry").then((r) => r.default());
|
|
5
|
-
const nuxtApp = useNuxtApp();
|
|
6
|
-
await nuxtApp.callHook("page:finish");
|
|
7
|
-
useRouter().afterEach(() => nuxtApp.callHook("page:finish"));
|
|
4
|
+
await setupNuxt();
|
|
8
5
|
vi.resetModules();
|
|
9
6
|
}
|
|
10
7
|
export {};
|
|
@@ -5,7 +5,7 @@ const options = JSON.parse(process.env.NUXT_TEST_OPTIONS || "{}");
|
|
|
5
5
|
const hooks = createTest(options);
|
|
6
6
|
export const setup = async () => {
|
|
7
7
|
kit.logger.info("Building Nuxt app...");
|
|
8
|
-
await hooks.
|
|
8
|
+
await hooks.beforeAll();
|
|
9
9
|
exposeContextToEnv();
|
|
10
10
|
kit.logger.info("Running tests...");
|
|
11
11
|
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { NuxtWindow } from '../../vitest-environment';
|
|
2
|
+
import type { NuxtEnvironmentOptions } from '../../config';
|
|
3
|
+
export declare function setupWindow(win: NuxtWindow, environmentOptions: {
|
|
4
|
+
nuxt: NuxtEnvironmentOptions;
|
|
5
|
+
nuxtRuntimeConfig?: Record<string, any>;
|
|
6
|
+
nuxtRouteRules?: Record<string, any>;
|
|
7
|
+
}): Promise<() => void>;
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { createFetch } from "ofetch";
|
|
2
|
+
import { joinURL } from "ufo";
|
|
3
|
+
import { createApp, defineEventHandler, toNodeListener } from "h3";
|
|
4
|
+
import { createRouter as createRadixRouter, exportMatcher, toRouteMatcher } from "radix3";
|
|
5
|
+
import { fetchNodeRequestHandler } from "node-mock-http";
|
|
6
|
+
export async function setupWindow(win, environmentOptions) {
|
|
7
|
+
win.__NUXT_VITEST_ENVIRONMENT__ = true;
|
|
8
|
+
win.__NUXT__ = {
|
|
9
|
+
serverRendered: false,
|
|
10
|
+
config: {
|
|
11
|
+
public: {},
|
|
12
|
+
app: { baseURL: "/" },
|
|
13
|
+
...environmentOptions?.nuxtRuntimeConfig
|
|
14
|
+
},
|
|
15
|
+
data: {},
|
|
16
|
+
state: {}
|
|
17
|
+
};
|
|
18
|
+
const rootId = environmentOptions.nuxt.rootId || "nuxt-test";
|
|
19
|
+
let el;
|
|
20
|
+
try {
|
|
21
|
+
el = win.document.querySelector(rootId);
|
|
22
|
+
} catch {
|
|
23
|
+
}
|
|
24
|
+
if (el) {
|
|
25
|
+
return () => {
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
const consoleInfo = console.info;
|
|
29
|
+
console.info = (...args) => {
|
|
30
|
+
if (args[0] === "<Suspense> is an experimental feature and its API will likely change.") {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
return consoleInfo(...args);
|
|
34
|
+
};
|
|
35
|
+
const app = win.document.createElement("div");
|
|
36
|
+
app.id = rootId;
|
|
37
|
+
win.document.body.appendChild(app);
|
|
38
|
+
const h3App = createApp();
|
|
39
|
+
if (!win.fetch) {
|
|
40
|
+
await import("node-fetch-native/polyfill");
|
|
41
|
+
win.URLSearchParams = globalThis.URLSearchParams;
|
|
42
|
+
}
|
|
43
|
+
const nodeHandler = toNodeListener(h3App);
|
|
44
|
+
const registry = /* @__PURE__ */ new Set();
|
|
45
|
+
win.fetch = async (url, init) => {
|
|
46
|
+
if (typeof url === "string") {
|
|
47
|
+
const base = url.split("?")[0];
|
|
48
|
+
if (registry.has(base) || registry.has(url)) {
|
|
49
|
+
url = "/_" + url;
|
|
50
|
+
}
|
|
51
|
+
if (url.startsWith("/")) {
|
|
52
|
+
const response = await fetchNodeRequestHandler(nodeHandler, url, init);
|
|
53
|
+
return normalizeFetchResponse(response);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return fetch(url, init);
|
|
57
|
+
};
|
|
58
|
+
win.$fetch = createFetch({ fetch: win.fetch, Headers: win.Headers });
|
|
59
|
+
win.__registry = registry;
|
|
60
|
+
win.__app = h3App;
|
|
61
|
+
const timestamp = Date.now();
|
|
62
|
+
const routeRulesMatcher = toRouteMatcher(
|
|
63
|
+
createRadixRouter({ routes: environmentOptions.nuxtRouteRules || {} })
|
|
64
|
+
);
|
|
65
|
+
const matcher = exportMatcher(routeRulesMatcher);
|
|
66
|
+
const manifestOutputPath = joinURL(
|
|
67
|
+
environmentOptions?.nuxtRuntimeConfig?.app?.baseURL || "/",
|
|
68
|
+
environmentOptions?.nuxtRuntimeConfig?.app?.buildAssetsDir || "_nuxt",
|
|
69
|
+
"builds"
|
|
70
|
+
);
|
|
71
|
+
const manifestBaseRoutePath = joinURL("/_", manifestOutputPath);
|
|
72
|
+
const buildId = win.__NUXT__.config?.app.buildId || "test";
|
|
73
|
+
h3App.use(
|
|
74
|
+
`${manifestBaseRoutePath}/latest.json`,
|
|
75
|
+
defineEventHandler(() => ({
|
|
76
|
+
id: buildId,
|
|
77
|
+
timestamp
|
|
78
|
+
}))
|
|
79
|
+
);
|
|
80
|
+
h3App.use(
|
|
81
|
+
`${manifestBaseRoutePath}/meta/${buildId}.json`,
|
|
82
|
+
defineEventHandler(() => ({
|
|
83
|
+
id: buildId,
|
|
84
|
+
timestamp,
|
|
85
|
+
matcher,
|
|
86
|
+
prerendered: []
|
|
87
|
+
}))
|
|
88
|
+
);
|
|
89
|
+
registry.add(`${manifestOutputPath}/latest.json`);
|
|
90
|
+
registry.add(`${manifestOutputPath}/meta/${buildId}.json`);
|
|
91
|
+
return () => {
|
|
92
|
+
console.info = consoleInfo;
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
function normalizeFetchResponse(response) {
|
|
96
|
+
if (!response.headers.has("set-cookie")) {
|
|
97
|
+
return response;
|
|
98
|
+
}
|
|
99
|
+
return new Response(response.body, {
|
|
100
|
+
status: response.status,
|
|
101
|
+
statusText: response.statusText,
|
|
102
|
+
headers: normalizeCookieHeaders(response.headers)
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
function normalizeCookieHeader(header = "") {
|
|
106
|
+
return splitCookiesString(joinHeaders(header));
|
|
107
|
+
}
|
|
108
|
+
function normalizeCookieHeaders(headers) {
|
|
109
|
+
const outgoingHeaders = new Headers();
|
|
110
|
+
for (const [name, header] of headers) {
|
|
111
|
+
if (name === "set-cookie") {
|
|
112
|
+
for (const cookie of normalizeCookieHeader(header)) {
|
|
113
|
+
outgoingHeaders.append("set-cookie", cookie);
|
|
114
|
+
}
|
|
115
|
+
} else {
|
|
116
|
+
outgoingHeaders.set(name, joinHeaders(header));
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return outgoingHeaders;
|
|
120
|
+
}
|
|
121
|
+
function joinHeaders(value) {
|
|
122
|
+
return Array.isArray(value) ? value.join(", ") : String(value);
|
|
123
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function setupNuxt(): Promise<void>;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export async function setupNuxt() {
|
|
2
|
+
const { useRouter } = await import("#app/composables/router");
|
|
3
|
+
await import("#app/nuxt-vitest-app-entry").then((r) => r.default());
|
|
4
|
+
const nuxtApp = useNuxtApp();
|
|
5
|
+
await nuxtApp.callHook("page:finish");
|
|
6
|
+
useRouter().afterEach(() => nuxtApp.callHook("page:finish"));
|
|
7
|
+
}
|
|
@@ -296,70 +296,73 @@ async function renderSuspended(component, options) {
|
|
|
296
296
|
// because there's no root element while Suspense is resolving
|
|
297
297
|
h$1(
|
|
298
298
|
WrapperComponent,
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
299
|
+
{},
|
|
300
|
+
{
|
|
301
|
+
default: () => h$1(
|
|
302
|
+
Suspense,
|
|
303
|
+
{
|
|
304
|
+
onResolve: () => nextTick().then(() => {
|
|
305
|
+
utils.setupState = setupState;
|
|
306
|
+
resolve(utils);
|
|
307
|
+
})
|
|
308
|
+
},
|
|
309
|
+
{
|
|
310
|
+
default: () => h$1({
|
|
311
|
+
name: "RenderHelper",
|
|
312
|
+
async setup() {
|
|
313
|
+
const router = useRouter();
|
|
314
|
+
await router.replace(route);
|
|
315
|
+
const clonedComponent = {
|
|
316
|
+
name: "RenderSuspendedComponent",
|
|
317
|
+
...component,
|
|
318
|
+
render: render ? function(_ctx, ...args) {
|
|
319
|
+
if (data && typeof data === "function") {
|
|
320
|
+
const dataObject = data();
|
|
321
|
+
for (const key in dataObject) {
|
|
322
|
+
renderContext[key] = dataObject[key];
|
|
323
|
+
}
|
|
321
324
|
}
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
325
|
+
for (const key in setupState || {}) {
|
|
326
|
+
const warn = console.warn;
|
|
327
|
+
console.warn = () => {
|
|
328
|
+
};
|
|
329
|
+
try {
|
|
330
|
+
renderContext[key] = isReadonly(setupState[key]) ? unref(setupState[key]) : setupState[key];
|
|
331
|
+
} catch {
|
|
332
|
+
} finally {
|
|
333
|
+
console.warn = warn;
|
|
334
|
+
}
|
|
335
|
+
if (key === "props") {
|
|
336
|
+
renderContext[key] = cloneProps(renderContext[key]);
|
|
337
|
+
}
|
|
332
338
|
}
|
|
333
|
-
|
|
334
|
-
|
|
339
|
+
const propsContext = "props" in renderContext ? renderContext.props : renderContext;
|
|
340
|
+
for (const key in props || {}) {
|
|
341
|
+
propsContext[key] = _ctx[key];
|
|
335
342
|
}
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
for (const key in props || {}) {
|
|
339
|
-
propsContext[key] = _ctx[key];
|
|
340
|
-
}
|
|
341
|
-
for (const key in passedProps || {}) {
|
|
342
|
-
propsContext[key] = passedProps[key];
|
|
343
|
-
}
|
|
344
|
-
if (methods && typeof methods === "object") {
|
|
345
|
-
for (const key in methods) {
|
|
346
|
-
renderContext[key] = methods[key].bind(renderContext);
|
|
343
|
+
for (const key in passedProps || {}) {
|
|
344
|
+
propsContext[key] = passedProps[key];
|
|
347
345
|
}
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
346
|
+
if (methods && typeof methods === "object") {
|
|
347
|
+
for (const key in methods) {
|
|
348
|
+
renderContext[key] = methods[key].bind(renderContext);
|
|
349
|
+
}
|
|
352
350
|
}
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
351
|
+
if (computed && typeof computed === "object") {
|
|
352
|
+
for (const key in computed) {
|
|
353
|
+
renderContext[key] = computed[key].call(renderContext);
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
return render.call(this, renderContext, ...args);
|
|
357
|
+
} : void 0,
|
|
358
|
+
setup: setup ? (props2) => wrappedSetup(props2, setupContext) : void 0
|
|
359
|
+
};
|
|
360
|
+
return () => h$1(clonedComponent, { ...props && typeof props === "object" ? props : {}, ...attrs }, slots);
|
|
361
|
+
}
|
|
362
|
+
})
|
|
363
|
+
}
|
|
364
|
+
)
|
|
365
|
+
}
|
|
363
366
|
)
|
|
364
367
|
)
|
|
365
368
|
},
|
|
@@ -5,7 +5,7 @@ import { resolve as resolve$1 } from 'pathe';
|
|
|
5
5
|
import { withTrailingSlash, joinURL } from 'ufo';
|
|
6
6
|
import { resolve } from 'node:path';
|
|
7
7
|
import { defu } from 'defu';
|
|
8
|
-
import { isWindows } from 'std-env';
|
|
8
|
+
import { isWindows, isBun } from 'std-env';
|
|
9
9
|
|
|
10
10
|
let currentContext;
|
|
11
11
|
function createTestContext(options) {
|
|
@@ -39,6 +39,8 @@ function createTestContext(options) {
|
|
|
39
39
|
_options.runner ||= "vitest";
|
|
40
40
|
} else if (process.env.JEST_WORKER_ID) {
|
|
41
41
|
_options.runner ||= "jest";
|
|
42
|
+
} else if (isBun) {
|
|
43
|
+
_options.runner ||= "bun";
|
|
42
44
|
}
|
|
43
45
|
return setTestContext({
|
|
44
46
|
options: _options,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { u as useTestContext, d as url, c as createTestContext, a as startServer, b as stopServer, s as setTestContext } from './test-utils.
|
|
1
|
+
import { u as useTestContext, d as url, c as createTestContext, a as startServer, b as stopServer, s as setTestContext } from './test-utils.B8qEdk9k.mjs';
|
|
2
2
|
import { existsSync, promises } from 'node:fs';
|
|
3
3
|
import { resolve } from 'node:path';
|
|
4
4
|
import { defu } from 'defu';
|
|
@@ -113,9 +113,18 @@ async function buildFixture() {
|
|
|
113
113
|
kit.logger.level = prevLevel;
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
+
async function setupBun(hooks) {
|
|
117
|
+
const bunTest = await import('bun:test');
|
|
118
|
+
hooks.ctx.mockFn = bunTest.mock;
|
|
119
|
+
bunTest.beforeAll(hooks.beforeAll);
|
|
120
|
+
bunTest.beforeEach(hooks.beforeEach);
|
|
121
|
+
bunTest.afterEach(hooks.afterEach);
|
|
122
|
+
bunTest.afterAll(hooks.afterAll);
|
|
123
|
+
}
|
|
124
|
+
|
|
116
125
|
async function setupCucumber(hooks) {
|
|
117
126
|
const { After, AfterAll, Before, BeforeAll } = await import('@cucumber/cucumber');
|
|
118
|
-
BeforeAll({ timeout: hooks.ctx.options.setupTimeout }, hooks.
|
|
127
|
+
BeforeAll({ timeout: hooks.ctx.options.setupTimeout }, hooks.beforeAll);
|
|
119
128
|
Before(hooks.beforeEach);
|
|
120
129
|
After(hooks.afterEach);
|
|
121
130
|
AfterAll(hooks.afterAll);
|
|
@@ -124,7 +133,7 @@ async function setupCucumber(hooks) {
|
|
|
124
133
|
async function setupJest(hooks) {
|
|
125
134
|
const { jest, test, beforeEach, afterAll, afterEach } = await import('@jest/globals');
|
|
126
135
|
hooks.ctx.mockFn = jest.fn;
|
|
127
|
-
test("setup", hooks.
|
|
136
|
+
test("setup", hooks.beforeAll, hooks.ctx.options.setupTimeout);
|
|
128
137
|
beforeEach(hooks.beforeEach);
|
|
129
138
|
afterEach(hooks.afterEach);
|
|
130
139
|
afterAll(hooks.afterAll, hooks.ctx.options.teardownTimeout);
|
|
@@ -133,13 +142,14 @@ async function setupJest(hooks) {
|
|
|
133
142
|
async function setupVitest(hooks) {
|
|
134
143
|
const vitest = await import('vitest');
|
|
135
144
|
hooks.ctx.mockFn = vitest.vi.fn;
|
|
136
|
-
vitest.beforeAll(hooks.
|
|
145
|
+
vitest.beforeAll(hooks.beforeAll, hooks.ctx.options.setupTimeout);
|
|
137
146
|
vitest.beforeEach(hooks.beforeEach);
|
|
138
147
|
vitest.afterEach(hooks.afterEach);
|
|
139
148
|
vitest.afterAll(hooks.afterAll, hooks.ctx.options.teardownTimeout);
|
|
140
149
|
}
|
|
141
150
|
|
|
142
151
|
const setupMaps = {
|
|
152
|
+
bun: setupBun,
|
|
143
153
|
cucumber: setupCucumber,
|
|
144
154
|
jest: setupJest,
|
|
145
155
|
vitest: setupVitest
|
|
@@ -166,7 +176,7 @@ function createTest(options) {
|
|
|
166
176
|
}
|
|
167
177
|
await Promise.all(!ctx.teardown ? [] : ctx.teardown.map((fn) => fn()));
|
|
168
178
|
};
|
|
169
|
-
const
|
|
179
|
+
const beforeAll = async () => {
|
|
170
180
|
if (ctx.options.fixture) {
|
|
171
181
|
await loadFixture();
|
|
172
182
|
}
|
|
@@ -187,7 +197,8 @@ function createTest(options) {
|
|
|
187
197
|
beforeEach,
|
|
188
198
|
afterEach,
|
|
189
199
|
afterAll,
|
|
190
|
-
|
|
200
|
+
beforeAll,
|
|
201
|
+
setup: beforeAll,
|
|
191
202
|
ctx
|
|
192
203
|
};
|
|
193
204
|
}
|
|
@@ -23,7 +23,7 @@ declare function fetch(path: string, options?: RequestInit): Promise<Response>;
|
|
|
23
23
|
declare const $fetch: (typeof globalThis)["$fetch"];
|
|
24
24
|
declare function url(path: string): string;
|
|
25
25
|
|
|
26
|
-
type TestRunner = 'vitest' | 'jest' | 'cucumber';
|
|
26
|
+
type TestRunner = 'vitest' | 'jest' | 'cucumber' | 'bun';
|
|
27
27
|
interface TestOptions {
|
|
28
28
|
testDir: string;
|
|
29
29
|
fixture: string;
|
|
@@ -62,7 +62,7 @@ interface TestOptions {
|
|
|
62
62
|
*/
|
|
63
63
|
browser: boolean;
|
|
64
64
|
/**
|
|
65
|
-
* Specify the runner for the test suite. One of `'vitest' | 'jest' | 'cucumber'`.
|
|
65
|
+
* Specify the runner for the test suite. One of `'vitest' | 'jest' | 'cucumber' | 'bun'`.
|
|
66
66
|
* @default `vitest`
|
|
67
67
|
*/
|
|
68
68
|
runner: TestRunner;
|
|
@@ -107,8 +107,13 @@ interface TestHooks {
|
|
|
107
107
|
beforeEach: () => void;
|
|
108
108
|
afterEach: () => void;
|
|
109
109
|
afterAll: () => Promise<void>;
|
|
110
|
+
beforeAll: () => Promise<void>;
|
|
111
|
+
/**
|
|
112
|
+
* @deprecated use `beforeAll` intead
|
|
113
|
+
*/
|
|
110
114
|
setup: () => Promise<void>;
|
|
111
115
|
ctx: TestContext;
|
|
112
116
|
}
|
|
113
117
|
|
|
114
|
-
export { $fetch as $,
|
|
118
|
+
export { $fetch as $, createBrowser as c, createPage as d, stopServer as e, fetch as f, getBrowser as g, startServer as s, url as u, waitForHydration as w };
|
|
119
|
+
export type { GotoOptions as G, NuxtPage as N, StartServerOptions as S, TestOptions as T, TestContext as a, TestHooks as b, TestRunner as h };
|
|
@@ -25,4 +25,5 @@ type EnvironmentNuxt = (global: typeof globalThis, options: EnvironmentNuxtOptio
|
|
|
25
25
|
teardown(): void;
|
|
26
26
|
}>;
|
|
27
27
|
|
|
28
|
-
export {
|
|
28
|
+
export { _default as default };
|
|
29
|
+
export type { EnvironmentNuxt, EnvironmentNuxtOptions, NuxtBuiltinEnvironment, NuxtWindow };
|
|
@@ -1,13 +1,132 @@
|
|
|
1
|
-
import { createFetch } from 'ofetch';
|
|
2
1
|
import { indexedDB } from 'fake-indexeddb';
|
|
3
2
|
import { joinURL } from 'ufo';
|
|
4
|
-
import { createApp, toNodeListener, defineEventHandler, splitCookiesString } from 'h3';
|
|
5
3
|
import defu from 'defu';
|
|
6
|
-
import { toRouteMatcher, createRouter, exportMatcher } from 'radix3';
|
|
7
4
|
import { populateGlobal } from 'vitest/environments';
|
|
5
|
+
import { createFetch } from 'ofetch';
|
|
6
|
+
import { createApp, toNodeListener, defineEventHandler } from 'h3';
|
|
7
|
+
import { toRouteMatcher, createRouter, exportMatcher } from 'radix3';
|
|
8
8
|
import { fetchNodeRequestHandler } from 'node-mock-http';
|
|
9
9
|
import { importModule } from 'local-pkg';
|
|
10
10
|
|
|
11
|
+
async function setupWindow(win, environmentOptions) {
|
|
12
|
+
win.__NUXT_VITEST_ENVIRONMENT__ = true;
|
|
13
|
+
win.__NUXT__ = {
|
|
14
|
+
serverRendered: false,
|
|
15
|
+
config: {
|
|
16
|
+
public: {},
|
|
17
|
+
app: { baseURL: "/" },
|
|
18
|
+
...environmentOptions?.nuxtRuntimeConfig
|
|
19
|
+
},
|
|
20
|
+
data: {},
|
|
21
|
+
state: {}
|
|
22
|
+
};
|
|
23
|
+
const rootId = environmentOptions.nuxt.rootId || "nuxt-test";
|
|
24
|
+
let el;
|
|
25
|
+
try {
|
|
26
|
+
el = win.document.querySelector(rootId);
|
|
27
|
+
} catch {
|
|
28
|
+
}
|
|
29
|
+
if (el) {
|
|
30
|
+
return () => {
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
const consoleInfo = console.info;
|
|
34
|
+
console.info = (...args) => {
|
|
35
|
+
if (args[0] === "<Suspense> is an experimental feature and its API will likely change.") {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
return consoleInfo(...args);
|
|
39
|
+
};
|
|
40
|
+
const app = win.document.createElement("div");
|
|
41
|
+
app.id = rootId;
|
|
42
|
+
win.document.body.appendChild(app);
|
|
43
|
+
const h3App = createApp();
|
|
44
|
+
if (!win.fetch) {
|
|
45
|
+
await import('node-fetch-native/polyfill');
|
|
46
|
+
win.URLSearchParams = globalThis.URLSearchParams;
|
|
47
|
+
}
|
|
48
|
+
const nodeHandler = toNodeListener(h3App);
|
|
49
|
+
const registry = /* @__PURE__ */ new Set();
|
|
50
|
+
win.fetch = async (url, init) => {
|
|
51
|
+
if (typeof url === "string") {
|
|
52
|
+
const base = url.split("?")[0];
|
|
53
|
+
if (registry.has(base) || registry.has(url)) {
|
|
54
|
+
url = "/_" + url;
|
|
55
|
+
}
|
|
56
|
+
if (url.startsWith("/")) {
|
|
57
|
+
const response = await fetchNodeRequestHandler(nodeHandler, url, init);
|
|
58
|
+
return normalizeFetchResponse(response);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return fetch(url, init);
|
|
62
|
+
};
|
|
63
|
+
win.$fetch = createFetch({ fetch: win.fetch, Headers: win.Headers });
|
|
64
|
+
win.__registry = registry;
|
|
65
|
+
win.__app = h3App;
|
|
66
|
+
const timestamp = Date.now();
|
|
67
|
+
const routeRulesMatcher = toRouteMatcher(
|
|
68
|
+
createRouter({ routes: environmentOptions.nuxtRouteRules || {} })
|
|
69
|
+
);
|
|
70
|
+
const matcher = exportMatcher(routeRulesMatcher);
|
|
71
|
+
const manifestOutputPath = joinURL(
|
|
72
|
+
environmentOptions?.nuxtRuntimeConfig?.app?.baseURL || "/",
|
|
73
|
+
environmentOptions?.nuxtRuntimeConfig?.app?.buildAssetsDir || "_nuxt",
|
|
74
|
+
"builds"
|
|
75
|
+
);
|
|
76
|
+
const manifestBaseRoutePath = joinURL("/_", manifestOutputPath);
|
|
77
|
+
const buildId = win.__NUXT__.config?.app.buildId || "test";
|
|
78
|
+
h3App.use(
|
|
79
|
+
`${manifestBaseRoutePath}/latest.json`,
|
|
80
|
+
defineEventHandler(() => ({
|
|
81
|
+
id: buildId,
|
|
82
|
+
timestamp
|
|
83
|
+
}))
|
|
84
|
+
);
|
|
85
|
+
h3App.use(
|
|
86
|
+
`${manifestBaseRoutePath}/meta/${buildId}.json`,
|
|
87
|
+
defineEventHandler(() => ({
|
|
88
|
+
id: buildId,
|
|
89
|
+
timestamp,
|
|
90
|
+
matcher,
|
|
91
|
+
prerendered: []
|
|
92
|
+
}))
|
|
93
|
+
);
|
|
94
|
+
registry.add(`${manifestOutputPath}/latest.json`);
|
|
95
|
+
registry.add(`${manifestOutputPath}/meta/${buildId}.json`);
|
|
96
|
+
return () => {
|
|
97
|
+
console.info = consoleInfo;
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
function normalizeFetchResponse(response) {
|
|
101
|
+
if (!response.headers.has("set-cookie")) {
|
|
102
|
+
return response;
|
|
103
|
+
}
|
|
104
|
+
return new Response(response.body, {
|
|
105
|
+
status: response.status,
|
|
106
|
+
statusText: response.statusText,
|
|
107
|
+
headers: normalizeCookieHeaders(response.headers)
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
function normalizeCookieHeader(header = "") {
|
|
111
|
+
return splitCookiesString(joinHeaders(header));
|
|
112
|
+
}
|
|
113
|
+
function normalizeCookieHeaders(headers) {
|
|
114
|
+
const outgoingHeaders = new Headers();
|
|
115
|
+
for (const [name, header] of headers) {
|
|
116
|
+
if (name === "set-cookie") {
|
|
117
|
+
for (const cookie of normalizeCookieHeader(header)) {
|
|
118
|
+
outgoingHeaders.append("set-cookie", cookie);
|
|
119
|
+
}
|
|
120
|
+
} else {
|
|
121
|
+
outgoingHeaders.set(name, joinHeaders(header));
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return outgoingHeaders;
|
|
125
|
+
}
|
|
126
|
+
function joinHeaders(value) {
|
|
127
|
+
return Array.isArray(value) ? value.join(", ") : String(value);
|
|
128
|
+
}
|
|
129
|
+
|
|
11
130
|
const happyDom = (async function(_, { happyDom = {} }) {
|
|
12
131
|
const { Window, GlobalWindow } = await importModule("happy-dom");
|
|
13
132
|
const window = new (GlobalWindow || Window)(happyDom);
|
|
@@ -58,33 +177,12 @@ const index = {
|
|
|
58
177
|
environmentOptions?.nuxt.url ?? "http://localhost:3000",
|
|
59
178
|
environmentOptions?.nuxtRuntimeConfig.app?.baseURL || "/"
|
|
60
179
|
);
|
|
61
|
-
const consoleInfo = console.info;
|
|
62
|
-
console.info = (...args) => {
|
|
63
|
-
if (args[0] === "<Suspense> is an experimental feature and its API will likely change.") {
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
return consoleInfo(...args);
|
|
67
|
-
};
|
|
68
180
|
const environmentName = environmentOptions.nuxt.domEnvironment;
|
|
69
181
|
const environment = environmentMap[environmentName] || environmentMap["happy-dom"];
|
|
70
182
|
const { window: win, teardown } = await environment(global, defu(environmentOptions, {
|
|
71
183
|
happyDom: { url },
|
|
72
184
|
jsdom: { url }
|
|
73
185
|
}));
|
|
74
|
-
win.__NUXT_VITEST_ENVIRONMENT__ = true;
|
|
75
|
-
win.__NUXT__ = {
|
|
76
|
-
serverRendered: false,
|
|
77
|
-
config: {
|
|
78
|
-
public: {},
|
|
79
|
-
app: { baseURL: "/" },
|
|
80
|
-
...environmentOptions?.nuxtRuntimeConfig
|
|
81
|
-
},
|
|
82
|
-
data: {},
|
|
83
|
-
state: {}
|
|
84
|
-
};
|
|
85
|
-
const app = win.document.createElement("div");
|
|
86
|
-
app.id = environmentOptions.nuxt.rootId;
|
|
87
|
-
win.document.body.appendChild(app);
|
|
88
186
|
if (environmentOptions?.nuxt?.mock?.intersectionObserver) {
|
|
89
187
|
win.IntersectionObserver = win.IntersectionObserver || class IntersectionObserver {
|
|
90
188
|
observe() {
|
|
@@ -98,101 +196,20 @@ const index = {
|
|
|
98
196
|
if (environmentOptions?.nuxt?.mock?.indexedDb) {
|
|
99
197
|
win.indexedDB = indexedDB;
|
|
100
198
|
}
|
|
101
|
-
const
|
|
102
|
-
if (!win.fetch) {
|
|
103
|
-
await import('node-fetch-native/polyfill');
|
|
104
|
-
win.URLSearchParams = globalThis.URLSearchParams;
|
|
105
|
-
}
|
|
106
|
-
const nodeHandler = toNodeListener(h3App);
|
|
107
|
-
const registry = /* @__PURE__ */ new Set();
|
|
108
|
-
win.fetch = async (url2, init) => {
|
|
109
|
-
if (typeof url2 === "string") {
|
|
110
|
-
const base = url2.split("?")[0];
|
|
111
|
-
if (registry.has(base) || registry.has(url2)) {
|
|
112
|
-
url2 = "/_" + url2;
|
|
113
|
-
}
|
|
114
|
-
if (url2.startsWith("/")) {
|
|
115
|
-
const response = await fetchNodeRequestHandler(nodeHandler, url2, init);
|
|
116
|
-
return normalizeFetchResponse(response);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
return fetch(url2, init);
|
|
120
|
-
};
|
|
121
|
-
win.$fetch = createFetch({ fetch: win.fetch, Headers: win.Headers });
|
|
122
|
-
win.__registry = registry;
|
|
123
|
-
win.__app = h3App;
|
|
199
|
+
const teardownWindow = await setupWindow(win, environmentOptions);
|
|
124
200
|
const { keys, originals } = populateGlobal(global, win, {
|
|
125
201
|
bindFunctions: true
|
|
126
202
|
});
|
|
127
|
-
const timestamp = Date.now();
|
|
128
|
-
const routeRulesMatcher = toRouteMatcher(
|
|
129
|
-
createRouter({ routes: environmentOptions.nuxtRouteRules || {} })
|
|
130
|
-
);
|
|
131
|
-
const matcher = exportMatcher(routeRulesMatcher);
|
|
132
|
-
const manifestOutputPath = joinURL(
|
|
133
|
-
"/",
|
|
134
|
-
environmentOptions?.nuxtRuntimeConfig.app?.buildAssetsDir || "_nuxt",
|
|
135
|
-
"builds"
|
|
136
|
-
);
|
|
137
|
-
const manifestBaseRoutePath = joinURL("/_", manifestOutputPath);
|
|
138
|
-
const buildId = win.__NUXT__.config.app.buildId || "test";
|
|
139
|
-
h3App.use(
|
|
140
|
-
`${manifestBaseRoutePath}/latest.json`,
|
|
141
|
-
defineEventHandler(() => ({
|
|
142
|
-
id: buildId,
|
|
143
|
-
timestamp
|
|
144
|
-
}))
|
|
145
|
-
);
|
|
146
|
-
h3App.use(
|
|
147
|
-
`${manifestBaseRoutePath}/meta/${buildId}.json`,
|
|
148
|
-
defineEventHandler(() => ({
|
|
149
|
-
id: buildId,
|
|
150
|
-
timestamp,
|
|
151
|
-
matcher,
|
|
152
|
-
prerendered: []
|
|
153
|
-
}))
|
|
154
|
-
);
|
|
155
|
-
registry.add(`${manifestOutputPath}/latest.json`);
|
|
156
|
-
registry.add(`${manifestOutputPath}/meta/${buildId}.json`);
|
|
157
203
|
return {
|
|
158
204
|
// called after all tests with this env have been run
|
|
159
205
|
teardown() {
|
|
160
206
|
keys.forEach((key) => delete global[key]);
|
|
161
|
-
|
|
207
|
+
teardownWindow();
|
|
162
208
|
originals.forEach((v, k) => global[k] = v);
|
|
163
209
|
teardown();
|
|
164
210
|
}
|
|
165
211
|
};
|
|
166
212
|
}
|
|
167
213
|
};
|
|
168
|
-
function normalizeFetchResponse(response) {
|
|
169
|
-
if (!response.headers.has("set-cookie")) {
|
|
170
|
-
return response;
|
|
171
|
-
}
|
|
172
|
-
return new Response(response.body, {
|
|
173
|
-
status: response.status,
|
|
174
|
-
statusText: response.statusText,
|
|
175
|
-
headers: normalizeCookieHeaders(response.headers)
|
|
176
|
-
});
|
|
177
|
-
}
|
|
178
|
-
function normalizeCookieHeader(header = "") {
|
|
179
|
-
return splitCookiesString(joinHeaders(header));
|
|
180
|
-
}
|
|
181
|
-
function normalizeCookieHeaders(headers) {
|
|
182
|
-
const outgoingHeaders = new Headers();
|
|
183
|
-
for (const [name, header] of headers) {
|
|
184
|
-
if (name === "set-cookie") {
|
|
185
|
-
for (const cookie of normalizeCookieHeader(header)) {
|
|
186
|
-
outgoingHeaders.append("set-cookie", cookie);
|
|
187
|
-
}
|
|
188
|
-
} else {
|
|
189
|
-
outgoingHeaders.set(name, joinHeaders(header));
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
return outgoingHeaders;
|
|
193
|
-
}
|
|
194
|
-
function joinHeaders(value) {
|
|
195
|
-
return Array.isArray(value) ? value.join(", ") : String(value);
|
|
196
|
-
}
|
|
197
214
|
|
|
198
215
|
export { index as default };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nuxt/test-utils",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.19.0",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/nuxt/test-utils.git"
|
|
@@ -63,16 +63,16 @@
|
|
|
63
63
|
"dev:prepare": "nuxi prepare && unbuild --stub && pnpm -r dev:prepare"
|
|
64
64
|
},
|
|
65
65
|
"dependencies": {
|
|
66
|
-
"@nuxt/kit": "^3.
|
|
67
|
-
"@nuxt/schema": "^3.
|
|
68
|
-
"c12": "^3.0.
|
|
69
|
-
"consola": "^3.4.
|
|
66
|
+
"@nuxt/kit": "^3.17.3",
|
|
67
|
+
"@nuxt/schema": "^3.17.3",
|
|
68
|
+
"c12": "^3.0.3",
|
|
69
|
+
"consola": "^3.4.2",
|
|
70
70
|
"defu": "^6.1.4",
|
|
71
|
-
"destr": "^2.0.
|
|
71
|
+
"destr": "^2.0.5",
|
|
72
72
|
"estree-walker": "^3.0.3",
|
|
73
|
-
"fake-indexeddb": "^6.0.
|
|
73
|
+
"fake-indexeddb": "^6.0.1",
|
|
74
74
|
"get-port-please": "^3.1.2",
|
|
75
|
-
"h3": "^1.15.
|
|
75
|
+
"h3": "^1.15.3",
|
|
76
76
|
"local-pkg": "^1.1.1",
|
|
77
77
|
"magic-string": "^0.30.17",
|
|
78
78
|
"node-fetch-native": "^1.6.5",
|
|
@@ -82,43 +82,44 @@
|
|
|
82
82
|
"perfect-debounce": "^1.0.0",
|
|
83
83
|
"radix3": "^1.1.2",
|
|
84
84
|
"scule": "^1.3.0",
|
|
85
|
-
"std-env": "^3.
|
|
86
|
-
"tinyexec": "^0.
|
|
87
|
-
"ufo": "^1.
|
|
88
|
-
"unplugin": "^2.
|
|
89
|
-
"vite": "^6.
|
|
85
|
+
"std-env": "^3.9.0",
|
|
86
|
+
"tinyexec": "^1.0.1",
|
|
87
|
+
"ufo": "^1.6.1",
|
|
88
|
+
"unplugin": "^2.3.3",
|
|
89
|
+
"vite": "^6.3.5",
|
|
90
90
|
"vitest-environment-nuxt": "^1.0.1",
|
|
91
91
|
"vue": "^3.5.13"
|
|
92
92
|
},
|
|
93
93
|
"devDependencies": {
|
|
94
94
|
"@cucumber/cucumber": "11.2.0",
|
|
95
95
|
"@jest/globals": "29.7.0",
|
|
96
|
-
"@nuxt/devtools-kit": "2.
|
|
97
|
-
"@nuxt/eslint-config": "1.1
|
|
98
|
-
"@playwright/test": "1.
|
|
96
|
+
"@nuxt/devtools-kit": "2.4.0",
|
|
97
|
+
"@nuxt/eslint-config": "1.3.1",
|
|
98
|
+
"@playwright/test": "1.52.0",
|
|
99
99
|
"@testing-library/vue": "8.1.0",
|
|
100
|
-
"@types/
|
|
100
|
+
"@types/bun": "1.2.13",
|
|
101
|
+
"@types/estree": "1.0.7",
|
|
101
102
|
"@types/jsdom": "21.1.7",
|
|
102
|
-
"@types/node": "22.
|
|
103
|
-
"@types/semver": "7.
|
|
103
|
+
"@types/node": "22.15.17",
|
|
104
|
+
"@types/semver": "7.7.0",
|
|
104
105
|
"@vue/test-utils": "2.4.6",
|
|
105
106
|
"changelogen": "0.6.1",
|
|
106
|
-
"compatx": "0.
|
|
107
|
-
"eslint": "9.
|
|
107
|
+
"compatx": "0.2.0",
|
|
108
|
+
"eslint": "9.26.0",
|
|
108
109
|
"installed-check": "9.3.0",
|
|
109
|
-
"knip": "5.
|
|
110
|
-
"nitropack": "2.11.
|
|
111
|
-
"nuxt": "3.
|
|
112
|
-
"pkg-pr-new": "0.0.
|
|
113
|
-
"playwright-core": "1.
|
|
114
|
-
"rollup": "4.
|
|
115
|
-
"semver": "7.7.
|
|
116
|
-
"typescript": "5.8.
|
|
110
|
+
"knip": "5.55.1",
|
|
111
|
+
"nitropack": "2.11.11",
|
|
112
|
+
"nuxt": "3.17.3",
|
|
113
|
+
"pkg-pr-new": "0.0.44",
|
|
114
|
+
"playwright-core": "1.52.0",
|
|
115
|
+
"rollup": "4.40.2",
|
|
116
|
+
"semver": "7.7.2",
|
|
117
|
+
"typescript": "5.8.3",
|
|
117
118
|
"unbuild": "latest",
|
|
118
|
-
"unimport": "
|
|
119
|
-
"vitest": "3.
|
|
120
|
-
"vue-router": "4.5.
|
|
121
|
-
"vue-tsc": "2.2.
|
|
119
|
+
"unimport": "5.0.1",
|
|
120
|
+
"vitest": "3.1.3",
|
|
121
|
+
"vue-router": "4.5.1",
|
|
122
|
+
"vue-tsc": "2.2.10"
|
|
122
123
|
},
|
|
123
124
|
"peerDependencies": {
|
|
124
125
|
"@cucumber/cucumber": "^10.3.1 || ^11.0.0",
|
|
@@ -166,22 +167,25 @@
|
|
|
166
167
|
"resolutions": {
|
|
167
168
|
"@cucumber/cucumber": "11.2.0",
|
|
168
169
|
"@nuxt/devtools": "1.0.8",
|
|
169
|
-
"@nuxt/kit": "^3.
|
|
170
|
-
"@nuxt/schema": "^3.
|
|
170
|
+
"@nuxt/kit": "^3.17.3",
|
|
171
|
+
"@nuxt/schema": "^3.17.3",
|
|
171
172
|
"@nuxt/test-utils": "workspace:*",
|
|
172
|
-
"rollup": "4.
|
|
173
|
-
"vite": "^6.
|
|
174
|
-
"vite-node": "3.
|
|
175
|
-
"vitest": "3.
|
|
173
|
+
"rollup": "4.40.2",
|
|
174
|
+
"vite": "^6.3.5",
|
|
175
|
+
"vite-node": "3.1.3",
|
|
176
|
+
"vitest": "3.1.3",
|
|
176
177
|
"vue": "^3.5.13"
|
|
177
178
|
},
|
|
178
179
|
"engines": {
|
|
179
180
|
"node": "^18.20.5 || ^20.9.0 || ^22.0.0 || >=23.0.0"
|
|
180
181
|
},
|
|
181
|
-
"packageManager": "pnpm@10.
|
|
182
|
+
"packageManager": "pnpm@10.10.0",
|
|
182
183
|
"pnpm": {
|
|
183
184
|
"onlyBuiltDependencies": [
|
|
184
185
|
"better-sqlite3"
|
|
186
|
+
],
|
|
187
|
+
"ignoredBuiltDependencies": [
|
|
188
|
+
"esbuild"
|
|
185
189
|
]
|
|
186
190
|
}
|
|
187
191
|
}
|