@nuxt/test-utils 3.23.0 → 4.0.1

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.
@@ -6,12 +6,12 @@ export default defineComponent({
6
6
  const nuxtApp = useNuxtApp();
7
7
  provide(PageRouteSymbol, useRoute());
8
8
  const done = nuxtApp.deferHydration();
9
- const results = nuxtApp.hooks.callHookWith((hooks) => hooks.map((hook) => hook()), "vue:setup");
9
+ const results = nuxtApp.hooks.callHookWith((hooks) => hooks.map((hook) => hook()), "vue:setup", []);
10
10
  if (import.meta.dev && results && results.some((i) => i && "then" in i)) {
11
11
  console.error("[nuxt] Error in `vue:setup`. Callbacks must be synchronous.");
12
12
  }
13
13
  onErrorCaptured((err, target, info) => {
14
- nuxtApp.hooks.callHook("vue:error", err, target, info).catch((hookError) => console.error("[nuxt] Error in `vue:error` hook", hookError));
14
+ nuxtApp.hooks.callHook("vue:error", err, target, info)?.catch((hookError) => console.error("[nuxt] Error in `vue:error` hook", hookError));
15
15
  if (isNuxtError(err) && (err.fatal || err.unhandled)) {
16
16
  return false;
17
17
  }
@@ -16,16 +16,6 @@ export async function setupWindow(win, environmentOptions) {
16
16
  data: {},
17
17
  state: {}
18
18
  };
19
- const rootId = environmentOptions.nuxt.rootId || "nuxt-test";
20
- let el;
21
- try {
22
- el = win.document.querySelector(rootId);
23
- } catch {
24
- }
25
- if (el) {
26
- return () => {
27
- };
28
- }
29
19
  const consoleInfo = console.info;
30
20
  console.info = (...args) => {
31
21
  if (args[0] === "<Suspense> is an experimental feature and its API will likely change.") {
@@ -34,7 +24,7 @@ export async function setupWindow(win, environmentOptions) {
34
24
  return consoleInfo(...args);
35
25
  };
36
26
  const app = win.document.createElement("div");
37
- app.id = rootId;
27
+ app.id = environmentOptions.nuxt.rootId || "nuxt-test";
38
28
  win.document.body.appendChild(app);
39
29
  if (!win.fetch || !("Request" in win)) {
40
30
  await import("node-fetch-native/polyfill");
@@ -1,50 +1,5 @@
1
- import type { VueWrapper } from '@vue/test-utils';
2
- type Options = ReturnType<typeof createPluginOptions>;
3
- export declare function getVueWrapperPlugin(): Options;
4
- declare function createPluginOptions(): {
5
- _name: string;
6
- _instances: WeakRef<VueWrapper>[];
7
- readonly instances: VueWrapper<unknown, {
8
- $: import("vue").ComponentInternalInstance;
9
- $data: {};
10
- $props: {};
11
- $attrs: {
12
- [x: string]: unknown;
13
- };
14
- $refs: {
15
- [x: string]: unknown;
16
- };
17
- $slots: Readonly<{
18
- [name: string]: import("vue").Slot<any> | undefined;
19
- }>;
20
- $root: import("vue").ComponentPublicInstance | null;
21
- $parent: import("vue").ComponentPublicInstance | null;
22
- $host: Element | null;
23
- $emit: (event: string, ...args: any[]) => void;
24
- $el: any;
25
- $options: import("vue").ComponentOptionsBase<any, any, any, any, any, any, any, any, any, {}, {}, string, {}, {}, {}, string, import("vue").ComponentProvideOptions> & {
26
- beforeCreate?: (() => void) | (() => void)[];
27
- created?: (() => void) | (() => void)[];
28
- beforeMount?: (() => void) | (() => void)[];
29
- mounted?: (() => void) | (() => void)[];
30
- beforeUpdate?: (() => void) | (() => void)[];
31
- updated?: (() => void) | (() => void)[];
32
- activated?: (() => void) | (() => void)[];
33
- deactivated?: (() => void) | (() => void)[];
34
- beforeDestroy?: (() => void) | (() => void)[];
35
- beforeUnmount?: (() => void) | (() => void)[];
36
- destroyed?: (() => void) | (() => void)[];
37
- unmounted?: (() => void) | (() => void)[];
38
- renderTracked?: ((e: import("vue").DebuggerEvent) => void) | ((e: import("vue").DebuggerEvent) => void)[];
39
- renderTriggered?: ((e: import("vue").DebuggerEvent) => void) | ((e: import("vue").DebuggerEvent) => void)[];
40
- errorCaptured?: ((err: unknown, instance: import("vue").ComponentPublicInstance | null, info: string) => boolean | void) | ((err: unknown, instance: import("vue").ComponentPublicInstance | null, info: string) => boolean | void)[];
41
- };
42
- $forceUpdate: () => void;
43
- $nextTick: typeof import("vue").nextTick;
44
- $watch<T extends string | ((...args: any) => any)>(source: T, cb: T extends (...args: any) => infer R ? (...args: [R, R, import("@vue/reactivity").OnCleanup]) => any : (...args: [any, any, import("@vue/reactivity").OnCleanup]) => any, options?: import("vue").WatchOptions): import("vue").WatchStopHandle;
45
- } & Readonly<{}> & Omit<{}, never> & import("vue").ShallowUnwrapRef<{}> & {} & import("vue").ComponentCustomProperties & {}>[];
46
- addInstance(instance: VueWrapper): void;
1
+ interface Options {
47
2
  hasNuxtPage(): boolean;
48
- _hasComponent(componentName: string): boolean;
49
- };
3
+ }
4
+ export declare function getVueWrapperPlugin(): Options;
50
5
  export {};
@@ -1,7 +1,12 @@
1
- import { config } from "@vue/test-utils";
2
1
  const PLUGIN_NAME = "nuxt-test-utils";
2
+ const config = await import("@vue/test-utils").then((r) => r.config).catch(() => void 0);
3
3
  export function getVueWrapperPlugin() {
4
- const installed = config.plugins.VueWrapper.installedPlugins.find(({ options: options2 }) => options2._name === PLUGIN_NAME);
4
+ if (!config) {
5
+ return {
6
+ hasNuxtPage: () => false
7
+ };
8
+ }
9
+ const installed = config.plugins.VueWrapper.installedPlugins.find(({ options: options2 }) => options2?._name === PLUGIN_NAME);
5
10
  if (installed) return installed.options;
6
11
  const options = createPluginOptions();
7
12
  config.plugins.VueWrapper.install((instance, options2) => {
@@ -56,9 +56,23 @@ declare function registerEndpoint(url: string, options: EventHandler | {
56
56
  * }
57
57
  * })
58
58
  * ```
59
+ * @example
60
+ * ```ts
61
+ * // Making partial mock with original implementation
62
+ * mockNuxtImport(useRoute, original => vi.fn(original))
63
+ * // or (with name based)
64
+ * mockNuxtImport('useRoute', original => vi.fn(original))
65
+ * // or (with name based, type parameter)
66
+ * mockNuxtImport<typeof useRoute>('useRoute', original => vi.fn(original))
67
+ *
68
+ * // Override in test
69
+ * vi.mocked(useRoute).mockImplementation(
70
+ * (...args) => ({ ...vi.mocked(useRoute).getMockImplementation()!(...args), path: '/mocked' }),
71
+ * )
72
+ * ```
59
73
  * @see https://nuxt.com/docs/getting-started/testing#mocknuxtimport
60
74
  */
61
- declare function mockNuxtImport<T = unknown>(_target: string | T, _factory: () => T | Promise<T>): void;
75
+ declare function mockNuxtImport<T = unknown>(_target: string | T, _factory: T extends string ? (original: any) => any : (original: T) => T | Promise<T>): void;
62
76
  /**
63
77
  * `mockComponent` allows you to mock Nuxt's component.
64
78
  * @param path - component name in PascalCase, or the relative path of the component.
@@ -1,17 +1,31 @@
1
1
  import { mount } from '@vue/test-utils';
2
- import { reactive, h as h$1, Suspense, nextTick as nextTick$1, getCurrentInstance, onErrorCaptured, effectScope } from 'vue';
3
- import { defu } from 'defu';
2
+ import { reactive, h as h$1, Suspense, nextTick, getCurrentInstance, onErrorCaptured, effectScope } from 'vue';
4
3
  import { defineComponent, useRouter, h, tryUseNuxtApp } from '#imports';
5
4
  import NuxtRoot from '#build/root-component.mjs';
6
5
 
7
- const endpointRegistry = {};
6
+ function getEndpointRegistry() {
7
+ const app = window.__app ?? {};
8
+ return app._registeredEndpointRegistry ||= {};
9
+ }
10
+ function findEndpointRegistryHandlers(url) {
11
+ const endpointRegistry = getEndpointRegistry();
12
+ const pathname = url.replace(/[?#].*$/, "");
13
+ for (const [key, handlers] of Object.entries(endpointRegistry)) {
14
+ if (key === url || key === pathname) {
15
+ if (handlers?.length) {
16
+ return handlers;
17
+ }
18
+ }
19
+ }
20
+ }
8
21
  function registerEndpoint(url, options) {
9
22
  const app = window.__app;
10
23
  if (!app) {
11
24
  throw new Error("registerEndpoint() can only be used in a `@nuxt/test-utils` runtime environment");
12
25
  }
13
- const config = typeof options === "function" ? { handler: options, method: void 0, once: false } : options;
26
+ const config = typeof options === "function" ? { url, handler: options, method: void 0, once: false } : { ...options, url };
14
27
  config.handler = Object.assign(config.handler, { __is_handler__: true });
28
+ const endpointRegistry = getEndpointRegistry();
15
29
  endpointRegistry[url] ||= [];
16
30
  endpointRegistry[url].push(config);
17
31
  window.__registry.add(url);
@@ -34,16 +48,17 @@ function mockComponent(_path, _component) {
34
48
  );
35
49
  }
36
50
  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);
51
+ const url = "url" in event && event.url ? (event.url.pathname + event.url.search).replace(/^\/_/, "") : event.path.replace(/^\/_/, "");
52
+ const registeredHandlers = findEndpointRegistryHandlers(url);
53
+ const latestHandler = [...registeredHandlers || []].reverse().find((config) => config.method ? event.method === config.method : true);
39
54
  if (!latestHandler) return;
40
55
  const result = await latestHandler.handler(event);
41
56
  if (!latestHandler.once) return result;
42
- const index = endpointRegistry[url]?.indexOf(latestHandler);
57
+ const index = registeredHandlers?.indexOf(latestHandler);
43
58
  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);
59
+ registeredHandlers?.splice(index, 1);
60
+ if (registeredHandlers?.length === 0) {
61
+ window.__registry.delete(latestHandler.url);
47
62
  }
48
63
  return result;
49
64
  }, { __is_handler__: true });
@@ -51,9 +66,10 @@ function registerGlobalHandler(app) {
51
66
  app.use(handler, {
52
67
  match: (...args) => {
53
68
  const [eventOrPath, _event = eventOrPath] = args;
54
- const url = typeof eventOrPath === "string" ? eventOrPath.replace(/^\/_/, "").replace(/[?#].*$/, "") : eventOrPath.url.pathname.replace(/^\/_/, "");
69
+ const url = typeof eventOrPath === "string" ? eventOrPath.replace(/^\/_/, "") : (eventOrPath.url.pathname + eventOrPath.url.search).replace(/^\/_/, "");
55
70
  const event = _event;
56
- return endpointRegistry[url]?.some((config) => config.method ? event?.method === config.method : true) ?? false;
71
+ const registeredHandlers = findEndpointRegistryHandlers(url);
72
+ return registeredHandlers?.some((config) => config.method ? event?.method === config.method : true) ?? false;
57
73
  }
58
74
  });
59
75
  return true;
@@ -197,7 +213,7 @@ function wrapperSuspended(component, options, {
197
213
  render: wrappedRender(() => h$1(
198
214
  Suspense,
199
215
  {
200
- onResolve: () => nextTick$1().then(() => {
216
+ onResolve: () => nextTick().then(() => {
201
217
  if (isMountSettled) return;
202
218
  isMountSettled = true;
203
219
  wrapper.setupState = setupState;
@@ -214,8 +230,9 @@ function wrapperSuspended(component, options, {
214
230
  }
215
231
  ))
216
232
  },
217
- defu(wrapperFnOptions, {
218
- global: {
233
+ {
234
+ ...wrapperFnOptions,
235
+ global: mergeComponentMountingGlobalOptions(wrapperFnOptions.global, {
219
236
  config: {
220
237
  globalProperties: makeAllPropertiesEnumerable(
221
238
  vueApp.config.globalProperties
@@ -229,11 +246,38 @@ function wrapperSuspended(component, options, {
229
246
  [ClonedComponent.name]: false
230
247
  },
231
248
  components: { ...vueApp._context.components, RouterLink }
232
- }
233
- })
249
+ })
250
+ }
234
251
  );
235
252
  });
236
253
  }
254
+ function mergeComponentMountingGlobalOptions(options = {}, defaults = {}) {
255
+ return {
256
+ ...options,
257
+ mixins: [...defaults.mixins || [], ...options.mixins || []],
258
+ stubs: {
259
+ ...defaults.stubs,
260
+ ...Array.isArray(options.stubs) ? Object.fromEntries(options.stubs.map((n) => [n, true])) : options.stubs
261
+ },
262
+ plugins: [...defaults.plugins || [], ...options.plugins || []],
263
+ components: { ...defaults.components, ...options.components },
264
+ provide: { ...defaults.provide, ...options.provide },
265
+ mocks: { ...defaults.mocks, ...options.mocks },
266
+ config: {
267
+ ...defaults.config,
268
+ ...options.config,
269
+ compilerOptions: {
270
+ ...defaults.config?.compilerOptions,
271
+ ...options.config?.compilerOptions
272
+ },
273
+ globalProperties: {
274
+ ...defaults.config?.globalProperties,
275
+ ...options.config?.globalProperties
276
+ }
277
+ },
278
+ directives: { ...defaults.directives, ...options.directives }
279
+ };
280
+ }
237
281
  function makeAllPropertiesEnumerable(target) {
238
282
  return {
239
283
  ...target,
@@ -1,4 +1,4 @@
1
- import { Browser, Page, Response as Response$1, BrowserContextOptions, LaunchOptions } from 'playwright-core';
1
+ import { Page, Response as Response$1, BrowserContextOptions, Browser, LaunchOptions } from 'playwright-core';
2
2
  import { NuxtConfig, Nuxt } from '@nuxt/schema';
3
3
  import { exec } from 'tinyexec';
4
4
  import { $Fetch } from 'ofetch';
@@ -116,5 +116,5 @@ interface TestHooks {
116
116
  ctx: TestContext;
117
117
  }
118
118
 
119
- 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 };
120
- export type { GotoOptions as G, NuxtPage as N, StartServerOptions as S, TestOptions as T, TestHooks as a, TestContext as b, TestRunner as h };
119
+ export { $fetch as $, createBrowser as d, createPage as e, fetch as f, getBrowser as g, stopServer as h, startServer as s, url as u, waitForHydration as w };
120
+ export type { GotoOptions as G, NuxtPage as N, StartServerOptions as S, TestOptions as T, TestHooks as a, TestContext as b, TestRunner as c };
@@ -117,10 +117,10 @@ async function buildFixture() {
117
117
  async function setupBun(hooks) {
118
118
  const bunTest = await import('bun:test');
119
119
  hooks.ctx.mockFn = bunTest.mock;
120
- bunTest.beforeAll(hooks.beforeAll);
120
+ bunTest.beforeAll(hooks.beforeAll, hooks.ctx.options.setupTimeout);
121
121
  bunTest.beforeEach(hooks.beforeEach);
122
122
  bunTest.afterEach(hooks.afterEach);
123
- bunTest.afterAll(hooks.afterAll);
123
+ bunTest.afterAll(hooks.afterAll, hooks.ctx.options.teardownTimeout);
124
124
  }
125
125
 
126
126
  async function setupCucumber(hooks) {
@@ -209,4 +209,4 @@ async function setup(options = {}) {
209
209
  await setupFn(hooks);
210
210
  }
211
211
 
212
- export { createPage as a, buildFixture as b, createBrowser as c, createTest as d, setup as e, getBrowser as g, loadFixture as l, setupMaps as s, waitForHydration as w };
212
+ export { createPage as a, buildFixture as b, createBrowser as c, createTest as d, setupMaps as e, getBrowser as g, loadFixture as l, setup as s, waitForHydration as w };
@@ -2,7 +2,7 @@ import { Environment } from 'vitest/environments';
2
2
  import { H3Event as H3Event$1 } from 'h3';
3
3
  import { H3Event } from 'h3-next';
4
4
  import { $Fetch } from 'nitropack';
5
- import { JSDOMOptions, HappyDOMOptions } from 'vitest/node';
5
+ import { EnvironmentOptions } from 'vitest/node';
6
6
 
7
7
  declare const _default: Environment;
8
8
 
@@ -29,8 +29,8 @@ interface NuxtWindow extends Window {
29
29
  Headers: typeof Headers;
30
30
  }
31
31
  interface EnvironmentNuxtOptions {
32
- jsdom?: JSDOMOptions;
33
- happyDom?: HappyDOMOptions;
32
+ jsdom?: EnvironmentOptions['jsdom'];
33
+ happyDom?: EnvironmentOptions['happyDOM'];
34
34
  }
35
35
  type EnvironmentNuxt = (global: typeof globalThis, options: EnvironmentNuxtOptions) => Promise<{
36
36
  window: NuxtWindow;
@@ -1,10 +1,9 @@
1
+ import { resolveModulePath } from 'exsolve';
1
2
  import { indexedDB } from 'fake-indexeddb';
2
3
  import { joinURL } from 'ufo';
3
4
  import defu from 'defu';
4
- import { populateGlobal } from 'vitest/environments';
5
5
  import { createFetch } from 'ofetch';
6
6
  import { toRouteMatcher, createRouter, exportMatcher } from 'radix3';
7
- import { importModule } from 'local-pkg';
8
7
 
9
8
  function defineEventHandler(handler) {
10
9
  return Object.assign(handler, { __is_handler__: true });
@@ -128,16 +127,6 @@ async function setupWindow(win, environmentOptions) {
128
127
  data: {},
129
128
  state: {}
130
129
  };
131
- const rootId = environmentOptions.nuxt.rootId || "nuxt-test";
132
- let el;
133
- try {
134
- el = win.document.querySelector(rootId);
135
- } catch {
136
- }
137
- if (el) {
138
- return () => {
139
- };
140
- }
141
130
  const consoleInfo = console.info;
142
131
  console.info = (...args) => {
143
132
  if (args[0] === "<Suspense> is an experimental feature and its API will likely change.") {
@@ -146,7 +135,7 @@ async function setupWindow(win, environmentOptions) {
146
135
  return consoleInfo(...args);
147
136
  };
148
137
  const app = win.document.createElement("div");
149
- app.id = rootId;
138
+ app.id = environmentOptions.nuxt.rootId || "nuxt-test";
150
139
  win.document.body.appendChild(app);
151
140
  if (!win.fetch || !("Request" in win)) {
152
141
  await import('node-fetch-native/polyfill');
@@ -202,7 +191,7 @@ async function setupWindow(win, environmentOptions) {
202
191
  }
203
192
 
204
193
  const happyDom = (async function(_, { happyDom = {} }) {
205
- const { Window, GlobalWindow } = await importModule("happy-dom");
194
+ const { Window, GlobalWindow } = await import('happy-dom');
206
195
  const window = new (GlobalWindow || Window)(happyDom);
207
196
  return {
208
197
  window,
@@ -213,7 +202,7 @@ const happyDom = (async function(_, { happyDom = {} }) {
213
202
  });
214
203
 
215
204
  const jsdom = (async function(global, { jsdom = {} }) {
216
- const { CookieJar, JSDOM, ResourceLoader, VirtualConsole } = await importModule("jsdom");
205
+ const { CookieJar, JSDOM, ResourceLoader, VirtualConsole } = await import('jsdom');
217
206
  const jsdomOptions = defu(jsdom, {
218
207
  html: "<!DOCTYPE html>",
219
208
  url: "http://localhost:3000",
@@ -227,7 +216,7 @@ const jsdom = (async function(global, { jsdom = {} }) {
227
216
  const virtualConsole = jsdomOptions.console && global.console ? new VirtualConsole() : void 0;
228
217
  const window = new JSDOM(jsdomOptions.html, {
229
218
  ...jsdomOptions,
230
- resources: jsdomOptions.resources ?? (jsdomOptions.userAgent ? new ResourceLoader({ userAgent: jsdomOptions.userAgent }) : void 0),
219
+ resources: jsdomOptions.resources ?? (jsdomOptions.userAgent ? ResourceLoader ? new ResourceLoader({ userAgent: jsdomOptions.userAgent }) : { userAgent: jsdomOptions.userAgent } : void 0),
231
220
  virtualConsole: virtualConsole ? "sendTo" in virtualConsole ? virtualConsole.sendTo(global.console) : virtualConsole.forwardTo(global.console) : void 0,
232
221
  cookieJar: jsdomOptions.cookieJar ? new CookieJar() : void 0
233
222
  }).window;
@@ -247,22 +236,23 @@ const environmentMap = {
247
236
  };
248
237
  const index = {
249
238
  name: "nuxt",
250
- transformMode: "web",
239
+ viteEnvironment: "client",
251
240
  async setup(global, environmentOptions) {
241
+ const { populateGlobal } = await importVitestEnvironments();
252
242
  const url = joinURL(
253
- environmentOptions?.nuxt.url ?? "http://localhost:3000",
254
- environmentOptions?.nuxtRuntimeConfig.app?.baseURL || "/"
243
+ environmentOptions.nuxt?.url ?? "http://localhost:3000",
244
+ environmentOptions.nuxtRuntimeConfig?.app?.baseURL || "/"
255
245
  );
256
- const environmentName = environmentOptions.nuxt.domEnvironment;
246
+ const environmentName = environmentOptions.nuxt?.domEnvironment;
257
247
  const environment = environmentMap[environmentName] || environmentMap["happy-dom"];
258
248
  const { window: win, teardown } = await environment(global, defu(environmentOptions, {
259
249
  happyDom: { url },
260
250
  jsdom: { url }
261
251
  }));
262
- if (environmentOptions?.nuxt?.mock?.intersectionObserver) {
252
+ if (environmentOptions.nuxt?.mock?.intersectionObserver) {
263
253
  win.IntersectionObserver ||= IntersectionObserver;
264
254
  }
265
- if (environmentOptions?.nuxt?.mock?.indexedDb) {
255
+ if (environmentOptions.nuxt?.mock?.indexedDb) {
266
256
  win.indexedDB = indexedDB;
267
257
  }
268
258
  const teardownWindow = await setupWindow(win, environmentOptions);
@@ -284,6 +274,10 @@ const index = {
284
274
  };
285
275
  }
286
276
  };
277
+ async function importVitestEnvironments() {
278
+ const pkg = resolveModulePath("vitest/runtime", { try: true }) ? "vitest/runtime" : "vitest/environments";
279
+ return await import(pkg);
280
+ }
287
281
  class IntersectionObserver {
288
282
  observe() {
289
283
  }
@@ -1,4 +1,3 @@
1
- import { importModule } from 'local-pkg';
2
1
  import { getPort } from 'get-port-please';
3
2
  import { a as listenHostMessages, b as sendMessageToHost } from '../shared/test-utils.DDUpsMYL.mjs';
4
3
 
@@ -32,10 +31,16 @@ function createCustomReporter(onVitestInit) {
32
31
  onTestRunStart() {
33
32
  sendMessageToHost("updated", toUpdatedResult());
34
33
  },
35
- onTaskUpdate() {
34
+ onTestModuleCollected() {
36
35
  sendMessageToHost("updated", toUpdatedResult());
37
36
  },
38
- onFinished() {
37
+ onTestCaseResult() {
38
+ sendMessageToHost("updated", toUpdatedResult());
39
+ },
40
+ onTestModuleEnd() {
41
+ sendMessageToHost("updated", toUpdatedResult());
42
+ },
43
+ onTestRunEnd() {
39
44
  sendMessageToHost("finished", toFinishedResult());
40
45
  }
41
46
  };
@@ -50,7 +55,7 @@ async function main() {
50
55
  });
51
56
  });
52
57
  const port = apiPorts ? await getPort({ ports: apiPorts }) : void 0;
53
- const { startVitest } = await importModule("vitest/node");
58
+ const { startVitest } = await import('vitest/node');
54
59
  const customReporter = createCustomReporter((vitest2) => {
55
60
  listenHostMessages(async ({ type, payload }) => {
56
61
  if (type === "stop") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nuxt/test-utils",
3
- "version": "3.23.0",
3
+ "version": "4.0.1",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/nuxt/test-utils.git"
@@ -57,19 +57,20 @@
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' --filter '!example-app-bun' -r test && pnpm --filter example-app-cucumber -r test",
60
+ "test:examples": "pnpm --filter '!@nuxt/test-utils' --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
- "test:types": "vue-tsc --noEmit",
64
- "test:unit": "vitest test/unit --run",
63
+ "test:types": "vue-tsc --noEmit && vitest --dir ./test/types --typecheck.only --run",
64
+ "test:unit": "vitest --dir ./test/unit --run",
65
65
  "build": "unbuild",
66
66
  "prepack": "unbuild",
67
67
  "dev:prepare": "nuxt prepare && unbuild --stub && pnpm -r dev:prepare"
68
68
  },
69
69
  "dependencies": {
70
- "@clack/prompts": "1.0.0-alpha.9",
71
- "@nuxt/kit": "^3.20.2",
72
- "c12": "^3.3.3",
70
+ "@clack/prompts": "1.2.0",
71
+ "@nuxt/devtools-kit": "^2.7.0",
72
+ "@nuxt/kit": "^3.21.2",
73
+ "c12": "^3.3.4",
73
74
  "consola": "^3.4.2",
74
75
  "defu": "^6.1.4",
75
76
  "destr": "^2.0.5",
@@ -77,70 +78,69 @@
77
78
  "exsolve": "^1.0.8",
78
79
  "fake-indexeddb": "^6.2.5",
79
80
  "get-port-please": "^3.2.0",
80
- "h3": "^1.15.4",
81
- "h3-next": "npm:h3@^2.0.1-rc.7",
81
+ "h3": "^1.15.11",
82
+ "h3-next": "npm:h3@2.0.1-rc.20",
82
83
  "local-pkg": "^1.1.2",
83
84
  "magic-string": "^0.30.21",
84
85
  "node-fetch-native": "^1.6.7",
85
86
  "node-mock-http": "^1.0.4",
86
- "nypm": "^0.6.2",
87
+ "nypm": "^0.6.5",
87
88
  "ofetch": "^1.5.1",
88
89
  "pathe": "^2.0.3",
89
- "perfect-debounce": "^2.0.0",
90
+ "perfect-debounce": "^2.1.0",
90
91
  "radix3": "^1.1.2",
91
92
  "scule": "^1.3.0",
92
- "std-env": "^3.10.0",
93
- "tinyexec": "^1.0.2",
94
- "ufo": "^1.6.1",
95
- "unplugin": "^2.3.11",
96
- "vitest-environment-nuxt": "^1.0.1",
97
- "vue": "^3.5.26"
93
+ "std-env": "^4.0.0",
94
+ "tinyexec": "^1.1.1",
95
+ "ufo": "^1.6.3",
96
+ "unplugin": "^3.0.0",
97
+ "vitest-environment-nuxt": "workspace:*",
98
+ "vue": "^3.5.32"
98
99
  },
99
100
  "devDependencies": {
100
- "@cucumber/cucumber": "12.5.0",
101
- "@jest/globals": "30.2.0",
102
- "@nuxt/devtools-kit": "2.7.0",
103
- "@nuxt/eslint-config": "1.12.1",
104
- "@nuxt/schema": "4.2.2",
105
- "@playwright/test": "1.57.0",
101
+ "@cucumber/cucumber": "12.7.0",
102
+ "@jest/globals": "30.3.0",
103
+ "@nuxt/eslint-config": "1.15.2",
104
+ "@nuxt/schema": "4.4.2",
105
+ "@playwright/test": "1.59.1",
106
106
  "@testing-library/vue": "8.1.0",
107
- "@types/bun": "1.3.5",
107
+ "@types/bun": "1.3.11",
108
108
  "@types/estree": "1.0.8",
109
- "@types/jsdom": "27.0.0",
109
+ "@types/jsdom": "28.0.1",
110
110
  "@types/node": "latest",
111
111
  "@types/semver": "7.7.1",
112
- "@vitest/browser-playwright": "4.0.16",
112
+ "@vitest/browser-playwright": "4.1.2",
113
113
  "@vue/test-utils": "2.4.6",
114
114
  "changelogen": "0.6.2",
115
115
  "compatx": "0.2.0",
116
- "eslint": "9.39.2",
117
- "installed-check": "9.3.0",
118
- "knip": "5.80.0",
119
- "nitropack": "2.12.9",
120
- "nuxt": "4.2.2",
121
- "oxc-parser": "^0.107.0",
122
- "pkg-pr-new": "0.0.62",
123
- "playwright-core": "1.57.0",
124
- "rollup": "4.55.1",
125
- "semver": "7.7.3",
126
- "typescript": "5.9.3",
116
+ "eslint": "10.2.0",
117
+ "installed-check": "10.0.1",
118
+ "knip": "6.3.0",
119
+ "nitropack": "2.13.3",
120
+ "nuxt": "4.4.2",
121
+ "oxc-parser": "0.124.0",
122
+ "pkg-pr-new": "0.0.66",
123
+ "playwright-core": "1.59.1",
124
+ "rollup": "4.60.1",
125
+ "semver": "7.7.4",
126
+ "typescript": "6.0.2",
127
127
  "unbuild": "latest",
128
- "unimport": "5.6.0",
129
- "vite": "7.3.0",
130
- "vitest": "3.2.4",
131
- "vue-router": "4.6.4",
132
- "vue-tsc": "3.2.2"
128
+ "unimport": "6.0.2",
129
+ "vite": "8.0.5",
130
+ "vitest": "4.1.2",
131
+ "vue-router": "5.0.4",
132
+ "vue-tsc": "3.2.6"
133
133
  },
134
134
  "peerDependencies": {
135
- "@cucumber/cucumber": "^10.3.1 || >=11.0.0",
136
- "@jest/globals": "^29.5.0 || >=30.0.0",
135
+ "@cucumber/cucumber": ">=11.0.0",
136
+ "@jest/globals": ">=30.0.0",
137
137
  "@playwright/test": "^1.43.1",
138
- "@testing-library/vue": "^7.0.0 || ^8.0.1",
138
+ "@testing-library/vue": "^8.0.1",
139
139
  "@vue/test-utils": "^2.4.2",
140
- "happy-dom": "*",
141
- "jsdom": "*",
140
+ "happy-dom": ">=20.0.11",
141
+ "jsdom": ">=27.4.0",
142
142
  "playwright-core": "^1.43.1",
143
- "vitest": "^3.2.0"
143
+ "vitest": "^4.0.2"
144
144
  },
145
145
  "peerDependenciesMeta": {
146
146
  "@cucumber/cucumber": {
@@ -175,19 +175,19 @@
175
175
  }
176
176
  },
177
177
  "resolutions": {
178
- "@cucumber/cucumber": "12.5.0",
179
- "@nuxt/schema": "4.2.2",
178
+ "@cucumber/cucumber": "12.7.0",
179
+ "@nuxt/schema": "4.4.2",
180
180
  "@nuxt/test-utils": "workspace:*",
181
- "@types/node": "24.10.4",
181
+ "@types/node": "24.12.2",
182
182
  "nitro": "https://pkg.pr.new/nitrojs/nitro@00598a8",
183
- "rollup": "4.55.1",
184
- "vite": "7.3.0",
185
- "vite-node": "5.2.0",
186
- "vitest": "3.2.4",
187
- "vue": "^3.5.26"
183
+ "rollup": "4.60.1",
184
+ "vite": "8.0.5",
185
+ "vite-node": "6.0.0",
186
+ "vitest": "4.1.2",
187
+ "vue": "^3.5.32"
188
188
  },
189
189
  "engines": {
190
- "node": "^20.11.1 || ^22.0.0 || >=24.0.0"
190
+ "node": "^20.19.0 || ^22.12.0 || >=24.0.0"
191
191
  },
192
- "packageManager": "pnpm@10.27.0"
192
+ "packageManager": "pnpm@10.33.0"
193
193
  }