@nuxt/test-utils 3.21.0 → 3.22.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 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#testing)
14
+ - in [an in-depth guide for module authors](https://nuxt.com/docs/4.x/guide/modules/testing)
15
15
 
16
16
  ## License
17
17
 
package/dist/config.d.mts CHANGED
@@ -1,9 +1,8 @@
1
- import * as vite from 'vite';
2
- import { UserConfig } from 'vite';
3
1
  import { NuxtConfig, Nuxt } from '@nuxt/schema';
4
2
  import { InlineConfig } from 'vitest/node';
5
3
  import { TestProjectInlineConfiguration } from 'vitest/config';
6
4
  import { DotenvOptions } from 'c12';
5
+ import { UserConfig, UserConfigFnPromise } from 'vite';
7
6
 
8
7
  interface GetVitestConfigOptions {
9
8
  nuxt: Nuxt;
@@ -19,7 +18,7 @@ declare function getVitestConfigFromNuxt(options?: GetVitestConfigOptions, loadN
19
18
  declare function defineVitestProject(config: TestProjectInlineConfiguration): Promise<TestProjectInlineConfiguration>;
20
19
  declare function defineVitestConfig(config?: UserConfig & {
21
20
  test?: InlineConfig;
22
- }): vite.UserConfigFnPromise;
21
+ }): UserConfigFnPromise;
23
22
  interface NuxtEnvironmentOptions {
24
23
  rootDir?: string;
25
24
  /**
package/dist/config.mjs CHANGED
@@ -3,12 +3,31 @@ import { defineConfig } from 'vite';
3
3
  import { setupDotenv } from 'c12';
4
4
  import { defu } from 'defu';
5
5
  import { createResolver, findPath } from '@nuxt/kit';
6
- import { a as applyEnv, l as loadKit } from './shared/test-utils.G1ew4kEe.mjs';
6
+ import { a as applyEnv, l as loadKit } from './shared/test-utils.BIY9XRkB.mjs';
7
7
  import 'destr';
8
8
  import 'scule';
9
9
  import 'node:url';
10
10
  import 'exsolve';
11
11
 
12
+ const PLUGIN_NAME = "nuxt:vitest:nuxt-environment-options";
13
+ const STUB_ID = "nuxt-vitest-environment-options";
14
+ function NuxtVitestEnvironmentOptionsPlugin(environmentOptions = {}) {
15
+ return {
16
+ name: PLUGIN_NAME,
17
+ enforce: "pre",
18
+ resolveId(id) {
19
+ if (id.endsWith(STUB_ID)) {
20
+ return STUB_ID;
21
+ }
22
+ },
23
+ load(id) {
24
+ if (id.endsWith(STUB_ID)) {
25
+ return `export default ${JSON.stringify(environmentOptions || {})}`;
26
+ }
27
+ }
28
+ };
29
+ }
30
+
12
31
  async function startNuxtAndGetViteConfig(rootDir = process.cwd(), options = {}) {
13
32
  const { buildNuxt, loadNuxt } = await loadKit(rootDir);
14
33
  const nuxt = await loadNuxt({
@@ -73,6 +92,7 @@ async function getVitestConfigFromNuxt(options, loadNuxtOptions = {}) {
73
92
  }
74
93
  });
75
94
  }
95
+ delete options.viteConfig.root;
76
96
  options.viteConfig.plugins = (options.viteConfig.plugins || []).filter((p) => !p || !("name" in p) || !excludedPlugins.includes(p.name));
77
97
  const resolver = createResolver(import.meta.url);
78
98
  const resolvedConfig = defu(
@@ -91,7 +111,6 @@ async function getVitestConfigFromNuxt(options, loadNuxtOptions = {}) {
91
111
  noDiscovery: true
92
112
  },
93
113
  test: {
94
- dir: process.cwd(),
95
114
  environmentOptions: {
96
115
  nuxtRuntimeConfig: applyEnv(structuredClone(options.nuxt.options.runtimeConfig), {
97
116
  prefix: "NUXT_",
@@ -188,14 +207,12 @@ async function getVitestConfigFromNuxt(options, loadNuxtOptions = {}) {
188
207
  return resolvedConfig;
189
208
  }
190
209
  async function defineVitestProject(config) {
191
- if (process.env.__NUXT_VITEST_RESOLVED__) return config;
192
210
  const resolvedConfig = await resolveConfig(config);
193
211
  resolvedConfig.test.environment = "nuxt";
194
212
  return resolvedConfig;
195
213
  }
196
214
  function defineVitestConfig(config = {}) {
197
215
  return defineConfig(async () => {
198
- if (process.env.__NUXT_VITEST_RESOLVED__) return config;
199
216
  const resolvedConfig = await resolveConfig(config);
200
217
  if (resolvedConfig.test.browser?.enabled) {
201
218
  return resolvedConfig;
@@ -256,22 +273,7 @@ async function resolveConfig(config) {
256
273
  overrides: structuredClone(overrides)
257
274
  })
258
275
  );
259
- const PLUGIN_NAME = "nuxt:vitest:nuxt-environment-options";
260
- const STUB_ID = "nuxt-vitest-environment-options";
261
- resolvedConfig.plugins.push({
262
- name: PLUGIN_NAME,
263
- enforce: "pre",
264
- resolveId(id) {
265
- if (id.endsWith(STUB_ID)) {
266
- return STUB_ID;
267
- }
268
- },
269
- load(id) {
270
- if (id.endsWith(STUB_ID)) {
271
- return `export default ${JSON.stringify(resolvedConfig.test.environmentOptions || {})}`;
272
- }
273
- }
274
- });
276
+ resolvedConfig.plugins.push(NuxtVitestEnvironmentOptionsPlugin(resolvedConfig.test.environmentOptions));
275
277
  if (resolvedConfig.test.browser?.enabled) {
276
278
  if (resolvedConfig.test.environment === "nuxt") {
277
279
  resolvedConfig.test.setupFiles = Array.isArray(resolvedConfig.test.setupFiles) ? resolvedConfig.test.setupFiles : [resolvedConfig.test.setupFiles].filter(Boolean);
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.20kU0tZa.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.20kU0tZa.mjs';
1
+ import { T as TestOptions, b as TestContext, a as TestHooks } from './shared/test-utils.ZByFDqps.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.ZByFDqps.mjs';
3
3
  import { LogType } from 'consola';
4
4
  import 'playwright-core';
5
5
  import '@nuxt/schema';
package/dist/e2e.mjs CHANGED
@@ -1,13 +1,13 @@
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.3NR-so9-.mjs';
2
- import { u as useTestContext } from './shared/test-utils.CtwoJP76.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.CtwoJP76.mjs';
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.D2ZzXztg.mjs';
2
+ import { u as useTestContext } from './shared/test-utils.C_clWQBc.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.C_clWQBc.mjs';
4
4
  import { consola } from 'consola';
5
5
  import { resolve } from 'pathe';
6
6
  import { distDir } from '#dirs';
7
7
  import 'node:fs';
8
8
  import 'node:path';
9
9
  import 'defu';
10
- import './shared/test-utils.G1ew4kEe.mjs';
10
+ import './shared/test-utils.BIY9XRkB.mjs';
11
11
  import 'destr';
12
12
  import 'scule';
13
13
  import 'node:url';
@@ -52,8 +52,10 @@ async function runTests(opts) {
52
52
  {
53
53
  root: opts.rootDir,
54
54
  run: !opts.watch,
55
- deps: {
56
- inline: [/@nuxt\/test-utils/]
55
+ server: {
56
+ deps: {
57
+ inline: [/@nuxt\/test-utils/]
58
+ }
57
59
  }
58
60
  },
59
61
  // Vite options
@@ -63,13 +65,15 @@ async function runTests(opts) {
63
65
  },
64
66
  test: {
65
67
  dir: opts.rootDir,
66
- deps: {
67
- inline: [
68
- distDir,
69
- "@nuxt/test-utils",
70
- "@nuxt/test-utils-nightly",
71
- "@nuxt/test-utils-edge"
72
- ]
68
+ server: {
69
+ deps: {
70
+ inline: [
71
+ distDir,
72
+ "@nuxt/test-utils",
73
+ "@nuxt/test-utils-nightly",
74
+ "@nuxt/test-utils-edge"
75
+ ]
76
+ }
73
77
  },
74
78
  globals: true,
75
79
  globalSetup: [
@@ -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.CtwoJP76.mjs';
3
+ import { $ as $fetch, u as useTestContext } from './shared/test-utils.C_clWQBc.mjs';
4
4
  import 'tinyexec';
5
5
  import 'get-port-please';
6
6
  import 'ofetch';
package/dist/module.mjs CHANGED
@@ -1,22 +1,20 @@
1
- import { pathToFileURL } from 'node:url';
2
- import { resolveIgnorePatterns, defineNuxtModule, createResolver, resolvePath, importModule, logger } from '@nuxt/kit';
3
- import { getPort } from 'get-port-please';
4
- import { h } from 'vue';
5
- import { debounce } from 'perfect-debounce';
6
- import { isCI } from 'std-env';
7
- import { defu } from 'defu';
8
- import { extname, join, dirname, relative } from 'pathe';
9
- import { getVitestConfigFromNuxt } from './config.mjs';
1
+ import { resolveIgnorePatterns, useNuxt, addDevServerHandler, defineNuxtModule, createResolver, resolvePath, logger } from '@nuxt/kit';
2
+ import { extname, join, dirname, resolve, relative } from 'pathe';
3
+ import { provider, isCI } from 'std-env';
10
4
  import { walk } from 'estree-walker';
11
5
  import MagicString from 'magic-string';
12
6
  import { createUnplugin } from 'unplugin';
13
- import { l as loadKit } from './shared/test-utils.G1ew4kEe.mjs';
7
+ import { l as loadKit } from './shared/test-utils.BIY9XRkB.mjs';
14
8
  import { readFileSync } from 'node:fs';
15
- import 'node:process';
16
- import 'vite';
17
- import 'c12';
9
+ import { h } from 'vue';
10
+ import { defineEventHandler } from 'h3';
11
+ import { debounce } from 'perfect-debounce';
12
+ import { fork } from 'node:child_process';
13
+ import { c as createVitestTestSummary, l as listenCliMessages, s as sendMessageToCli } from './shared/test-utils.DDUpsMYL.mjs';
14
+ import { distDir } from '#dirs';
18
15
  import 'destr';
19
16
  import 'scule';
17
+ import 'node:url';
20
18
  import 'exsolve';
21
19
 
22
20
  const PLUGIN_NAME$1 = "nuxt:vitest:mock-transform";
@@ -297,28 +295,232 @@ async function setupImportMocking(nuxt) {
297
295
 
298
296
  const PLUGIN_NAME = "nuxt:vitest:nuxt-root-stub";
299
297
  const STUB_ID = "nuxt-vitest-app-entry";
300
- const NuxtRootStubPlugin = createUnplugin((options) => {
301
- const STUB_ID_WITH_EXT = STUB_ID + extname(options.entry);
298
+ const NuxtRootStubPlugin = (options) => {
299
+ const extension = extname(options.entry);
300
+ const escapedExt = extension.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
301
+ const entryPath = join(dirname(options.entry), STUB_ID + extension);
302
+ const idFilter = new RegExp(`${STUB_ID}(?:${escapedExt})?$`);
302
303
  return {
303
304
  name: PLUGIN_NAME,
304
305
  enforce: "pre",
305
- vite: {
306
- async resolveId(id, importer) {
307
- if (id.endsWith(STUB_ID) || id.endsWith(STUB_ID_WITH_EXT)) {
308
- return importer?.endsWith("index.html") ? id : join(dirname(options.entry), STUB_ID_WITH_EXT);
309
- }
306
+ resolveId: {
307
+ filter: {
308
+ id: idFilter
309
+ },
310
+ async handler(id, importer) {
311
+ return importer?.endsWith("index.html") ? id : entryPath;
312
+ }
313
+ },
314
+ load: {
315
+ filter: {
316
+ id: idFilter
310
317
  },
311
- async load(id) {
312
- if (id.endsWith(STUB_ID) || id.endsWith(STUB_ID_WITH_EXT)) {
313
- const entryContents = readFileSync(options.entry, "utf-8");
314
- return entryContents.replace("#build/root-component.mjs", options.rootStubPath);
318
+ async handler() {
319
+ const entryContents = readFileSync(options.entry, "utf-8");
320
+ return entryContents.replace("#build/root-component.mjs", options.rootStubPath);
321
+ }
322
+ }
323
+ };
324
+ };
325
+
326
+ async function setupDevTools(vitestWrapper, nuxt = useNuxt()) {
327
+ const iframeSrc = "/__test_utils_vitest__/";
328
+ const updateTabs = debounce(() => {
329
+ nuxt.callHook("devtools:customTabs:refresh");
330
+ }, 100);
331
+ nuxt.hook("devtools:customTabs", (tabs) => {
332
+ const tab = createVitestCustomTab(vitestWrapper, { iframeSrc });
333
+ const index = tabs.findIndex(({ name }) => tab.name === name);
334
+ if (index === -1) {
335
+ tabs.push(tab);
336
+ } else {
337
+ tabs.splice(index, 1, tab);
338
+ }
339
+ });
340
+ addDevServerHandler({
341
+ route: iframeSrc,
342
+ handler: defineEventHandler(
343
+ () => iframeContentHtml(vitestWrapper.uiUrl)
344
+ )
345
+ });
346
+ vitestWrapper.ons({
347
+ started() {
348
+ updateTabs();
349
+ },
350
+ updated() {
351
+ updateTabs();
352
+ },
353
+ finished() {
354
+ updateTabs();
355
+ },
356
+ exited() {
357
+ updateTabs();
358
+ }
359
+ });
360
+ }
361
+ function createVitestCustomTab(vitest, { iframeSrc }) {
362
+ const launchView = {
363
+ type: "launch",
364
+ description: "Start tests along with Nuxt",
365
+ actions: [
366
+ {
367
+ get label() {
368
+ switch (vitest.status) {
369
+ case "starting":
370
+ return "Starting...";
371
+ case "running":
372
+ return "Running Vitest";
373
+ case "stopped":
374
+ return "Start Vitest";
375
+ case "finished":
376
+ return "Start Vitest";
377
+ }
378
+ },
379
+ get pending() {
380
+ return vitest.status === "starting" || vitest.status === "running";
381
+ },
382
+ handle: () => {
383
+ vitest.start();
315
384
  }
316
385
  }
386
+ ]
387
+ };
388
+ const uiView = {
389
+ type: "iframe",
390
+ persistent: false,
391
+ src: iframeSrc
392
+ };
393
+ const tab = {
394
+ title: "Vitest",
395
+ name: "vitest",
396
+ icon: "logos-vitest",
397
+ get view() {
398
+ if (vitest.status === "stopped" || vitest.status === "starting" || !vitest.uiUrl) {
399
+ return launchView;
400
+ } else {
401
+ return uiView;
402
+ }
403
+ },
404
+ extraTabVNode: vitest.testSummary.totalCount ? h("div", { style: { color: vitest.testSummary.failedCount ? "orange" : "green" } }, [
405
+ h("span", {}, vitest.testSummary.passedCount),
406
+ h("span", { style: { opacity: "0.5", fontSize: "0.9em" } }, "/"),
407
+ h(
408
+ "span",
409
+ { style: { opacity: "0.8", fontSize: "0.9em" } },
410
+ vitest.testSummary.totalCount
411
+ )
412
+ ]) : void 0
413
+ };
414
+ return tab;
415
+ }
416
+ function iframeContentHtml(uiUrl) {
417
+ return [
418
+ "<html><head><script>",
419
+ `(${function redirect(uiUrl2, provider2) {
420
+ if (typeof window === "undefined") return;
421
+ if (!uiUrl2) return;
422
+ if (provider2 === "stackblitz") {
423
+ const url = new URL(window.location.href);
424
+ const newUrl = new URL(uiUrl2);
425
+ newUrl.host = url.host.replace(/--\d+--/, `--${newUrl.port}--`);
426
+ newUrl.protocol = url.protocol;
427
+ newUrl.port = url.port;
428
+ uiUrl2 = newUrl.toString();
429
+ }
430
+ window.location.replace(uiUrl2);
431
+ }})(${JSON.stringify(uiUrl)}, ${JSON.stringify(provider)})`,
432
+ "<\/script></head></html>"
433
+ ].join("\n");
434
+ }
435
+
436
+ function vitestWrapper(options) {
437
+ const { cwd, ...startOptions } = options;
438
+ let _status = "stopped";
439
+ let _uiUrl;
440
+ let _process;
441
+ let _testSummary = createVitestTestSummary();
442
+ const _handlers = {
443
+ started: [({ uiUrl }) => {
444
+ _uiUrl = uiUrl;
445
+ _status = "running";
446
+ _testSummary = createVitestTestSummary();
447
+ }],
448
+ updated: [(summary) => {
449
+ _testSummary = summary;
450
+ }],
451
+ finished: [(summary) => {
452
+ _status = "finished";
453
+ _testSummary = summary;
454
+ }],
455
+ exited: [clear]
456
+ };
457
+ function clear() {
458
+ _status = "stopped";
459
+ _uiUrl = void 0;
460
+ _process = void 0;
461
+ _testSummary = createVitestTestSummary();
462
+ }
463
+ function on(name, handler) {
464
+ _handlers[name] ??= [];
465
+ _handlers[name]?.push(handler);
466
+ }
467
+ function ons(handlers) {
468
+ for (const [name, handler] of Object.entries(handlers)) {
469
+ if (typeof handler === "function") {
470
+ on(name, handler);
471
+ }
472
+ }
473
+ }
474
+ async function stop() {
475
+ const vitest = _process;
476
+ if (!vitest || vitest.exitCode !== null) return;
477
+ return new Promise((resolve2) => {
478
+ vitest.once("exit", () => resolve2());
479
+ sendMessageToCli(vitest, "stop", { force: true });
480
+ });
481
+ }
482
+ async function start() {
483
+ if (_process) return false;
484
+ const vitest = fork(resolve(distDir, "./vitest-wrapper/cli.mjs"), {
485
+ cwd,
486
+ env: {
487
+ ...process.env,
488
+ NODE_ENV: "test",
489
+ MODE: "test"
490
+ },
491
+ stdio: startOptions.logToConsole ? void 0 : ["ignore", "ignore", "inherit", "ipc"]
492
+ });
493
+ _status = "starting";
494
+ _process = vitest;
495
+ vitest.once("exit", () => {
496
+ _handlers.exited.forEach((fn) => fn({ exitCode: vitest.exitCode ?? 0 }));
497
+ });
498
+ listenCliMessages(vitest, ({ type, payload }) => {
499
+ _handlers[type].forEach((fn) => fn(payload));
500
+ });
501
+ sendMessageToCli(vitest, "start", startOptions);
502
+ return true;
503
+ }
504
+ return {
505
+ on,
506
+ ons,
507
+ stop,
508
+ start,
509
+ get uiUrl() {
510
+ return _uiUrl;
511
+ },
512
+ get options() {
513
+ return options;
514
+ },
515
+ get status() {
516
+ return _status;
517
+ },
518
+ get testSummary() {
519
+ return { ..._testSummary };
317
520
  }
318
521
  };
319
- });
522
+ }
320
523
 
321
- const vitePluginBlocklist = ["vite-plugin-vue-inspector", "vite-plugin-vue-inspector:post", "vite-plugin-inspect", "nuxt:type-check"];
322
524
  const module$1 = defineNuxtModule({
323
525
  meta: {
324
526
  name: "@nuxt/test-utils",
@@ -334,141 +536,64 @@ const module$1 = defineNuxtModule({
334
536
  }
335
537
  const { addVitePlugin } = await loadKit(nuxt.options.rootDir);
336
538
  const resolver = createResolver(import.meta.url);
337
- addVitePlugin(NuxtRootStubPlugin.vite({
338
- entry: await resolvePath("#app/entry", { alias: nuxt.options.alias }),
339
- rootStubPath: await resolvePath(resolver.resolve("./runtime/nuxt-root"))
340
- }));
539
+ if (nuxt.options.test || nuxt.options.dev) {
540
+ addVitePlugin(NuxtRootStubPlugin({
541
+ entry: await resolvePath("#app/entry", { alias: nuxt.options.alias }),
542
+ rootStubPath: await resolvePath(resolver.resolve("./runtime/nuxt-root"))
543
+ }));
544
+ }
341
545
  if (!nuxt.options.test && !nuxt.options.dev) {
342
546
  nuxt.options.vite.define ||= {};
343
547
  nuxt.options.vite.define["import.meta.vitest"] = "undefined";
344
548
  }
345
- nuxt.hook("prepare:types", (ctx2) => {
346
- ctx2.references.push({ types: "vitest/import-meta" });
347
- if (ctx2.nodeTsConfig) {
348
- ctx2.nodeTsConfig.include ||= [];
349
- ctx2.nodeTsConfig.include.push(relative(nuxt.options.buildDir, join(nuxt.options.rootDir, "vitest.config.*")));
549
+ nuxt.hook("prepare:types", (ctx) => {
550
+ ctx.references.push({ types: "vitest/import-meta" });
551
+ if (ctx.nodeTsConfig) {
552
+ ctx.nodeTsConfig.include ||= [];
553
+ ctx.nodeTsConfig.include.push(relative(nuxt.options.buildDir, join(nuxt.options.rootDir, "vitest.config.*")));
350
554
  if (nuxt.options.workspaceDir !== nuxt.options.rootDir) {
351
- ctx2.nodeTsConfig.include.push(relative(nuxt.options.buildDir, join(nuxt.options.workspaceDir, "vitest.config.*")));
555
+ ctx.nodeTsConfig.include.push(relative(nuxt.options.buildDir, join(nuxt.options.workspaceDir, "vitest.config.*")));
352
556
  }
353
557
  }
354
558
  });
355
559
  if (!nuxt.options.dev) return;
356
560
  if (process.env.TEST || process.env.VITE_TEST) return;
357
- const rawViteConfigPromise = new Promise((resolve) => {
358
- nuxt.hook("app:resolve", () => {
359
- nuxt.hook("vite:configResolved", (config, { isClient }) => {
360
- if (isClient) resolve(config);
361
- });
362
- });
363
- });
364
- let loaded = false;
365
- let promise;
366
- let ctx = void 0;
367
- let testFiles = null;
368
- const updateTabs = debounce(() => {
369
- nuxt.callHook("devtools:customTabs:refresh");
370
- }, 100);
371
- let URL;
372
- async function start() {
373
- const { mergeConfig } = await importModule("vite", { paths: nuxt.options.modulesDir });
374
- const rawViteConfig = mergeConfig({}, await rawViteConfigPromise);
375
- const viteConfig = await getVitestConfigFromNuxt({ nuxt, viteConfig: defu({ test: options.vitestConfig }, rawViteConfig) });
376
- viteConfig.plugins = (viteConfig.plugins || []).filter((p) => {
377
- return !p || !("name" in p) || !vitePluginBlocklist.includes(p.name);
378
- });
379
- viteConfig.test.environmentMatchGlobs ||= [];
380
- viteConfig.test.environmentMatchGlobs.push(
381
- ["**/*.nuxt.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}", "nuxt"],
382
- ["{test,tests}/nuxt/**.*", "nuxt"]
383
- );
384
- process.env.__NUXT_VITEST_RESOLVED__ = "true";
385
- const { startVitest } = await import(pathToFileURL(await resolvePath("vitest/node")).href);
386
- const customReporter = {
387
- onInit(_ctx) {
388
- ctx = _ctx;
389
- },
390
- onTaskUpdate() {
391
- testFiles = ctx.state.getFiles();
392
- updateTabs();
393
- },
394
- onFinished() {
395
- testFiles = ctx.state.getFiles();
396
- updateTabs();
397
- }
398
- };
399
- const watchMode = !process.env.NUXT_VITEST_DEV_TEST && !isCI;
400
- const PORT = await getPort({ port: 15555 });
401
- const PROTOCOL = nuxt.options.devServer.https ? "https" : "http";
402
- URL = `${PROTOCOL}://localhost:${PORT}/__vitest__/`;
403
- const overrides = watchMode ? {
404
- passWithNoTests: true,
405
- reporters: options.logToConsole ? [
406
- ...toArray(options.vitestConfig?.reporters ?? ["default"]),
407
- customReporter
408
- ] : [customReporter],
409
- // do not report to console
410
- watch: true,
411
- ui: true,
412
- open: false,
413
- api: {
414
- port: PORT
415
- }
416
- } : { watch: false };
417
- const promise2 = startVitest("test", [], defu(overrides, viteConfig.test), viteConfig);
418
- promise2.catch(() => process.exit(1));
419
- if (watchMode) {
420
- logger.info(`Vitest UI starting on ${URL}`);
421
- nuxt.hook("close", () => promise2.then((v) => v?.close()));
422
- await new Promise((resolve) => setTimeout(resolve, 1e3));
423
- } else {
424
- promise2.then((v) => nuxt.close().then(() => v?.close()).then(() => process.exit()));
425
- }
426
- loaded = true;
427
- }
428
- nuxt.hook("devtools:customTabs", (tabs) => {
429
- const failedCount = testFiles?.filter((f) => f.result?.state === "fail").length ?? 0;
430
- const passedCount = testFiles?.filter((f) => f.result?.state === "pass").length ?? 0;
431
- const totalCount = testFiles?.length ?? 0;
432
- tabs.push({
433
- title: "Vitest",
434
- name: "vitest",
435
- icon: "logos-vitest",
436
- view: loaded ? {
437
- type: "iframe",
438
- src: URL
439
- } : {
440
- type: "launch",
441
- description: "Start tests along with Nuxt",
442
- actions: [
443
- {
444
- label: promise ? "Starting..." : "Start Vitest",
445
- pending: !!promise,
446
- handle: () => {
447
- promise = promise || start();
448
- return promise;
449
- }
450
- }
451
- ]
452
- },
453
- extraTabVNode: totalCount ? h("div", { style: { color: failedCount ? "orange" : "green" } }, [
454
- h("span", {}, passedCount),
455
- h("span", { style: { opacity: "0.5", fontSize: "0.9em" } }, "/"),
456
- h(
457
- "span",
458
- { style: { opacity: "0.8", fontSize: "0.9em" } },
459
- totalCount
460
- )
461
- ]) : void 0
462
- });
561
+ const vitestWrapper2 = createVitestWrapper(options, nuxt);
562
+ nuxt.hook("devtools:before", async () => {
563
+ await setupDevTools(vitestWrapper2, nuxt);
463
564
  });
464
565
  if (options.startOnBoot) {
465
- promise = promise || start();
466
- promise.then(updateTabs);
566
+ vitestWrapper2.start();
467
567
  }
468
568
  }
469
569
  });
470
- function toArray(value) {
471
- return Array.isArray(value) ? value : [value];
570
+ function createVitestWrapper(options, nuxt = useNuxt()) {
571
+ const watchMode = !isCI;
572
+ const wrapper = vitestWrapper({
573
+ cwd: nuxt.options.rootDir,
574
+ apiPorts: [15555],
575
+ logToConsole: options.logToConsole ?? false,
576
+ watchMode
577
+ });
578
+ wrapper.ons({
579
+ started({ uiUrl }) {
580
+ if (watchMode) {
581
+ logger.info(`Vitest UI starting on ${uiUrl}`);
582
+ }
583
+ },
584
+ exited({ exitCode }) {
585
+ if (watchMode) {
586
+ logger.info(`Vitest exited with code ${exitCode}`);
587
+ } else {
588
+ nuxt.close().finally(() => process.exit(exitCode));
589
+ }
590
+ }
591
+ });
592
+ nuxt.hooks.addHooks({
593
+ close: () => wrapper.stop(),
594
+ restart: () => wrapper.stop()
595
+ });
596
+ return wrapper;
472
597
  }
473
598
 
474
599
  export { module$1 as default };
@@ -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.20kU0tZa.mjs';
4
+ import { T as TestOptions$1, G as GotoOptions, a as TestHooks } from './shared/test-utils.ZByFDqps.mjs';
5
5
  import '@nuxt/schema';
6
6
  import 'tinyexec';
7
7