@nuxt/test-utils 3.21.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.
Files changed (32) hide show
  1. package/README.md +1 -1
  2. package/dist/config.d.mts +3 -3
  3. package/dist/config.mjs +40 -21
  4. package/dist/e2e.d.mts +3 -2
  5. package/dist/e2e.mjs +17 -13
  6. package/dist/experimental.mjs +1 -1
  7. package/dist/module.mjs +721 -148
  8. package/dist/playwright.d.mts +2 -1
  9. package/dist/playwright.mjs +3 -3
  10. package/dist/runtime/shared/environment.mjs +11 -66
  11. package/dist/runtime/shared/h3-v1.d.ts +6 -0
  12. package/dist/runtime/shared/h3-v1.mjs +69 -0
  13. package/dist/runtime/shared/h3-v2.d.ts +6 -0
  14. package/dist/runtime/shared/h3-v2.mjs +35 -0
  15. package/dist/runtime/shared/h3.d.ts +3 -0
  16. package/dist/runtime/shared/h3.mjs +3 -0
  17. package/dist/runtime/shared/nuxt.d.ts +1 -1
  18. package/dist/runtime/shared/nuxt.mjs +10 -2
  19. package/dist/runtime/shared/vue-wrapper-plugin.d.ts +50 -0
  20. package/dist/runtime/shared/vue-wrapper-plugin.mjs +41 -0
  21. package/dist/runtime-utils/index.d.mts +26 -25
  22. package/dist/runtime-utils/index.mjs +185 -272
  23. package/dist/shared/{test-utils.3NR-so9-.mjs → test-utils.5cnw0YZR.mjs} +2 -2
  24. package/dist/shared/{test-utils.G1ew4kEe.mjs → test-utils.BIY9XRkB.mjs} +1 -1
  25. package/dist/shared/{test-utils.CtwoJP76.mjs → test-utils.BsmyE2FA.mjs} +10 -8
  26. package/dist/shared/{test-utils.20kU0tZa.d.mts → test-utils.C9GKP_T5.d.mts} +3 -2
  27. package/dist/shared/test-utils.DDUpsMYL.mjs +32 -0
  28. package/dist/vitest-environment.d.mts +15 -3
  29. package/dist/vitest-environment.mjs +118 -66
  30. package/dist/vitest-wrapper/cli.d.mts +2 -0
  31. package/dist/vitest-wrapper/cli.mjs +78 -0
  32. package/package.json +32 -26
@@ -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 nodeHandler = toNodeListener(h3App);
58
- const registry = /* @__PURE__ */ new Set();
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");
@@ -0,0 +1,2 @@
1
+
2
+ export { };
@@ -0,0 +1,78 @@
1
+ import { importModule } from 'local-pkg';
2
+ import { getPort } from 'get-port-please';
3
+ import { a as listenHostMessages, b as sendMessageToHost } from '../shared/test-utils.DDUpsMYL.mjs';
4
+
5
+ function createCustomReporter(onVitestInit) {
6
+ let ctx = void 0;
7
+ function getVitestUiUrl() {
8
+ if (!ctx.config.ui) return void 0;
9
+ const protocol = ctx.vite.config.server.https ? "https:" : "http:";
10
+ const host = ctx.config.api.host || "localhost";
11
+ const port = ctx.config.api.port;
12
+ const uiBase = ctx.config.uiBase;
13
+ return `${protocol}//${host}:${port}${uiBase}`;
14
+ }
15
+ function toUpdatedResult() {
16
+ const files = ctx.state.getFiles();
17
+ return {
18
+ failedCount: files.filter((f) => f.result?.state === "fail").length ?? 0,
19
+ passedCount: files.filter((f) => f.result?.state === "pass").length ?? 0,
20
+ totalCount: files.length ?? 0
21
+ };
22
+ }
23
+ function toFinishedResult() {
24
+ return toUpdatedResult();
25
+ }
26
+ return {
27
+ onInit(_ctx) {
28
+ ctx = _ctx;
29
+ onVitestInit(ctx);
30
+ sendMessageToHost("started", { uiUrl: getVitestUiUrl() });
31
+ },
32
+ onTestRunStart() {
33
+ sendMessageToHost("updated", toUpdatedResult());
34
+ },
35
+ onTaskUpdate() {
36
+ sendMessageToHost("updated", toUpdatedResult());
37
+ },
38
+ onFinished() {
39
+ sendMessageToHost("finished", toFinishedResult());
40
+ }
41
+ };
42
+ }
43
+ async function main() {
44
+ const {
45
+ apiPorts,
46
+ watchMode
47
+ } = await new Promise((resolve) => {
48
+ listenHostMessages(({ type, payload }) => {
49
+ if (type === "start") resolve(payload);
50
+ });
51
+ });
52
+ const port = apiPorts ? await getPort({ ports: apiPorts }) : void 0;
53
+ const { startVitest } = await importModule("vitest/node");
54
+ const customReporter = createCustomReporter((vitest2) => {
55
+ listenHostMessages(async ({ type, payload }) => {
56
+ if (type === "stop") {
57
+ await vitest2.exit(payload.force);
58
+ process.exit();
59
+ }
60
+ });
61
+ });
62
+ const vitest = await startVitest("test", [], watchMode ? {
63
+ passWithNoTests: true,
64
+ ui: true,
65
+ watch: true,
66
+ open: false,
67
+ api: { port }
68
+ } : { ui: false, watch: false }, {
69
+ test: {
70
+ reporters: ["default", customReporter]
71
+ }
72
+ });
73
+ if (!watchMode) {
74
+ await vitest.exit();
75
+ process.exit();
76
+ }
77
+ }
78
+ main();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nuxt/test-utils",
3
- "version": "3.21.0",
3
+ "version": "3.23.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/nuxt/test-utils.git"
@@ -57,7 +57,7 @@
57
57
  "lint": "eslint .",
58
58
  "lint:fix": "eslint . --fix",
59
59
  "test": "pnpm test:types && pnpm test:unit && pnpm test:examples",
60
- "test:examples": "pnpm --filter '!example-app-cucumber' --filter '!example-app-jest' -r test && pnpm --filter example-app-cucumber -r test",
60
+ "test:examples": "pnpm --filter '!example-app-cucumber' --filter '!example-app-jest' --filter '!example-app-bun' -r test && pnpm --filter example-app-cucumber -r test",
61
61
  "test:knip": "knip",
62
62
  "test:engines": "pnpm installed-check --no-workspaces --ignore-dev",
63
63
  "test:types": "vue-tsc --noEmit",
@@ -67,8 +67,9 @@
67
67
  "dev:prepare": "nuxt prepare && unbuild --stub && pnpm -r dev:prepare"
68
68
  },
69
69
  "dependencies": {
70
- "@nuxt/kit": "^3.20.1",
71
- "c12": "^3.3.2",
70
+ "@clack/prompts": "1.0.0-alpha.9",
71
+ "@nuxt/kit": "^3.20.2",
72
+ "c12": "^3.3.3",
72
73
  "consola": "^3.4.2",
73
74
  "defu": "^6.1.4",
74
75
  "destr": "^2.0.5",
@@ -77,10 +78,12 @@
77
78
  "fake-indexeddb": "^6.2.5",
78
79
  "get-port-please": "^3.2.0",
79
80
  "h3": "^1.15.4",
81
+ "h3-next": "npm:h3@^2.0.1-rc.7",
80
82
  "local-pkg": "^1.1.2",
81
83
  "magic-string": "^0.30.21",
82
84
  "node-fetch-native": "^1.6.7",
83
- "node-mock-http": "^1.0.3",
85
+ "node-mock-http": "^1.0.4",
86
+ "nypm": "^0.6.2",
84
87
  "ofetch": "^1.5.1",
85
88
  "pathe": "^2.0.3",
86
89
  "perfect-debounce": "^2.0.0",
@@ -91,40 +94,42 @@
91
94
  "ufo": "^1.6.1",
92
95
  "unplugin": "^2.3.11",
93
96
  "vitest-environment-nuxt": "^1.0.1",
94
- "vue": "^3.5.25"
97
+ "vue": "^3.5.26"
95
98
  },
96
99
  "devDependencies": {
97
- "@cucumber/cucumber": "12.3.0",
100
+ "@cucumber/cucumber": "12.5.0",
98
101
  "@jest/globals": "30.2.0",
99
102
  "@nuxt/devtools-kit": "2.7.0",
100
- "@nuxt/eslint-config": "1.11.0",
101
- "@nuxt/schema": "4.2.1",
103
+ "@nuxt/eslint-config": "1.12.1",
104
+ "@nuxt/schema": "4.2.2",
102
105
  "@playwright/test": "1.57.0",
103
106
  "@testing-library/vue": "8.1.0",
104
- "@types/bun": "1.3.3",
107
+ "@types/bun": "1.3.5",
105
108
  "@types/estree": "1.0.8",
106
109
  "@types/jsdom": "27.0.0",
107
110
  "@types/node": "latest",
108
111
  "@types/semver": "7.7.1",
112
+ "@vitest/browser-playwright": "4.0.16",
109
113
  "@vue/test-utils": "2.4.6",
110
114
  "changelogen": "0.6.2",
111
115
  "compatx": "0.2.0",
112
- "eslint": "9.39.1",
116
+ "eslint": "9.39.2",
113
117
  "installed-check": "9.3.0",
114
- "knip": "5.71.0",
118
+ "knip": "5.80.0",
115
119
  "nitropack": "2.12.9",
116
- "nuxt": "4.2.1",
120
+ "nuxt": "4.2.2",
121
+ "oxc-parser": "^0.107.0",
117
122
  "pkg-pr-new": "0.0.62",
118
123
  "playwright-core": "1.57.0",
119
- "rollup": "4.53.3",
124
+ "rollup": "4.55.1",
120
125
  "semver": "7.7.3",
121
126
  "typescript": "5.9.3",
122
127
  "unbuild": "latest",
123
- "unimport": "5.5.0",
124
- "vite": "7.2.6",
128
+ "unimport": "5.6.0",
129
+ "vite": "7.3.0",
125
130
  "vitest": "3.2.4",
126
- "vue-router": "4.6.3",
127
- "vue-tsc": "3.1.5"
131
+ "vue-router": "4.6.4",
132
+ "vue-tsc": "3.2.2"
128
133
  },
129
134
  "peerDependencies": {
130
135
  "@cucumber/cucumber": "^10.3.1 || >=11.0.0",
@@ -170,18 +175,19 @@
170
175
  }
171
176
  },
172
177
  "resolutions": {
173
- "@cucumber/cucumber": "12.3.0",
174
- "@nuxt/schema": "4.2.1",
178
+ "@cucumber/cucumber": "12.5.0",
179
+ "@nuxt/schema": "4.2.2",
175
180
  "@nuxt/test-utils": "workspace:*",
176
- "@types/node": "24.10.1",
177
- "rollup": "4.53.3",
178
- "vite": "7.2.6",
181
+ "@types/node": "24.10.4",
182
+ "nitro": "https://pkg.pr.new/nitrojs/nitro@00598a8",
183
+ "rollup": "4.55.1",
184
+ "vite": "7.3.0",
179
185
  "vite-node": "5.2.0",
180
186
  "vitest": "3.2.4",
181
- "vue": "^3.5.25"
187
+ "vue": "^3.5.26"
182
188
  },
183
189
  "engines": {
184
- "node": "^20.0.0 || ^22.0.0 || >=24.0.0"
190
+ "node": "^20.11.1 || ^22.0.0 || >=24.0.0"
185
191
  },
186
- "packageManager": "pnpm@10.24.0"
192
+ "packageManager": "pnpm@10.27.0"
187
193
  }