@nuxt/test-utils 3.22.0 → 3.23.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/dist/config.d.mts +1 -0
- package/dist/config.mjs +18 -1
- package/dist/e2e.d.mts +3 -2
- package/dist/e2e.mjs +3 -3
- package/dist/experimental.mjs +1 -1
- package/dist/module.mjs +458 -10
- package/dist/playwright.d.mts +2 -1
- package/dist/playwright.mjs +2 -2
- package/dist/runtime/shared/environment.mjs +11 -66
- package/dist/runtime/shared/h3-v1.d.ts +6 -0
- package/dist/runtime/shared/h3-v1.mjs +69 -0
- package/dist/runtime/shared/h3-v2.d.ts +6 -0
- package/dist/runtime/shared/h3-v2.mjs +35 -0
- package/dist/runtime/shared/h3.d.ts +3 -0
- package/dist/runtime/shared/h3.mjs +3 -0
- package/dist/runtime-utils/index.d.mts +2 -1
- package/dist/runtime-utils/index.mjs +28 -23
- package/dist/shared/{test-utils.D2ZzXztg.mjs → test-utils.5cnw0YZR.mjs} +1 -1
- package/dist/shared/{test-utils.C_clWQBc.mjs → test-utils.BsmyE2FA.mjs} +6 -4
- package/dist/shared/{test-utils.ZByFDqps.d.mts → test-utils.C9GKP_T5.d.mts} +2 -1
- package/dist/vitest-environment.d.mts +15 -3
- package/dist/vitest-environment.mjs +118 -66
- package/package.json +13 -7
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { createFetch } from "ofetch";
|
|
2
2
|
import { joinURL } from "ufo";
|
|
3
|
-
import {
|
|
3
|
+
import { defineEventHandler } from "./h3.mjs";
|
|
4
4
|
import { createRouter as createRadixRouter, exportMatcher, toRouteMatcher } from "radix3";
|
|
5
|
-
import {
|
|
5
|
+
import { createFetchForH3V1 } from "./h3-v1.mjs";
|
|
6
|
+
import { createFetchForH3V2 } from "./h3-v2.mjs";
|
|
6
7
|
export async function setupWindow(win, environmentOptions) {
|
|
7
8
|
win.__NUXT_VITEST_ENVIRONMENT__ = true;
|
|
8
9
|
win.__NUXT__ = {
|
|
@@ -35,7 +36,6 @@ export async function setupWindow(win, environmentOptions) {
|
|
|
35
36
|
const app = win.document.createElement("div");
|
|
36
37
|
app.id = rootId;
|
|
37
38
|
win.document.body.appendChild(app);
|
|
38
|
-
const h3App = createApp();
|
|
39
39
|
if (!win.fetch || !("Request" in win)) {
|
|
40
40
|
await import("node-fetch-native/polyfill");
|
|
41
41
|
win.URLSearchParams = globalThis.URLSearchParams;
|
|
@@ -49,37 +49,11 @@ export async function setupWindow(win, environmentOptions) {
|
|
|
49
49
|
}
|
|
50
50
|
};
|
|
51
51
|
}
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
const _fetch = fetch;
|
|
55
|
-
win.fetch = async (input, _init) => {
|
|
56
|
-
let url;
|
|
57
|
-
let init = _init;
|
|
58
|
-
if (typeof input === "string") {
|
|
59
|
-
url = input;
|
|
60
|
-
} else if (input instanceof URL) {
|
|
61
|
-
url = input.toString();
|
|
62
|
-
} else {
|
|
63
|
-
url = input.url;
|
|
64
|
-
init = {
|
|
65
|
-
method: init?.method ?? input.method,
|
|
66
|
-
body: init?.body ?? input.body,
|
|
67
|
-
headers: init?.headers ?? input.headers
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
const base = url.split("?")[0];
|
|
71
|
-
if (registry.has(base) || registry.has(url)) {
|
|
72
|
-
url = "/_" + url;
|
|
73
|
-
}
|
|
74
|
-
if (url.startsWith("/")) {
|
|
75
|
-
const response = await fetchNodeRequestHandler(nodeHandler, url, init);
|
|
76
|
-
return normalizeFetchResponse(response);
|
|
77
|
-
}
|
|
78
|
-
return _fetch(input, _init);
|
|
79
|
-
};
|
|
52
|
+
const res = environmentOptions.nuxt.h3Version === 2 ? await createFetchForH3V2() : await createFetchForH3V1();
|
|
53
|
+
win.fetch = res.fetch;
|
|
80
54
|
win.$fetch = createFetch({ fetch: win.fetch, Headers: win.Headers });
|
|
81
|
-
win.__registry = registry;
|
|
82
|
-
win.__app = h3App;
|
|
55
|
+
win.__registry = res.registry;
|
|
56
|
+
win.__app = res.h3App;
|
|
83
57
|
const timestamp = Date.now();
|
|
84
58
|
const routeRulesMatcher = toRouteMatcher(
|
|
85
59
|
createRadixRouter({ routes: environmentOptions.nuxtRouteRules || {} })
|
|
@@ -92,14 +66,14 @@ export async function setupWindow(win, environmentOptions) {
|
|
|
92
66
|
);
|
|
93
67
|
const manifestBaseRoutePath = joinURL("/_", manifestOutputPath);
|
|
94
68
|
const buildId = win.__NUXT__.config?.app.buildId || "test";
|
|
95
|
-
h3App.use(
|
|
69
|
+
res.h3App.use(
|
|
96
70
|
`${manifestBaseRoutePath}/latest.json`,
|
|
97
71
|
defineEventHandler(() => ({
|
|
98
72
|
id: buildId,
|
|
99
73
|
timestamp
|
|
100
74
|
}))
|
|
101
75
|
);
|
|
102
|
-
h3App.use(
|
|
76
|
+
res.h3App.use(
|
|
103
77
|
`${manifestBaseRoutePath}/meta/${buildId}.json`,
|
|
104
78
|
defineEventHandler(() => ({
|
|
105
79
|
id: buildId,
|
|
@@ -108,38 +82,9 @@ export async function setupWindow(win, environmentOptions) {
|
|
|
108
82
|
prerendered: []
|
|
109
83
|
}))
|
|
110
84
|
);
|
|
111
|
-
registry.add(`${manifestOutputPath}/latest.json`);
|
|
112
|
-
registry.add(`${manifestOutputPath}/meta/${buildId}.json`);
|
|
85
|
+
res.registry.add(`${manifestOutputPath}/latest.json`);
|
|
86
|
+
res.registry.add(`${manifestOutputPath}/meta/${buildId}.json`);
|
|
113
87
|
return () => {
|
|
114
88
|
console.info = consoleInfo;
|
|
115
89
|
};
|
|
116
90
|
}
|
|
117
|
-
function normalizeFetchResponse(response) {
|
|
118
|
-
if (!response.headers.has("set-cookie")) {
|
|
119
|
-
return response;
|
|
120
|
-
}
|
|
121
|
-
return new Response(response.body, {
|
|
122
|
-
status: response.status,
|
|
123
|
-
statusText: response.statusText,
|
|
124
|
-
headers: normalizeCookieHeaders(response.headers)
|
|
125
|
-
});
|
|
126
|
-
}
|
|
127
|
-
function normalizeCookieHeader(header = "") {
|
|
128
|
-
return splitCookiesString(joinHeaders(header));
|
|
129
|
-
}
|
|
130
|
-
function normalizeCookieHeaders(headers) {
|
|
131
|
-
const outgoingHeaders = new Headers();
|
|
132
|
-
for (const [name, header] of headers) {
|
|
133
|
-
if (name === "set-cookie") {
|
|
134
|
-
for (const cookie of normalizeCookieHeader(header)) {
|
|
135
|
-
outgoingHeaders.append("set-cookie", cookie);
|
|
136
|
-
}
|
|
137
|
-
} else {
|
|
138
|
-
outgoingHeaders.set(name, joinHeaders(header));
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
return outgoingHeaders;
|
|
142
|
-
}
|
|
143
|
-
function joinHeaders(value) {
|
|
144
|
-
return Array.isArray(value) ? value.join(", ") : String(value);
|
|
145
|
-
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
export async function createFetchForH3V1() {
|
|
2
|
+
const [{ createApp, toNodeListener }, { fetchNodeRequestHandler }] = await Promise.all([
|
|
3
|
+
import("h3"),
|
|
4
|
+
import("node-mock-http")
|
|
5
|
+
]);
|
|
6
|
+
const h3App = createApp();
|
|
7
|
+
const nodeHandler = toNodeListener(h3App);
|
|
8
|
+
const registry = /* @__PURE__ */ new Set();
|
|
9
|
+
const _fetch = fetch;
|
|
10
|
+
const h3Fetch = (async (input, _init) => {
|
|
11
|
+
let url;
|
|
12
|
+
let init = _init;
|
|
13
|
+
if (typeof input === "string") {
|
|
14
|
+
url = input;
|
|
15
|
+
} else if (input instanceof URL) {
|
|
16
|
+
url = input.toString();
|
|
17
|
+
} else {
|
|
18
|
+
url = input.url;
|
|
19
|
+
init = {
|
|
20
|
+
method: init?.method ?? input.method,
|
|
21
|
+
body: init?.body ?? input.body,
|
|
22
|
+
headers: init?.headers ?? input.headers
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
const base = url.split("?")[0];
|
|
26
|
+
if (registry.has(base) || registry.has(url)) {
|
|
27
|
+
url = "/_" + url;
|
|
28
|
+
}
|
|
29
|
+
if (url.startsWith("/")) {
|
|
30
|
+
const response = await fetchNodeRequestHandler(nodeHandler, url, init);
|
|
31
|
+
return normalizeFetchResponse(response);
|
|
32
|
+
}
|
|
33
|
+
return _fetch(input, _init);
|
|
34
|
+
});
|
|
35
|
+
return {
|
|
36
|
+
h3App,
|
|
37
|
+
registry,
|
|
38
|
+
fetch: h3Fetch
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
function normalizeFetchResponse(response) {
|
|
42
|
+
if (!response.headers.has("set-cookie")) {
|
|
43
|
+
return response;
|
|
44
|
+
}
|
|
45
|
+
return new Response(response.body, {
|
|
46
|
+
status: response.status,
|
|
47
|
+
statusText: response.statusText,
|
|
48
|
+
headers: normalizeCookieHeaders(response.headers)
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
function normalizeCookieHeader(header = "") {
|
|
52
|
+
return splitCookiesString(joinHeaders(header));
|
|
53
|
+
}
|
|
54
|
+
function normalizeCookieHeaders(headers) {
|
|
55
|
+
const outgoingHeaders = new Headers();
|
|
56
|
+
for (const [name, header] of headers) {
|
|
57
|
+
if (name === "set-cookie") {
|
|
58
|
+
for (const cookie of normalizeCookieHeader(header)) {
|
|
59
|
+
outgoingHeaders.append("set-cookie", cookie);
|
|
60
|
+
}
|
|
61
|
+
} else {
|
|
62
|
+
outgoingHeaders.set(name, joinHeaders(header));
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return outgoingHeaders;
|
|
66
|
+
}
|
|
67
|
+
function joinHeaders(value) {
|
|
68
|
+
return Array.isArray(value) ? value.join(", ") : String(value);
|
|
69
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export async function createFetchForH3V2() {
|
|
2
|
+
const { H3 } = await import("h3-next/generic");
|
|
3
|
+
const h3App = new H3();
|
|
4
|
+
const registry = /* @__PURE__ */ new Set();
|
|
5
|
+
const _fetch = fetch;
|
|
6
|
+
const h3Fetch = (async (input, _init) => {
|
|
7
|
+
let url;
|
|
8
|
+
let init = _init;
|
|
9
|
+
if (typeof input === "string") {
|
|
10
|
+
url = input;
|
|
11
|
+
} else if (input instanceof URL) {
|
|
12
|
+
url = input.toString();
|
|
13
|
+
} else {
|
|
14
|
+
url = input.url;
|
|
15
|
+
init = {
|
|
16
|
+
method: init?.method ?? input.method,
|
|
17
|
+
body: init?.body ?? input.body,
|
|
18
|
+
headers: init?.headers ?? input.headers
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
const base = url.split("?")[0];
|
|
22
|
+
if (registry.has(base) || registry.has(url)) {
|
|
23
|
+
return h3App.fetch(new Request("/_" + url, init));
|
|
24
|
+
}
|
|
25
|
+
if (url.startsWith("/")) {
|
|
26
|
+
return new Response("Not Found", { status: 404, statusText: "Not Found" });
|
|
27
|
+
}
|
|
28
|
+
return _fetch(input, _init);
|
|
29
|
+
});
|
|
30
|
+
return {
|
|
31
|
+
h3App,
|
|
32
|
+
registry,
|
|
33
|
+
fetch: h3Fetch
|
|
34
|
+
};
|
|
35
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { EventHandler
|
|
1
|
+
import { EventHandler } from 'h3';
|
|
2
|
+
import { HTTPMethod } from 'h3-next';
|
|
2
3
|
import { SetupContext, RenderFunction, ComputedOptions, MethodOptions, ComponentOptionsMixin, EmitsOptions, ComponentInjectOptions, ComponentOptionsWithoutProps, ComponentOptionsWithArrayProps, ComponentPropsOptions, ComponentOptionsWithObjectProps } from 'vue';
|
|
3
4
|
import { mount } from '@vue/test-utils';
|
|
4
5
|
import { RouteLocationRaw } from 'vue-router';
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { defineEventHandler } from 'h3';
|
|
2
1
|
import { mount } from '@vue/test-utils';
|
|
3
2
|
import { reactive, h as h$1, Suspense, nextTick as nextTick$1, getCurrentInstance, onErrorCaptured, effectScope } from 'vue';
|
|
4
3
|
import { defu } from 'defu';
|
|
@@ -12,30 +11,11 @@ function registerEndpoint(url, options) {
|
|
|
12
11
|
throw new Error("registerEndpoint() can only be used in a `@nuxt/test-utils` runtime environment");
|
|
13
12
|
}
|
|
14
13
|
const config = typeof options === "function" ? { handler: options, method: void 0, once: false } : options;
|
|
15
|
-
config.handler =
|
|
16
|
-
const hasBeenRegistered = window.__registry.has(url);
|
|
14
|
+
config.handler = Object.assign(config.handler, { __is_handler__: true });
|
|
17
15
|
endpointRegistry[url] ||= [];
|
|
18
16
|
endpointRegistry[url].push(config);
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
app.use("/_" + url, defineEventHandler(async (event) => {
|
|
22
|
-
const latestHandler = [...endpointRegistry[url] || []].reverse().find((config2) => config2.method ? event.method === config2.method : true);
|
|
23
|
-
if (!latestHandler) return;
|
|
24
|
-
const result = await latestHandler.handler(event);
|
|
25
|
-
if (!latestHandler.once) return result;
|
|
26
|
-
const index = endpointRegistry[url]?.indexOf(latestHandler);
|
|
27
|
-
if (index === void 0 || index === -1) return result;
|
|
28
|
-
endpointRegistry[url]?.splice(index, 1);
|
|
29
|
-
if (endpointRegistry[url]?.length === 0) {
|
|
30
|
-
window.__registry.delete(url);
|
|
31
|
-
}
|
|
32
|
-
return result;
|
|
33
|
-
}), {
|
|
34
|
-
match(_, event) {
|
|
35
|
-
return endpointRegistry[url]?.some((config2) => config2.method ? event?.method === config2.method : true) ?? false;
|
|
36
|
-
}
|
|
37
|
-
});
|
|
38
|
-
}
|
|
17
|
+
window.__registry.add(url);
|
|
18
|
+
app._registered ||= registerGlobalHandler(app);
|
|
39
19
|
return () => {
|
|
40
20
|
endpointRegistry[url]?.splice(endpointRegistry[url].indexOf(config), 1);
|
|
41
21
|
if (endpointRegistry[url]?.length === 0) {
|
|
@@ -53,6 +33,31 @@ function mockComponent(_path, _component) {
|
|
|
53
33
|
"mockComponent() is a macro and it did not get transpiled. This may be an internal bug of @nuxt/test-utils."
|
|
54
34
|
);
|
|
55
35
|
}
|
|
36
|
+
const handler = Object.assign(async (event) => {
|
|
37
|
+
const url = "url" in event && event.url ? event.url.pathname.replace(/^\/_/, "") : event.path.replace(/[?#].*$/, "").replace(/^\/_/, "");
|
|
38
|
+
const latestHandler = [...endpointRegistry[url] || []].reverse().find((config) => config.method ? event.method === config.method : true);
|
|
39
|
+
if (!latestHandler) return;
|
|
40
|
+
const result = await latestHandler.handler(event);
|
|
41
|
+
if (!latestHandler.once) return result;
|
|
42
|
+
const index = endpointRegistry[url]?.indexOf(latestHandler);
|
|
43
|
+
if (index === void 0 || index === -1) return result;
|
|
44
|
+
endpointRegistry[url]?.splice(index, 1);
|
|
45
|
+
if (endpointRegistry[url]?.length === 0) {
|
|
46
|
+
window.__registry.delete(url);
|
|
47
|
+
}
|
|
48
|
+
return result;
|
|
49
|
+
}, { __is_handler__: true });
|
|
50
|
+
function registerGlobalHandler(app) {
|
|
51
|
+
app.use(handler, {
|
|
52
|
+
match: (...args) => {
|
|
53
|
+
const [eventOrPath, _event = eventOrPath] = args;
|
|
54
|
+
const url = typeof eventOrPath === "string" ? eventOrPath.replace(/^\/_/, "").replace(/[?#].*$/, "") : eventOrPath.url.pathname.replace(/^\/_/, "");
|
|
55
|
+
const event = _event;
|
|
56
|
+
return endpointRegistry[url]?.some((config) => config.method ? event?.method === config.method : true) ?? false;
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
56
61
|
|
|
57
62
|
const RouterLink = defineComponent({
|
|
58
63
|
functional: true,
|
|
@@ -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.BsmyE2FA.mjs';
|
|
2
2
|
import { existsSync, promises } from 'node:fs';
|
|
3
3
|
import { resolve } from 'node:path';
|
|
4
4
|
import { defu } from 'defu';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { x } from 'tinyexec';
|
|
2
2
|
import { getRandomPort, waitForPort } from 'get-port-please';
|
|
3
|
-
import {
|
|
3
|
+
import { createFetch, fetch as fetch$1 } from 'ofetch';
|
|
4
4
|
import { resolve as resolve$1 } from 'pathe';
|
|
5
5
|
import { withTrailingSlash, joinURL } from 'ufo';
|
|
6
6
|
import { resolve } from 'node:path';
|
|
@@ -72,6 +72,7 @@ function exposeContextToEnv() {
|
|
|
72
72
|
process.env.NUXT_TEST_CONTEXT = JSON.stringify({ options, browser, url });
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
+
const globalFetch = globalThis.fetch || fetch$1;
|
|
75
76
|
async function startServer(options = {}) {
|
|
76
77
|
const ctx = useTestContext();
|
|
77
78
|
await stopServer();
|
|
@@ -144,10 +145,11 @@ async function stopServer() {
|
|
|
144
145
|
}
|
|
145
146
|
}
|
|
146
147
|
function fetch(path, options) {
|
|
147
|
-
return
|
|
148
|
+
return globalFetch(url(path), options);
|
|
148
149
|
}
|
|
149
|
-
const $fetch =
|
|
150
|
-
|
|
150
|
+
const _$fetch = createFetch({ fetch: globalFetch });
|
|
151
|
+
const $fetch = function $fetch2(path, options) {
|
|
152
|
+
return _$fetch(url(path), options);
|
|
151
153
|
};
|
|
152
154
|
function url(path) {
|
|
153
155
|
const ctx = useTestContext();
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Browser, Page, Response as Response$1, BrowserContextOptions, LaunchOptions } from 'playwright-core';
|
|
2
2
|
import { NuxtConfig, Nuxt } from '@nuxt/schema';
|
|
3
3
|
import { exec } from 'tinyexec';
|
|
4
|
+
import { $Fetch } from 'ofetch';
|
|
4
5
|
|
|
5
6
|
declare function createBrowser(): Promise<void>;
|
|
6
7
|
declare function getBrowser(): Promise<Browser>;
|
|
@@ -20,7 +21,7 @@ interface StartServerOptions {
|
|
|
20
21
|
declare function startServer(options?: StartServerOptions): Promise<void>;
|
|
21
22
|
declare function stopServer(): Promise<void>;
|
|
22
23
|
declare function fetch(path: string, options?: RequestInit): Promise<Response>;
|
|
23
|
-
declare const $fetch:
|
|
24
|
+
declare const $fetch: "$fetch" extends keyof typeof globalThis ? typeof globalThis.$fetch : $Fetch;
|
|
24
25
|
declare function url(path: string): string;
|
|
25
26
|
|
|
26
27
|
type TestRunner = 'vitest' | 'jest' | 'cucumber' | 'bun';
|
|
@@ -1,13 +1,25 @@
|
|
|
1
1
|
import { Environment } from 'vitest/environments';
|
|
2
|
-
import {
|
|
2
|
+
import { H3Event as H3Event$1 } from 'h3';
|
|
3
|
+
import { H3Event } from 'h3-next';
|
|
3
4
|
import { $Fetch } from 'nitropack';
|
|
4
5
|
import { JSDOMOptions, HappyDOMOptions } from 'vitest/node';
|
|
5
6
|
|
|
6
7
|
declare const _default: Environment;
|
|
7
8
|
|
|
8
9
|
type NuxtBuiltinEnvironment = 'happy-dom' | 'jsdom';
|
|
10
|
+
interface GenericAppUse {
|
|
11
|
+
(route: string, handler: (event: H3Event | H3Event$1) => unknown, options?: {
|
|
12
|
+
match: (...args: [string, H3Event$1 | undefined] | [H3Event]) => boolean;
|
|
13
|
+
}): void;
|
|
14
|
+
(handler: (event: H3Event | H3Event$1) => unknown, options?: {
|
|
15
|
+
match: (...args: [string, H3Event$1 | undefined] | [H3Event]) => boolean;
|
|
16
|
+
}): void;
|
|
17
|
+
}
|
|
18
|
+
interface GenericApp {
|
|
19
|
+
use: GenericAppUse;
|
|
20
|
+
}
|
|
9
21
|
interface NuxtWindow extends Window {
|
|
10
|
-
__app
|
|
22
|
+
__app?: GenericApp;
|
|
11
23
|
__registry: Set<string>;
|
|
12
24
|
__NUXT_VITEST_ENVIRONMENT__?: boolean;
|
|
13
25
|
__NUXT__: Record<string, unknown>;
|
|
@@ -26,4 +38,4 @@ type EnvironmentNuxt = (global: typeof globalThis, options: EnvironmentNuxtOptio
|
|
|
26
38
|
}>;
|
|
27
39
|
|
|
28
40
|
export { _default as default };
|
|
29
|
-
export type { EnvironmentNuxt, EnvironmentNuxtOptions, NuxtBuiltinEnvironment, NuxtWindow };
|
|
41
|
+
export type { EnvironmentNuxt, EnvironmentNuxtOptions, GenericApp, NuxtBuiltinEnvironment, NuxtWindow };
|
|
@@ -3,11 +3,119 @@ import { joinURL } from 'ufo';
|
|
|
3
3
|
import defu from 'defu';
|
|
4
4
|
import { populateGlobal } from 'vitest/environments';
|
|
5
5
|
import { createFetch } from 'ofetch';
|
|
6
|
-
import { createApp, toNodeListener, defineEventHandler } from 'h3';
|
|
7
6
|
import { toRouteMatcher, createRouter, exportMatcher } from 'radix3';
|
|
8
|
-
import { fetchNodeRequestHandler } from 'node-mock-http';
|
|
9
7
|
import { importModule } from 'local-pkg';
|
|
10
8
|
|
|
9
|
+
function defineEventHandler(handler) {
|
|
10
|
+
return Object.assign(handler, { __is_handler__: true });
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
async function createFetchForH3V1() {
|
|
14
|
+
const [{ createApp, toNodeListener }, { fetchNodeRequestHandler }] = await Promise.all([
|
|
15
|
+
import('h3'),
|
|
16
|
+
import('node-mock-http')
|
|
17
|
+
]);
|
|
18
|
+
const h3App = createApp();
|
|
19
|
+
const nodeHandler = toNodeListener(h3App);
|
|
20
|
+
const registry = /* @__PURE__ */ new Set();
|
|
21
|
+
const _fetch = fetch;
|
|
22
|
+
const h3Fetch = (async (input, _init) => {
|
|
23
|
+
let url;
|
|
24
|
+
let init = _init;
|
|
25
|
+
if (typeof input === "string") {
|
|
26
|
+
url = input;
|
|
27
|
+
} else if (input instanceof URL) {
|
|
28
|
+
url = input.toString();
|
|
29
|
+
} else {
|
|
30
|
+
url = input.url;
|
|
31
|
+
init = {
|
|
32
|
+
method: init?.method ?? input.method,
|
|
33
|
+
body: init?.body ?? input.body,
|
|
34
|
+
headers: init?.headers ?? input.headers
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
const base = url.split("?")[0];
|
|
38
|
+
if (registry.has(base) || registry.has(url)) {
|
|
39
|
+
url = "/_" + url;
|
|
40
|
+
}
|
|
41
|
+
if (url.startsWith("/")) {
|
|
42
|
+
const response = await fetchNodeRequestHandler(nodeHandler, url, init);
|
|
43
|
+
return normalizeFetchResponse(response);
|
|
44
|
+
}
|
|
45
|
+
return _fetch(input, _init);
|
|
46
|
+
});
|
|
47
|
+
return {
|
|
48
|
+
h3App,
|
|
49
|
+
registry,
|
|
50
|
+
fetch: h3Fetch
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
function normalizeFetchResponse(response) {
|
|
54
|
+
if (!response.headers.has("set-cookie")) {
|
|
55
|
+
return response;
|
|
56
|
+
}
|
|
57
|
+
return new Response(response.body, {
|
|
58
|
+
status: response.status,
|
|
59
|
+
statusText: response.statusText,
|
|
60
|
+
headers: normalizeCookieHeaders(response.headers)
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
function normalizeCookieHeader(header = "") {
|
|
64
|
+
return splitCookiesString(joinHeaders(header));
|
|
65
|
+
}
|
|
66
|
+
function normalizeCookieHeaders(headers) {
|
|
67
|
+
const outgoingHeaders = new Headers();
|
|
68
|
+
for (const [name, header] of headers) {
|
|
69
|
+
if (name === "set-cookie") {
|
|
70
|
+
for (const cookie of normalizeCookieHeader(header)) {
|
|
71
|
+
outgoingHeaders.append("set-cookie", cookie);
|
|
72
|
+
}
|
|
73
|
+
} else {
|
|
74
|
+
outgoingHeaders.set(name, joinHeaders(header));
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return outgoingHeaders;
|
|
78
|
+
}
|
|
79
|
+
function joinHeaders(value) {
|
|
80
|
+
return Array.isArray(value) ? value.join(", ") : String(value);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
async function createFetchForH3V2() {
|
|
84
|
+
const { H3 } = await import('h3-next/generic');
|
|
85
|
+
const h3App = new H3();
|
|
86
|
+
const registry = /* @__PURE__ */ new Set();
|
|
87
|
+
const _fetch = fetch;
|
|
88
|
+
const h3Fetch = (async (input, _init) => {
|
|
89
|
+
let url;
|
|
90
|
+
let init = _init;
|
|
91
|
+
if (typeof input === "string") {
|
|
92
|
+
url = input;
|
|
93
|
+
} else if (input instanceof URL) {
|
|
94
|
+
url = input.toString();
|
|
95
|
+
} else {
|
|
96
|
+
url = input.url;
|
|
97
|
+
init = {
|
|
98
|
+
method: init?.method ?? input.method,
|
|
99
|
+
body: init?.body ?? input.body,
|
|
100
|
+
headers: init?.headers ?? input.headers
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
const base = url.split("?")[0];
|
|
104
|
+
if (registry.has(base) || registry.has(url)) {
|
|
105
|
+
return h3App.fetch(new Request("/_" + url, init));
|
|
106
|
+
}
|
|
107
|
+
if (url.startsWith("/")) {
|
|
108
|
+
return new Response("Not Found", { status: 404, statusText: "Not Found" });
|
|
109
|
+
}
|
|
110
|
+
return _fetch(input, _init);
|
|
111
|
+
});
|
|
112
|
+
return {
|
|
113
|
+
h3App,
|
|
114
|
+
registry,
|
|
115
|
+
fetch: h3Fetch
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
|
|
11
119
|
async function setupWindow(win, environmentOptions) {
|
|
12
120
|
win.__NUXT_VITEST_ENVIRONMENT__ = true;
|
|
13
121
|
win.__NUXT__ = {
|
|
@@ -40,7 +148,6 @@ async function setupWindow(win, environmentOptions) {
|
|
|
40
148
|
const app = win.document.createElement("div");
|
|
41
149
|
app.id = rootId;
|
|
42
150
|
win.document.body.appendChild(app);
|
|
43
|
-
const h3App = createApp();
|
|
44
151
|
if (!win.fetch || !("Request" in win)) {
|
|
45
152
|
await import('node-fetch-native/polyfill');
|
|
46
153
|
win.URLSearchParams = globalThis.URLSearchParams;
|
|
@@ -54,37 +161,11 @@ async function setupWindow(win, environmentOptions) {
|
|
|
54
161
|
}
|
|
55
162
|
};
|
|
56
163
|
}
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
const _fetch = fetch;
|
|
60
|
-
win.fetch = async (input, _init) => {
|
|
61
|
-
let url;
|
|
62
|
-
let init = _init;
|
|
63
|
-
if (typeof input === "string") {
|
|
64
|
-
url = input;
|
|
65
|
-
} else if (input instanceof URL) {
|
|
66
|
-
url = input.toString();
|
|
67
|
-
} else {
|
|
68
|
-
url = input.url;
|
|
69
|
-
init = {
|
|
70
|
-
method: init?.method ?? input.method,
|
|
71
|
-
body: init?.body ?? input.body,
|
|
72
|
-
headers: init?.headers ?? input.headers
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
const base = url.split("?")[0];
|
|
76
|
-
if (registry.has(base) || registry.has(url)) {
|
|
77
|
-
url = "/_" + url;
|
|
78
|
-
}
|
|
79
|
-
if (url.startsWith("/")) {
|
|
80
|
-
const response = await fetchNodeRequestHandler(nodeHandler, url, init);
|
|
81
|
-
return normalizeFetchResponse(response);
|
|
82
|
-
}
|
|
83
|
-
return _fetch(input, _init);
|
|
84
|
-
};
|
|
164
|
+
const res = environmentOptions.nuxt.h3Version === 2 ? await createFetchForH3V2() : await createFetchForH3V1();
|
|
165
|
+
win.fetch = res.fetch;
|
|
85
166
|
win.$fetch = createFetch({ fetch: win.fetch, Headers: win.Headers });
|
|
86
|
-
win.__registry = registry;
|
|
87
|
-
win.__app = h3App;
|
|
167
|
+
win.__registry = res.registry;
|
|
168
|
+
win.__app = res.h3App;
|
|
88
169
|
const timestamp = Date.now();
|
|
89
170
|
const routeRulesMatcher = toRouteMatcher(
|
|
90
171
|
createRouter({ routes: environmentOptions.nuxtRouteRules || {} })
|
|
@@ -97,14 +178,14 @@ async function setupWindow(win, environmentOptions) {
|
|
|
97
178
|
);
|
|
98
179
|
const manifestBaseRoutePath = joinURL("/_", manifestOutputPath);
|
|
99
180
|
const buildId = win.__NUXT__.config?.app.buildId || "test";
|
|
100
|
-
h3App.use(
|
|
181
|
+
res.h3App.use(
|
|
101
182
|
`${manifestBaseRoutePath}/latest.json`,
|
|
102
183
|
defineEventHandler(() => ({
|
|
103
184
|
id: buildId,
|
|
104
185
|
timestamp
|
|
105
186
|
}))
|
|
106
187
|
);
|
|
107
|
-
h3App.use(
|
|
188
|
+
res.h3App.use(
|
|
108
189
|
`${manifestBaseRoutePath}/meta/${buildId}.json`,
|
|
109
190
|
defineEventHandler(() => ({
|
|
110
191
|
id: buildId,
|
|
@@ -113,41 +194,12 @@ async function setupWindow(win, environmentOptions) {
|
|
|
113
194
|
prerendered: []
|
|
114
195
|
}))
|
|
115
196
|
);
|
|
116
|
-
registry.add(`${manifestOutputPath}/latest.json`);
|
|
117
|
-
registry.add(`${manifestOutputPath}/meta/${buildId}.json`);
|
|
197
|
+
res.registry.add(`${manifestOutputPath}/latest.json`);
|
|
198
|
+
res.registry.add(`${manifestOutputPath}/meta/${buildId}.json`);
|
|
118
199
|
return () => {
|
|
119
200
|
console.info = consoleInfo;
|
|
120
201
|
};
|
|
121
202
|
}
|
|
122
|
-
function normalizeFetchResponse(response) {
|
|
123
|
-
if (!response.headers.has("set-cookie")) {
|
|
124
|
-
return response;
|
|
125
|
-
}
|
|
126
|
-
return new Response(response.body, {
|
|
127
|
-
status: response.status,
|
|
128
|
-
statusText: response.statusText,
|
|
129
|
-
headers: normalizeCookieHeaders(response.headers)
|
|
130
|
-
});
|
|
131
|
-
}
|
|
132
|
-
function normalizeCookieHeader(header = "") {
|
|
133
|
-
return splitCookiesString(joinHeaders(header));
|
|
134
|
-
}
|
|
135
|
-
function normalizeCookieHeaders(headers) {
|
|
136
|
-
const outgoingHeaders = new Headers();
|
|
137
|
-
for (const [name, header] of headers) {
|
|
138
|
-
if (name === "set-cookie") {
|
|
139
|
-
for (const cookie of normalizeCookieHeader(header)) {
|
|
140
|
-
outgoingHeaders.append("set-cookie", cookie);
|
|
141
|
-
}
|
|
142
|
-
} else {
|
|
143
|
-
outgoingHeaders.set(name, joinHeaders(header));
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
return outgoingHeaders;
|
|
147
|
-
}
|
|
148
|
-
function joinHeaders(value) {
|
|
149
|
-
return Array.isArray(value) ? value.join(", ") : String(value);
|
|
150
|
-
}
|
|
151
203
|
|
|
152
204
|
const happyDom = (async function(_, { happyDom = {} }) {
|
|
153
205
|
const { Window, GlobalWindow } = await importModule("happy-dom");
|