@nuxt/test-utils-nightly 3.21.1-20251220-095456-4c8a3b7 → 3.21.1-20251231-212503-838ed8b
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 +2 -3
- package/dist/config.mjs +1 -4
- package/dist/e2e.d.mts +2 -2
- package/dist/e2e.mjs +2 -2
- package/dist/module.mjs +247 -130
- package/dist/playwright.d.mts +1 -1
- package/dist/playwright.mjs +2 -2
- package/dist/runtime-utils/index.d.mts +23 -23
- package/dist/runtime-utils/index.mjs +154 -281
- package/dist/shared/{test-utils-nightly.G1ew4kEe.mjs → test-utils-nightly.BIY9XRkB.mjs} +1 -1
- package/dist/shared/{test-utils-nightly.BpHODLaZ.mjs → test-utils-nightly.D0-o1nCe.mjs} +1 -1
- package/dist/shared/test-utils-nightly.DDUpsMYL.mjs +32 -0
- package/dist/shared/{test-utils-nightly.20kU0tZa.d.mts → test-utils-nightly.ZByFDqps.d.mts} +1 -1
- package/dist/vitest-wrapper/cli.d.mts +2 -0
- package/dist/vitest-wrapper/cli.mjs +78 -0
- package/package.json +16 -16
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
|
-
}):
|
|
21
|
+
}): UserConfigFnPromise;
|
|
23
22
|
interface NuxtEnvironmentOptions {
|
|
24
23
|
rootDir?: string;
|
|
25
24
|
/**
|
package/dist/config.mjs
CHANGED
|
@@ -3,7 +3,7 @@ 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-nightly.
|
|
6
|
+
import { a as applyEnv, l as loadKit } from './shared/test-utils-nightly.BIY9XRkB.mjs';
|
|
7
7
|
import 'destr';
|
|
8
8
|
import 'scule';
|
|
9
9
|
import 'node:url';
|
|
@@ -91,7 +91,6 @@ async function getVitestConfigFromNuxt(options, loadNuxtOptions = {}) {
|
|
|
91
91
|
noDiscovery: true
|
|
92
92
|
},
|
|
93
93
|
test: {
|
|
94
|
-
dir: process.cwd(),
|
|
95
94
|
environmentOptions: {
|
|
96
95
|
nuxtRuntimeConfig: applyEnv(structuredClone(options.nuxt.options.runtimeConfig), {
|
|
97
96
|
prefix: "NUXT_",
|
|
@@ -188,14 +187,12 @@ async function getVitestConfigFromNuxt(options, loadNuxtOptions = {}) {
|
|
|
188
187
|
return resolvedConfig;
|
|
189
188
|
}
|
|
190
189
|
async function defineVitestProject(config) {
|
|
191
|
-
if (process.env.__NUXT_VITEST_RESOLVED__) return config;
|
|
192
190
|
const resolvedConfig = await resolveConfig(config);
|
|
193
191
|
resolvedConfig.test.environment = "nuxt";
|
|
194
192
|
return resolvedConfig;
|
|
195
193
|
}
|
|
196
194
|
function defineVitestConfig(config = {}) {
|
|
197
195
|
return defineConfig(async () => {
|
|
198
|
-
if (process.env.__NUXT_VITEST_RESOLVED__) return config;
|
|
199
196
|
const resolvedConfig = await resolveConfig(config);
|
|
200
197
|
if (resolvedConfig.test.browser?.enabled) {
|
|
201
198
|
return resolvedConfig;
|
package/dist/e2e.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { T as TestOptions,
|
|
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-nightly.
|
|
1
|
+
import { T as TestOptions, b as TestContext, a as TestHooks } from './shared/test-utils-nightly.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-nightly.ZByFDqps.mjs';
|
|
3
3
|
import { LogType } from 'consola';
|
|
4
4
|
import 'playwright-core';
|
|
5
5
|
import '@nuxt/schema';
|
package/dist/e2e.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
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-nightly.
|
|
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-nightly.D0-o1nCe.mjs';
|
|
2
2
|
import { u as useTestContext } from './shared/test-utils-nightly.C_clWQBc.mjs';
|
|
3
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-nightly.C_clWQBc.mjs';
|
|
4
4
|
import { consola } from 'consola';
|
|
@@ -7,7 +7,7 @@ import { distDir } from '#dirs';
|
|
|
7
7
|
import 'node:fs';
|
|
8
8
|
import 'node:path';
|
|
9
9
|
import 'defu';
|
|
10
|
-
import './shared/test-utils-nightly.
|
|
10
|
+
import './shared/test-utils-nightly.BIY9XRkB.mjs';
|
|
11
11
|
import 'destr';
|
|
12
12
|
import 'scule';
|
|
13
13
|
import 'node:url';
|
package/dist/module.mjs
CHANGED
|
@@ -1,22 +1,20 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
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-nightly.
|
|
7
|
+
import { l as loadKit } from './shared/test-utils-nightly.BIY9XRkB.mjs';
|
|
14
8
|
import { readFileSync } from 'node:fs';
|
|
15
|
-
import '
|
|
16
|
-
import '
|
|
17
|
-
import '
|
|
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-nightly.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";
|
|
@@ -325,7 +323,204 @@ const NuxtRootStubPlugin = (options) => {
|
|
|
325
323
|
};
|
|
326
324
|
};
|
|
327
325
|
|
|
328
|
-
|
|
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();
|
|
384
|
+
}
|
|
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 };
|
|
520
|
+
}
|
|
521
|
+
};
|
|
522
|
+
}
|
|
523
|
+
|
|
329
524
|
const module$1 = defineNuxtModule({
|
|
330
525
|
meta: {
|
|
331
526
|
name: "@nuxt/test-utils",
|
|
@@ -351,133 +546,55 @@ const module$1 = defineNuxtModule({
|
|
|
351
546
|
nuxt.options.vite.define ||= {};
|
|
352
547
|
nuxt.options.vite.define["import.meta.vitest"] = "undefined";
|
|
353
548
|
}
|
|
354
|
-
nuxt.hook("prepare:types", (
|
|
355
|
-
|
|
356
|
-
if (
|
|
357
|
-
|
|
358
|
-
|
|
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.*")));
|
|
359
554
|
if (nuxt.options.workspaceDir !== nuxt.options.rootDir) {
|
|
360
|
-
|
|
555
|
+
ctx.nodeTsConfig.include.push(relative(nuxt.options.buildDir, join(nuxt.options.workspaceDir, "vitest.config.*")));
|
|
361
556
|
}
|
|
362
557
|
}
|
|
363
558
|
});
|
|
364
559
|
if (!nuxt.options.dev) return;
|
|
365
560
|
if (process.env.TEST || process.env.VITE_TEST) return;
|
|
366
|
-
const
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
});
|
|
371
|
-
});
|
|
372
|
-
});
|
|
373
|
-
let loaded = false;
|
|
374
|
-
let promise;
|
|
375
|
-
let ctx = void 0;
|
|
376
|
-
let testFiles = null;
|
|
377
|
-
const updateTabs = debounce(() => {
|
|
378
|
-
nuxt.callHook("devtools:customTabs:refresh");
|
|
379
|
-
}, 100);
|
|
380
|
-
let URL;
|
|
381
|
-
async function start() {
|
|
382
|
-
const { mergeConfig } = await importModule("vite", { paths: nuxt.options.modulesDir });
|
|
383
|
-
const rawViteConfig = mergeConfig({}, await rawViteConfigPromise);
|
|
384
|
-
const viteConfig = await getVitestConfigFromNuxt({ nuxt, viteConfig: defu({ test: options.vitestConfig }, rawViteConfig) });
|
|
385
|
-
viteConfig.plugins = (viteConfig.plugins || []).filter((p) => {
|
|
386
|
-
return !p || !("name" in p) || !vitePluginBlocklist.includes(p.name);
|
|
387
|
-
});
|
|
388
|
-
viteConfig.test.environmentMatchGlobs ||= [];
|
|
389
|
-
viteConfig.test.environmentMatchGlobs.push(
|
|
390
|
-
["**/*.nuxt.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}", "nuxt"],
|
|
391
|
-
["{test,tests}/nuxt/**.*", "nuxt"]
|
|
392
|
-
);
|
|
393
|
-
process.env.__NUXT_VITEST_RESOLVED__ = "true";
|
|
394
|
-
const { startVitest } = await import(pathToFileURL(await resolvePath("vitest/node")).href);
|
|
395
|
-
const customReporter = {
|
|
396
|
-
onInit(_ctx) {
|
|
397
|
-
ctx = _ctx;
|
|
398
|
-
},
|
|
399
|
-
onTaskUpdate() {
|
|
400
|
-
testFiles = ctx.state.getFiles();
|
|
401
|
-
updateTabs();
|
|
402
|
-
},
|
|
403
|
-
onFinished() {
|
|
404
|
-
testFiles = ctx.state.getFiles();
|
|
405
|
-
updateTabs();
|
|
406
|
-
}
|
|
407
|
-
};
|
|
408
|
-
const watchMode = !process.env.NUXT_VITEST_DEV_TEST && !isCI;
|
|
409
|
-
const PORT = await getPort({ port: 15555 });
|
|
410
|
-
const PROTOCOL = nuxt.options.devServer.https ? "https" : "http";
|
|
411
|
-
URL = `${PROTOCOL}://localhost:${PORT}/__vitest__/`;
|
|
412
|
-
const overrides = watchMode ? {
|
|
413
|
-
passWithNoTests: true,
|
|
414
|
-
reporters: options.logToConsole ? [
|
|
415
|
-
...toArray(options.vitestConfig?.reporters ?? ["default"]),
|
|
416
|
-
customReporter
|
|
417
|
-
] : [customReporter],
|
|
418
|
-
// do not report to console
|
|
419
|
-
watch: true,
|
|
420
|
-
ui: true,
|
|
421
|
-
open: false,
|
|
422
|
-
api: {
|
|
423
|
-
port: PORT
|
|
424
|
-
}
|
|
425
|
-
} : { watch: false };
|
|
426
|
-
const promise2 = startVitest("test", [], defu(overrides, viteConfig.test), viteConfig);
|
|
427
|
-
promise2.catch(() => process.exit(1));
|
|
428
|
-
if (watchMode) {
|
|
429
|
-
logger.info(`Vitest UI starting on ${URL}`);
|
|
430
|
-
nuxt.hook("close", () => promise2.then((v) => v?.close()));
|
|
431
|
-
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
432
|
-
} else {
|
|
433
|
-
promise2.then((v) => nuxt.close().then(() => v?.close()).then(() => process.exit()));
|
|
434
|
-
}
|
|
435
|
-
loaded = true;
|
|
561
|
+
const vitestWrapper2 = createVitestWrapper(options, nuxt);
|
|
562
|
+
const isDevToolsEnabled = typeof nuxt.options.devtools === "boolean" ? nuxt.options.devtools : nuxt.options.devtools.enabled;
|
|
563
|
+
if (isDevToolsEnabled) {
|
|
564
|
+
await setupDevTools(vitestWrapper2, nuxt);
|
|
436
565
|
}
|
|
437
|
-
nuxt.hook("devtools:customTabs", (tabs) => {
|
|
438
|
-
const failedCount = testFiles?.filter((f) => f.result?.state === "fail").length ?? 0;
|
|
439
|
-
const passedCount = testFiles?.filter((f) => f.result?.state === "pass").length ?? 0;
|
|
440
|
-
const totalCount = testFiles?.length ?? 0;
|
|
441
|
-
tabs.push({
|
|
442
|
-
title: "Vitest",
|
|
443
|
-
name: "vitest",
|
|
444
|
-
icon: "logos-vitest",
|
|
445
|
-
view: loaded ? {
|
|
446
|
-
type: "iframe",
|
|
447
|
-
src: URL
|
|
448
|
-
} : {
|
|
449
|
-
type: "launch",
|
|
450
|
-
description: "Start tests along with Nuxt",
|
|
451
|
-
actions: [
|
|
452
|
-
{
|
|
453
|
-
label: promise ? "Starting..." : "Start Vitest",
|
|
454
|
-
pending: !!promise,
|
|
455
|
-
handle: () => {
|
|
456
|
-
promise = promise || start();
|
|
457
|
-
return promise;
|
|
458
|
-
}
|
|
459
|
-
}
|
|
460
|
-
]
|
|
461
|
-
},
|
|
462
|
-
extraTabVNode: totalCount ? h("div", { style: { color: failedCount ? "orange" : "green" } }, [
|
|
463
|
-
h("span", {}, passedCount),
|
|
464
|
-
h("span", { style: { opacity: "0.5", fontSize: "0.9em" } }, "/"),
|
|
465
|
-
h(
|
|
466
|
-
"span",
|
|
467
|
-
{ style: { opacity: "0.8", fontSize: "0.9em" } },
|
|
468
|
-
totalCount
|
|
469
|
-
)
|
|
470
|
-
]) : void 0
|
|
471
|
-
});
|
|
472
|
-
});
|
|
473
566
|
if (options.startOnBoot) {
|
|
474
|
-
|
|
475
|
-
promise.then(updateTabs);
|
|
567
|
+
vitestWrapper2.start();
|
|
476
568
|
}
|
|
477
569
|
}
|
|
478
570
|
});
|
|
479
|
-
function
|
|
480
|
-
|
|
571
|
+
function createVitestWrapper(options, nuxt = useNuxt()) {
|
|
572
|
+
const watchMode = !isCI;
|
|
573
|
+
const wrapper = vitestWrapper({
|
|
574
|
+
cwd: nuxt.options.rootDir,
|
|
575
|
+
apiPorts: [15555],
|
|
576
|
+
logToConsole: options.logToConsole ?? false,
|
|
577
|
+
watchMode
|
|
578
|
+
});
|
|
579
|
+
wrapper.ons({
|
|
580
|
+
started({ uiUrl }) {
|
|
581
|
+
if (watchMode) {
|
|
582
|
+
logger.info(`Vitest UI starting on ${uiUrl}`);
|
|
583
|
+
}
|
|
584
|
+
},
|
|
585
|
+
exited({ exitCode }) {
|
|
586
|
+
if (watchMode) {
|
|
587
|
+
logger.info(`Vitest exited with code ${exitCode}`);
|
|
588
|
+
} else {
|
|
589
|
+
nuxt.close().finally(() => process.exit(exitCode));
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
});
|
|
593
|
+
nuxt.hooks.addHooks({
|
|
594
|
+
close: () => wrapper.stop(),
|
|
595
|
+
restart: () => wrapper.stop()
|
|
596
|
+
});
|
|
597
|
+
return wrapper;
|
|
481
598
|
}
|
|
482
599
|
|
|
483
600
|
export { module$1 as default };
|
package/dist/playwright.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as _playwright_test from '@playwright/test';
|
|
2
2
|
export { expect } from '@playwright/test';
|
|
3
3
|
import { Response } from 'playwright-core';
|
|
4
|
-
import { T as TestOptions$1, G as GotoOptions,
|
|
4
|
+
import { T as TestOptions$1, G as GotoOptions, a as TestHooks } from './shared/test-utils-nightly.ZByFDqps.mjs';
|
|
5
5
|
import '@nuxt/schema';
|
|
6
6
|
import 'tinyexec';
|
|
7
7
|
|
package/dist/playwright.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import defu from 'defu';
|
|
2
2
|
import { test as test$1 } from '@playwright/test';
|
|
3
3
|
export { expect } from '@playwright/test';
|
|
4
|
-
import { w as waitForHydration, d as createTest } from './shared/test-utils-nightly.
|
|
4
|
+
import { w as waitForHydration, d as createTest } from './shared/test-utils-nightly.D0-o1nCe.mjs';
|
|
5
5
|
import 'node:path';
|
|
6
6
|
import 'ufo';
|
|
7
7
|
import 'std-env';
|
|
@@ -14,7 +14,7 @@ import 'exsolve';
|
|
|
14
14
|
import { d as url } from './shared/test-utils-nightly.C_clWQBc.mjs';
|
|
15
15
|
import 'pathe';
|
|
16
16
|
import '#dirs';
|
|
17
|
-
import './shared/test-utils-nightly.
|
|
17
|
+
import './shared/test-utils-nightly.BIY9XRkB.mjs';
|
|
18
18
|
import 'tinyexec';
|
|
19
19
|
import 'get-port-please';
|
|
20
20
|
import 'ofetch';
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { EventHandler, HTTPMethod } from 'h3';
|
|
2
2
|
import { SetupContext, RenderFunction, ComputedOptions, MethodOptions, ComponentOptionsMixin, EmitsOptions, ComponentInjectOptions, ComponentOptionsWithoutProps, ComponentOptionsWithArrayProps, ComponentPropsOptions, ComponentOptionsWithObjectProps } from 'vue';
|
|
3
|
-
import {
|
|
3
|
+
import { mount } from '@vue/test-utils';
|
|
4
4
|
import { RouteLocationRaw } from 'vue-router';
|
|
5
|
-
import {
|
|
5
|
+
import { render } from '@testing-library/vue';
|
|
6
6
|
|
|
7
7
|
type Awaitable<T> = T | Promise<T>;
|
|
8
8
|
type OptionalFunction<T> = T | (() => Awaitable<T>);
|
|
@@ -95,14 +95,26 @@ declare function mockComponent<Props = {}, RawBindings = {}, D = {}, C extends C
|
|
|
95
95
|
declare function mockComponent<PropNames extends string, RawBindings, D, C extends ComputedOptions = {}, M extends MethodOptions = {}, Mixin extends ComponentOptionsMixin = ComponentOptionsMixin, Extends extends ComponentOptionsMixin = ComponentOptionsMixin, E extends EmitsOptions = {}, EE extends string = string, I extends ComponentInjectOptions = {}, II extends string = string>(path: string, options: OptionalFunction<ComponentOptionsWithArrayProps<PropNames, RawBindings, D, C, M, Mixin, Extends, E, EE, I, II>>): void;
|
|
96
96
|
declare function mockComponent<PropsOptions extends Readonly<ComponentPropsOptions>, RawBindings, D, C extends ComputedOptions = {}, M extends MethodOptions = {}, Mixin extends ComponentOptionsMixin = ComponentOptionsMixin, Extends extends ComponentOptionsMixin = ComponentOptionsMixin, E extends EmitsOptions = {}, EE extends string = string, I extends ComponentInjectOptions = {}, II extends string = string>(path: string, options: OptionalFunction<ComponentOptionsWithObjectProps<PropsOptions, RawBindings, D, C, M, Mixin, Extends, E, EE, I, II>>): void;
|
|
97
97
|
|
|
98
|
-
type
|
|
98
|
+
type SetupState = Record<string, any>;
|
|
99
|
+
type WrapperFnComponent<Fn> = Fn extends (c: infer C, o: infer _) => infer _ ? C : never;
|
|
100
|
+
type WrapperFnOption<Fn> = Fn extends (c: WrapperFnComponent<Fn>, o: infer O) => infer _ ? O : never;
|
|
101
|
+
type WrapperFnResult<Fn> = Fn extends (c: WrapperFnComponent<Fn>, o: WrapperFnOption<Fn>) => infer R ? R : never;
|
|
102
|
+
type WrapperSuspendedOptions<Fn> = WrapperFnOption<Fn> & {
|
|
99
103
|
route?: RouteLocationRaw;
|
|
100
104
|
scoped?: boolean;
|
|
101
105
|
};
|
|
102
|
-
type
|
|
103
|
-
setupState: SetupState
|
|
106
|
+
type WrapperSuspendedResult<Fn> = WrapperFnResult<Fn> & {
|
|
107
|
+
setupState: SetupState;
|
|
104
108
|
};
|
|
105
|
-
|
|
109
|
+
declare global {
|
|
110
|
+
interface Window {
|
|
111
|
+
__cleanup?: Array<() => void>;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
type WrapperFn$1<C> = typeof mount<C>;
|
|
116
|
+
type WrapperOptions$1<C> = WrapperSuspendedOptions<WrapperFn$1<C>>;
|
|
117
|
+
type WrapperResult$1<C> = WrapperSuspendedResult<WrapperFn$1<C>>;
|
|
106
118
|
/**
|
|
107
119
|
* `mountSuspended` allows you to mount any vue component within the Nuxt environment, allowing async setup and access to injections from your Nuxt plugins. For example:
|
|
108
120
|
*
|
|
@@ -129,18 +141,11 @@ type SetupState$1 = Record<string, any>;
|
|
|
129
141
|
* @param component the component to be tested
|
|
130
142
|
* @param options optional options to set up your component
|
|
131
143
|
*/
|
|
132
|
-
declare function mountSuspended<T>(component: T, options?:
|
|
133
|
-
declare global {
|
|
134
|
-
var __cleanup: Array<() => void> | undefined;
|
|
135
|
-
}
|
|
144
|
+
declare function mountSuspended<T>(component: T, options?: WrapperOptions$1<T>): Promise<WrapperResult$1<T>>;
|
|
136
145
|
|
|
137
|
-
type
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
type RenderSuspendeResult = RenderResult & {
|
|
141
|
-
setupState: SetupState;
|
|
142
|
-
};
|
|
143
|
-
type SetupState = Record<string, any>;
|
|
146
|
+
type WrapperFn<C> = typeof render<C>;
|
|
147
|
+
type WrapperOptions<C> = WrapperSuspendedOptions<WrapperFn<C>>;
|
|
148
|
+
type WrapperResult<C> = WrapperSuspendedResult<WrapperFn<C>>;
|
|
144
149
|
/**
|
|
145
150
|
* `renderSuspended` allows you to mount any vue component within the Nuxt environment, allowing async setup and access to injections from your Nuxt plugins.
|
|
146
151
|
*
|
|
@@ -171,11 +176,6 @@ type SetupState = Record<string, any>;
|
|
|
171
176
|
* @param component the component to be tested
|
|
172
177
|
* @param options optional options to set up your component
|
|
173
178
|
*/
|
|
174
|
-
declare function renderSuspended<T>(component: T, options?:
|
|
175
|
-
declare global {
|
|
176
|
-
interface Window {
|
|
177
|
-
__cleanup?: Array<() => void>;
|
|
178
|
-
}
|
|
179
|
-
}
|
|
179
|
+
declare function renderSuspended<T>(component: T, options?: WrapperOptions<T>): Promise<WrapperResult<T>>;
|
|
180
180
|
|
|
181
181
|
export { mockComponent, mockNuxtImport, mountSuspended, registerEndpoint, renderSuspended };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { defineEventHandler } from 'h3';
|
|
2
2
|
import { mount } from '@vue/test-utils';
|
|
3
|
-
import { reactive, h as h$1, Suspense, nextTick, getCurrentInstance,
|
|
3
|
+
import { reactive, h as h$1, Suspense, nextTick as nextTick$1, getCurrentInstance, onErrorCaptured, effectScope } from 'vue';
|
|
4
4
|
import { defu } from 'defu';
|
|
5
|
-
import { defineComponent, useRouter, h, tryUseNuxtApp
|
|
5
|
+
import { defineComponent, useRouter, h, tryUseNuxtApp } from '#imports';
|
|
6
6
|
import NuxtRoot from '#build/root-component.mjs';
|
|
7
7
|
|
|
8
8
|
const endpointRegistry = {};
|
|
@@ -88,19 +88,34 @@ const RouterLink = defineComponent({
|
|
|
88
88
|
}
|
|
89
89
|
});
|
|
90
90
|
|
|
91
|
-
|
|
92
|
-
const {
|
|
93
|
-
|
|
94
|
-
attrs = {},
|
|
95
|
-
slots = {},
|
|
96
|
-
route = "/",
|
|
97
|
-
..._options
|
|
98
|
-
} = options || {};
|
|
99
|
-
for (const cleanupFunction of globalThis.__cleanup || []) {
|
|
100
|
-
cleanupFunction();
|
|
91
|
+
function cleanupAll() {
|
|
92
|
+
for (const fn of (window.__cleanup || []).splice(0)) {
|
|
93
|
+
fn();
|
|
101
94
|
}
|
|
95
|
+
}
|
|
96
|
+
function addCleanup(fn) {
|
|
97
|
+
window.__cleanup ||= [];
|
|
98
|
+
window.__cleanup.push(fn);
|
|
99
|
+
}
|
|
100
|
+
function runEffectScope(fn) {
|
|
101
|
+
const scope = effectScope();
|
|
102
|
+
addCleanup(() => scope.stop());
|
|
103
|
+
return scope.run(fn);
|
|
104
|
+
}
|
|
105
|
+
function wrapperSuspended(component, options, {
|
|
106
|
+
wrapperFn,
|
|
107
|
+
wrappedRender = (fn) => fn,
|
|
108
|
+
suspendedHelperName,
|
|
109
|
+
clonedComponentName
|
|
110
|
+
}) {
|
|
111
|
+
const { props = {}, attrs = {} } = options;
|
|
112
|
+
const { route = "/", scoped = false, ...wrapperFnOptions } = options;
|
|
102
113
|
const vueApp = tryUseNuxtApp()?.vueApp || globalThis.__unctx__.get("nuxt-app").tryUse().vueApp;
|
|
103
|
-
const {
|
|
114
|
+
const {
|
|
115
|
+
render: componentRender,
|
|
116
|
+
setup: componentSetup,
|
|
117
|
+
...componentRest
|
|
118
|
+
} = component;
|
|
104
119
|
let wrappedInstance = null;
|
|
105
120
|
let setupContext;
|
|
106
121
|
let setupState;
|
|
@@ -113,28 +128,19 @@ async function mountSuspended(component, options) {
|
|
|
113
128
|
app[key] = value;
|
|
114
129
|
}
|
|
115
130
|
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
if (options?.scoped) {
|
|
127
|
-
componentScope = effectScope();
|
|
128
|
-
globalThis.__cleanup ||= [];
|
|
129
|
-
globalThis.__cleanup.push(() => {
|
|
130
|
-
componentScope?.stop();
|
|
131
|
-
});
|
|
132
|
-
result = await componentScope?.run(async () => {
|
|
133
|
-
return await setup(props2, setupContext2);
|
|
134
|
-
});
|
|
135
|
-
} else {
|
|
136
|
-
result = await setup(props2, setupContext2);
|
|
131
|
+
const ClonedComponent = {
|
|
132
|
+
components: {},
|
|
133
|
+
...component,
|
|
134
|
+
name: clonedComponentName,
|
|
135
|
+
async setup(props2, instanceContext) {
|
|
136
|
+
const currentInstance = getCurrentInstance();
|
|
137
|
+
if (currentInstance) {
|
|
138
|
+
currentInstance.emit = (event, ...args) => {
|
|
139
|
+
setupContext.emit(event, ...args);
|
|
140
|
+
};
|
|
137
141
|
}
|
|
142
|
+
if (!componentSetup) return;
|
|
143
|
+
const result = scoped ? await runEffectScope(() => componentSetup(props2, setupContext)) : await componentSetup(props2, setupContext);
|
|
138
144
|
if (wrappedInstance?.exposed) {
|
|
139
145
|
instanceContext.expose(wrappedInstance.exposed);
|
|
140
146
|
}
|
|
@@ -142,114 +148,108 @@ async function mountSuspended(component, options) {
|
|
|
142
148
|
return result;
|
|
143
149
|
}
|
|
144
150
|
};
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
151
|
+
const SuspendedHelper = {
|
|
152
|
+
name: suspendedHelperName,
|
|
153
|
+
render: () => "",
|
|
154
|
+
async setup() {
|
|
155
|
+
const router = useRouter();
|
|
156
|
+
await router.replace(route);
|
|
157
|
+
return () => h$1(ClonedComponent, { ...props, ...setProps, ...attrs }, setupContext.slots);
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
return new Promise((resolve, reject) => {
|
|
161
|
+
let isMountSettled = false;
|
|
162
|
+
const wrapper = wrapperFn(
|
|
163
|
+
{
|
|
164
|
+
inheritAttrs: false,
|
|
165
|
+
__cssModules: componentRest.__cssModules,
|
|
166
|
+
setup: (props2, ctx) => {
|
|
167
|
+
patchInstanceAppContext();
|
|
168
|
+
wrappedInstance = getCurrentInstance();
|
|
169
|
+
setupContext = ctx;
|
|
170
|
+
const nuxtRootSetupResult = runEffectScope(
|
|
171
|
+
() => NuxtRoot.setup(props2, {
|
|
172
|
+
...ctx,
|
|
173
|
+
expose: () => {
|
|
174
|
+
}
|
|
175
|
+
})
|
|
176
|
+
);
|
|
177
|
+
onErrorCaptured((error, ...args) => {
|
|
178
|
+
if (isMountSettled) return;
|
|
179
|
+
isMountSettled = true;
|
|
180
|
+
try {
|
|
181
|
+
wrappedInstance?.appContext.config.errorHandler?.(error, ...args);
|
|
182
|
+
reject(error);
|
|
183
|
+
} catch (error2) {
|
|
184
|
+
reject(error2);
|
|
174
185
|
}
|
|
175
|
-
|
|
186
|
+
return false;
|
|
187
|
+
});
|
|
188
|
+
return nuxtRootSetupResult;
|
|
189
|
+
},
|
|
190
|
+
render: wrappedRender(() => h$1(
|
|
191
|
+
Suspense,
|
|
192
|
+
{
|
|
193
|
+
onResolve: () => nextTick$1().then(() => {
|
|
176
194
|
if (isMountSettled) return;
|
|
177
195
|
isMountSettled = true;
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
reject(error2);
|
|
183
|
-
}
|
|
184
|
-
return false;
|
|
185
|
-
});
|
|
186
|
-
return nuxtRootSetupResult;
|
|
187
|
-
},
|
|
188
|
-
render: () => h$1(
|
|
189
|
-
Suspense,
|
|
190
|
-
{
|
|
191
|
-
onResolve: () => nextTick().then(() => {
|
|
192
|
-
if (isMountSettled) return;
|
|
193
|
-
isMountSettled = true;
|
|
194
|
-
vm.setupState = setupState;
|
|
195
|
-
vm.__setProps = (props2) => {
|
|
196
|
+
wrapper.setupState = setupState;
|
|
197
|
+
resolve({
|
|
198
|
+
wrapper,
|
|
199
|
+
setProps: (props2) => {
|
|
196
200
|
Object.assign(setProps, props2);
|
|
197
|
-
};
|
|
198
|
-
resolve(wrappedMountedWrapper(vm));
|
|
199
|
-
})
|
|
200
|
-
},
|
|
201
|
-
{
|
|
202
|
-
default: () => h$1({
|
|
203
|
-
name: "MountSuspendedHelper",
|
|
204
|
-
render: () => "",
|
|
205
|
-
async setup() {
|
|
206
|
-
const router = useRouter();
|
|
207
|
-
await router.replace(route);
|
|
208
|
-
const clonedComponent = {
|
|
209
|
-
components: {},
|
|
210
|
-
...component,
|
|
211
|
-
name: "MountSuspendedComponent",
|
|
212
|
-
setup: (props2, ctx) => wrappedSetup(props2, setupContext, ctx)
|
|
213
|
-
};
|
|
214
|
-
return () => h$1(clonedComponent, { ...props, ...setProps, ...attrs }, setupContext.slots);
|
|
215
201
|
}
|
|
216
|
-
})
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
},
|
|
220
|
-
defu(
|
|
221
|
-
_options,
|
|
202
|
+
});
|
|
203
|
+
})
|
|
204
|
+
},
|
|
222
205
|
{
|
|
223
|
-
|
|
224
|
-
slots,
|
|
225
|
-
attrs,
|
|
226
|
-
global: {
|
|
227
|
-
config: {
|
|
228
|
-
globalProperties: {
|
|
229
|
-
...vueApp.config.globalProperties,
|
|
230
|
-
// make all properties/keys enumerable.
|
|
231
|
-
...Object.fromEntries(
|
|
232
|
-
Object.getOwnPropertyNames(vueApp.config.globalProperties).map((key) => [key, vueApp.config.globalProperties[key]])
|
|
233
|
-
)
|
|
234
|
-
}
|
|
235
|
-
},
|
|
236
|
-
directives: vueApp._context.directives,
|
|
237
|
-
provide: vueApp._context.provides,
|
|
238
|
-
stubs: {
|
|
239
|
-
Suspense: false,
|
|
240
|
-
MountSuspendedHelper: false,
|
|
241
|
-
[component && typeof component === "object" && "name" in component && typeof component.name === "string" ? component.name : "MountSuspendedComponent"]: false
|
|
242
|
-
},
|
|
243
|
-
components: { ...vueApp._context.components, RouterLink }
|
|
244
|
-
}
|
|
206
|
+
default: () => h$1(SuspendedHelper)
|
|
245
207
|
}
|
|
246
|
-
)
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
208
|
+
))
|
|
209
|
+
},
|
|
210
|
+
defu(wrapperFnOptions, {
|
|
211
|
+
global: {
|
|
212
|
+
config: {
|
|
213
|
+
globalProperties: makeAllPropertiesEnumerable(
|
|
214
|
+
vueApp.config.globalProperties
|
|
215
|
+
)
|
|
216
|
+
},
|
|
217
|
+
directives: vueApp._context.directives,
|
|
218
|
+
provide: vueApp._context.provides,
|
|
219
|
+
stubs: {
|
|
220
|
+
Suspense: false,
|
|
221
|
+
[SuspendedHelper.name]: false,
|
|
222
|
+
[ClonedComponent.name]: false
|
|
223
|
+
},
|
|
224
|
+
components: { ...vueApp._context.components, RouterLink }
|
|
225
|
+
}
|
|
226
|
+
})
|
|
227
|
+
);
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
function makeAllPropertiesEnumerable(target) {
|
|
231
|
+
return {
|
|
232
|
+
...target,
|
|
233
|
+
...Object.fromEntries(
|
|
234
|
+
Object.getOwnPropertyNames(target).map((key) => [key, target[key]])
|
|
235
|
+
)
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
async function mountSuspended(component, options = {}) {
|
|
240
|
+
const suspendedHelperName = "MountSuspendedHelper";
|
|
241
|
+
const clonedComponentName = "MountSuspendedComponent";
|
|
242
|
+
cleanupAll();
|
|
243
|
+
const { wrapper, setProps } = await wrapperSuspended(component, options, {
|
|
244
|
+
wrapperFn: mount,
|
|
245
|
+
suspendedHelperName,
|
|
246
|
+
clonedComponentName
|
|
247
|
+
});
|
|
248
|
+
Object.assign(wrapper, { __setProps: setProps });
|
|
249
|
+
const clonedComponent = wrapper.findComponent({ name: clonedComponentName });
|
|
250
|
+
return wrappedMountedWrapper(wrapper, clonedComponent);
|
|
250
251
|
}
|
|
251
|
-
function wrappedMountedWrapper(wrapper) {
|
|
252
|
-
const component = wrapper.findComponent({ name: "MountSuspendedComponent" });
|
|
252
|
+
function wrappedMountedWrapper(wrapper, component) {
|
|
253
253
|
const wrapperProps = [
|
|
254
254
|
"setProps",
|
|
255
255
|
"emitted",
|
|
@@ -290,154 +290,27 @@ function wrappedMountedWrapper(wrapper) {
|
|
|
290
290
|
}
|
|
291
291
|
}
|
|
292
292
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
const
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
const setProps = reactive({});
|
|
309
|
-
function patchInstanceAppContext() {
|
|
310
|
-
const app = getCurrentInstance()?.appContext.app;
|
|
311
|
-
if (!app) return;
|
|
312
|
-
for (const [key, value] of Object.entries(vueApp)) {
|
|
313
|
-
if (key in app) continue;
|
|
314
|
-
app[key] = value;
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
for (const fn of window.__cleanup || []) {
|
|
318
|
-
fn();
|
|
319
|
-
}
|
|
320
|
-
document.querySelector(`#${WRAPPER_EL_ID}`)?.remove();
|
|
321
|
-
const wrappedSetup = async (props2, setupContext2, instanceContext) => {
|
|
322
|
-
const currentInstance = getCurrentInstance();
|
|
323
|
-
if (currentInstance) {
|
|
324
|
-
currentInstance.emit = (event, ...args) => {
|
|
325
|
-
setupContext2.emit(event, ...args);
|
|
326
|
-
};
|
|
327
|
-
}
|
|
328
|
-
if (setup) {
|
|
329
|
-
const result = await setup(props2, setupContext2);
|
|
330
|
-
setupState = result && typeof result === "object" ? result : {};
|
|
331
|
-
if (wrappedInstance?.exposed) {
|
|
332
|
-
instanceContext.expose(wrappedInstance.exposed);
|
|
333
|
-
}
|
|
334
|
-
return result;
|
|
335
|
-
}
|
|
336
|
-
};
|
|
337
|
-
const WrapperComponent = defineComponent$1({
|
|
338
|
-
inheritAttrs: false,
|
|
339
|
-
render() {
|
|
340
|
-
return h$1("div", { id: WRAPPER_EL_ID }, this.$slots.default?.());
|
|
341
|
-
}
|
|
342
|
-
});
|
|
343
|
-
return new Promise((resolve, reject) => {
|
|
344
|
-
let isMountSettled = false;
|
|
345
|
-
const utils = renderFromTestingLibrary(
|
|
346
|
-
{
|
|
347
|
-
__cssModules: componentRest.__cssModules,
|
|
348
|
-
inheritAttrs: false,
|
|
349
|
-
setup: (props2, ctx) => {
|
|
350
|
-
patchInstanceAppContext();
|
|
351
|
-
wrappedInstance = getCurrentInstance();
|
|
352
|
-
setupContext = ctx;
|
|
353
|
-
const scope = effectScope();
|
|
354
|
-
window.__cleanup ||= [];
|
|
355
|
-
window.__cleanup.push(() => {
|
|
356
|
-
scope.stop();
|
|
357
|
-
});
|
|
358
|
-
const nuxtRootSetupResult = scope.run(() => NuxtRoot.setup(props2, {
|
|
359
|
-
...ctx,
|
|
360
|
-
expose: () => ({})
|
|
361
|
-
}));
|
|
362
|
-
onErrorCaptured((error, ...args) => {
|
|
363
|
-
if (isMountSettled) return;
|
|
364
|
-
isMountSettled = true;
|
|
365
|
-
try {
|
|
366
|
-
wrappedInstance?.appContext.config.errorHandler?.(error, ...args);
|
|
367
|
-
reject(error);
|
|
368
|
-
} catch (error2) {
|
|
369
|
-
reject(error2);
|
|
370
|
-
}
|
|
371
|
-
return false;
|
|
372
|
-
});
|
|
373
|
-
return nuxtRootSetupResult;
|
|
374
|
-
},
|
|
375
|
-
render: () => (
|
|
376
|
-
// See discussions in https://github.com/testing-library/vue-testing-library/issues/230
|
|
377
|
-
// we add this additional root element because otherwise testing-library breaks
|
|
378
|
-
// because there's no root element while Suspense is resolving
|
|
379
|
-
h$1(
|
|
380
|
-
WrapperComponent,
|
|
381
|
-
{},
|
|
382
|
-
{
|
|
383
|
-
default: () => h$1(
|
|
384
|
-
Suspense,
|
|
385
|
-
{
|
|
386
|
-
onResolve: () => nextTick().then(() => {
|
|
387
|
-
if (isMountSettled) return;
|
|
388
|
-
isMountSettled = true;
|
|
389
|
-
utils.setupState = setupState;
|
|
390
|
-
utils.rerender = async (props2) => {
|
|
391
|
-
Object.assign(setProps, props2);
|
|
392
|
-
await nextTick();
|
|
393
|
-
};
|
|
394
|
-
resolve(utils);
|
|
395
|
-
})
|
|
396
|
-
},
|
|
397
|
-
{
|
|
398
|
-
default: () => h$1({
|
|
399
|
-
name: "RenderHelper",
|
|
400
|
-
render: () => "",
|
|
401
|
-
async setup() {
|
|
402
|
-
const router = useRouter();
|
|
403
|
-
await router.replace(route);
|
|
404
|
-
const clonedComponent = {
|
|
405
|
-
components: {},
|
|
406
|
-
...component,
|
|
407
|
-
name: "RenderSuspendedComponent",
|
|
408
|
-
render,
|
|
409
|
-
setup: (props2, ctx) => wrappedSetup(props2, setupContext, ctx)
|
|
410
|
-
};
|
|
411
|
-
return () => h$1(clonedComponent, { ...props && typeof props === "object" ? props : {}, ...setProps, ...attrs }, setupContext.slots);
|
|
412
|
-
}
|
|
413
|
-
})
|
|
414
|
-
}
|
|
415
|
-
)
|
|
416
|
-
}
|
|
417
|
-
)
|
|
418
|
-
)
|
|
419
|
-
},
|
|
420
|
-
defu(_options, {
|
|
421
|
-
props,
|
|
422
|
-
slots,
|
|
423
|
-
attrs,
|
|
424
|
-
global: {
|
|
425
|
-
config: {
|
|
426
|
-
globalProperties: {
|
|
427
|
-
...vueApp.config.globalProperties,
|
|
428
|
-
// make all properties/keys enumerable.
|
|
429
|
-
...Object.fromEntries(
|
|
430
|
-
Object.getOwnPropertyNames(vueApp.config.globalProperties).map((key) => [key, vueApp.config.globalProperties[key]])
|
|
431
|
-
)
|
|
432
|
-
}
|
|
433
|
-
},
|
|
434
|
-
directives: vueApp._context.directives,
|
|
435
|
-
provide: vueApp._context.provides,
|
|
436
|
-
components: { RouterLink }
|
|
437
|
-
}
|
|
438
|
-
})
|
|
439
|
-
);
|
|
293
|
+
async function renderSuspended(component, options = {}) {
|
|
294
|
+
const wrapperId = "test-wrapper";
|
|
295
|
+
const suspendedHelperName = "RenderHelper";
|
|
296
|
+
const clonedComponentName = "RenderSuspendedComponent";
|
|
297
|
+
const { render: wrapperFn } = await import('@testing-library/vue');
|
|
298
|
+
cleanupAll();
|
|
299
|
+
document.getElementById(wrapperId)?.remove();
|
|
300
|
+
const { wrapper, setProps } = await wrapperSuspended(component, options, {
|
|
301
|
+
wrapperFn,
|
|
302
|
+
wrappedRender: (render) => () => h$1({
|
|
303
|
+
inheritAttrs: false,
|
|
304
|
+
render: () => h$1("div", { id: wrapperId }, render())
|
|
305
|
+
}),
|
|
306
|
+
suspendedHelperName,
|
|
307
|
+
clonedComponentName
|
|
440
308
|
});
|
|
309
|
+
wrapper.rerender = async (props) => {
|
|
310
|
+
setProps(props);
|
|
311
|
+
await nextTick();
|
|
312
|
+
};
|
|
313
|
+
return wrapper;
|
|
441
314
|
}
|
|
442
315
|
|
|
443
316
|
export { mockComponent, mockNuxtImport, mountSuspended, registerEndpoint, renderSuspended };
|
|
@@ -48,7 +48,7 @@ async function loadKit(rootDir) {
|
|
|
48
48
|
} catch (e) {
|
|
49
49
|
if (e.toString().includes("Cannot find module '@nuxt/kit'")) {
|
|
50
50
|
throw new Error(
|
|
51
|
-
"
|
|
51
|
+
"`@nuxt/test-utils` requires `@nuxt/kit` to be installed in your project. Try installing `nuxt` v3+ or `@nuxt/bridge` first."
|
|
52
52
|
);
|
|
53
53
|
}
|
|
54
54
|
throw e;
|
|
@@ -2,7 +2,7 @@ import { u as useTestContext, d as url, c as createTestContext, a as startServer
|
|
|
2
2
|
import { existsSync, promises } from 'node:fs';
|
|
3
3
|
import { resolve } from 'node:path';
|
|
4
4
|
import { defu } from 'defu';
|
|
5
|
-
import { l as loadKit } from './test-utils-nightly.
|
|
5
|
+
import { l as loadKit } from './test-utils-nightly.BIY9XRkB.mjs';
|
|
6
6
|
|
|
7
7
|
async function createBrowser() {
|
|
8
8
|
const ctx = useTestContext();
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
function isMessage(message) {
|
|
2
|
+
return message !== null && typeof message === "object" && "type" in message && message.type !== null && typeof message.type === "string" && "payload" in message && message.payload !== null && typeof message.payload === "object";
|
|
3
|
+
}
|
|
4
|
+
function createVitestTestSummary() {
|
|
5
|
+
return {
|
|
6
|
+
failedCount: 0,
|
|
7
|
+
passedCount: 0,
|
|
8
|
+
totalCount: 0
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
function sendMessageToHost(type, payload) {
|
|
12
|
+
process.send?.({ type, payload });
|
|
13
|
+
}
|
|
14
|
+
function listenHostMessages(listener) {
|
|
15
|
+
process.on("message", (message) => {
|
|
16
|
+
if (isMessage(message)) {
|
|
17
|
+
listener(message);
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
function sendMessageToCli(cli, type, payload) {
|
|
22
|
+
cli.send({ type, payload });
|
|
23
|
+
}
|
|
24
|
+
function listenCliMessages(cli, listener) {
|
|
25
|
+
cli.on("message", (message) => {
|
|
26
|
+
if (isMessage(message)) {
|
|
27
|
+
listener(message);
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export { listenHostMessages as a, sendMessageToHost as b, createVitestTestSummary as c, listenCliMessages as l, sendMessageToCli as s };
|
|
@@ -116,4 +116,4 @@ interface TestHooks {
|
|
|
116
116
|
}
|
|
117
117
|
|
|
118
118
|
export { $fetch as $, createBrowser as c, createPage as d, stopServer as e, fetch as f, getBrowser as g, startServer as s, url as u, waitForHydration as w };
|
|
119
|
-
export type { GotoOptions as G, NuxtPage as N, StartServerOptions as S, TestOptions as T,
|
|
119
|
+
export type { GotoOptions as G, NuxtPage as N, StartServerOptions as S, TestOptions as T, TestHooks as a, TestContext as b, TestRunner as h };
|
|
@@ -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-nightly.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-nightly",
|
|
3
|
-
"version": "3.21.1-
|
|
3
|
+
"version": "3.21.1-20251231-212503-838ed8b",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/nuxt/test-utils.git"
|
|
@@ -67,8 +67,8 @@
|
|
|
67
67
|
"dev:prepare": "nuxt prepare && unbuild --stub && pnpm -r dev:prepare"
|
|
68
68
|
},
|
|
69
69
|
"dependencies": {
|
|
70
|
-
"@nuxt/kit": "^3.20.
|
|
71
|
-
"c12": "^3.3.
|
|
70
|
+
"@nuxt/kit": "^3.20.2",
|
|
71
|
+
"c12": "^3.3.3",
|
|
72
72
|
"consola": "^3.4.2",
|
|
73
73
|
"defu": "^6.1.4",
|
|
74
74
|
"destr": "^2.0.5",
|
|
@@ -91,17 +91,17 @@
|
|
|
91
91
|
"ufo": "^1.6.1",
|
|
92
92
|
"unplugin": "^2.3.11",
|
|
93
93
|
"vitest-environment-nuxt": "^1.0.1",
|
|
94
|
-
"vue": "^3.5.
|
|
94
|
+
"vue": "^3.5.26"
|
|
95
95
|
},
|
|
96
96
|
"devDependencies": {
|
|
97
|
-
"@cucumber/cucumber": "12.
|
|
97
|
+
"@cucumber/cucumber": "12.5.0",
|
|
98
98
|
"@jest/globals": "30.2.0",
|
|
99
99
|
"@nuxt/devtools-kit": "2.7.0",
|
|
100
100
|
"@nuxt/eslint-config": "1.12.1",
|
|
101
|
-
"@nuxt/schema": "4.2.
|
|
101
|
+
"@nuxt/schema": "4.2.2",
|
|
102
102
|
"@playwright/test": "1.57.0",
|
|
103
103
|
"@testing-library/vue": "8.1.0",
|
|
104
|
-
"@types/bun": "1.3.
|
|
104
|
+
"@types/bun": "1.3.5",
|
|
105
105
|
"@types/estree": "1.0.8",
|
|
106
106
|
"@types/jsdom": "27.0.0",
|
|
107
107
|
"@types/node": "latest",
|
|
@@ -111,12 +111,12 @@
|
|
|
111
111
|
"compatx": "0.2.0",
|
|
112
112
|
"eslint": "9.39.2",
|
|
113
113
|
"installed-check": "9.3.0",
|
|
114
|
-
"knip": "5.
|
|
114
|
+
"knip": "5.78.0",
|
|
115
115
|
"nitropack": "2.12.9",
|
|
116
|
-
"nuxt": "4.2.
|
|
116
|
+
"nuxt": "4.2.2",
|
|
117
117
|
"pkg-pr-new": "0.0.62",
|
|
118
118
|
"playwright-core": "1.57.0",
|
|
119
|
-
"rollup": "4.
|
|
119
|
+
"rollup": "4.54.0",
|
|
120
120
|
"semver": "7.7.3",
|
|
121
121
|
"typescript": "5.9.3",
|
|
122
122
|
"unbuild": "latest",
|
|
@@ -124,7 +124,7 @@
|
|
|
124
124
|
"vite": "7.3.0",
|
|
125
125
|
"vitest": "3.2.4",
|
|
126
126
|
"vue-router": "4.6.4",
|
|
127
|
-
"vue-tsc": "3.1
|
|
127
|
+
"vue-tsc": "3.2.1"
|
|
128
128
|
},
|
|
129
129
|
"peerDependencies": {
|
|
130
130
|
"@cucumber/cucumber": "^10.3.1 || >=11.0.0",
|
|
@@ -170,18 +170,18 @@
|
|
|
170
170
|
}
|
|
171
171
|
},
|
|
172
172
|
"resolutions": {
|
|
173
|
-
"@cucumber/cucumber": "12.
|
|
174
|
-
"@nuxt/schema": "4.2.
|
|
173
|
+
"@cucumber/cucumber": "12.5.0",
|
|
174
|
+
"@nuxt/schema": "4.2.2",
|
|
175
175
|
"@nuxt/test-utils": "workspace:*",
|
|
176
176
|
"@types/node": "24.10.4",
|
|
177
|
-
"rollup": "4.
|
|
177
|
+
"rollup": "4.54.0",
|
|
178
178
|
"vite": "7.3.0",
|
|
179
179
|
"vite-node": "5.2.0",
|
|
180
180
|
"vitest": "3.2.4",
|
|
181
|
-
"vue": "^3.5.
|
|
181
|
+
"vue": "^3.5.26"
|
|
182
182
|
},
|
|
183
183
|
"engines": {
|
|
184
184
|
"node": "^20.0.0 || ^22.0.0 || >=24.0.0"
|
|
185
185
|
},
|
|
186
|
-
"packageManager": "pnpm@10.26.
|
|
186
|
+
"packageManager": "pnpm@10.26.2"
|
|
187
187
|
}
|