@nuxt/test-utils 3.20.1 → 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 +1 -1
- package/dist/config.d.mts +2 -3
- package/dist/config.mjs +27 -51
- package/dist/e2e.d.mts +2 -2
- package/dist/e2e.mjs +21 -13
- package/dist/experimental.mjs +1 -1
- package/dist/module.mjs +286 -151
- package/dist/playwright.d.mts +1 -1
- package/dist/playwright.mjs +7 -3
- package/dist/runtime/global-setup.mjs +3 -4
- package/dist/runtime/shared/environment.mjs +0 -3
- package/dist/runtime/shared/nuxt.d.ts +1 -1
- package/dist/runtime/shared/nuxt.mjs +10 -2
- package/dist/runtime/shared/vue-wrapper-plugin.d.ts +50 -0
- package/dist/runtime/shared/vue-wrapper-plugin.mjs +41 -0
- package/dist/runtime-utils/index.d.mts +59 -27
- package/dist/runtime-utils/index.mjs +206 -372
- package/dist/shared/test-utils.BIY9XRkB.mjs +67 -0
- package/dist/shared/{test-utils.CtwoJP76.mjs → test-utils.C_clWQBc.mjs} +4 -4
- package/dist/shared/{test-utils.CtoalVlS.mjs → test-utils.D2ZzXztg.mjs} +9 -8
- package/dist/shared/test-utils.DDUpsMYL.mjs +32 -0
- package/dist/shared/{test-utils.20kU0tZa.d.mts → test-utils.ZByFDqps.d.mts} +1 -1
- package/dist/vitest-environment.mjs +0 -3
- package/dist/vitest-wrapper/cli.d.mts +2 -0
- package/dist/vitest-wrapper/cli.mjs +78 -0
- package/package.json +37 -49
package/dist/module.mjs
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
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 { 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';
|
|
9
4
|
import { walk } from 'estree-walker';
|
|
10
5
|
import MagicString from 'magic-string';
|
|
11
6
|
import { createUnplugin } from 'unplugin';
|
|
7
|
+
import { l as loadKit } from './shared/test-utils.BIY9XRkB.mjs';
|
|
12
8
|
import { readFileSync } from 'node:fs';
|
|
13
|
-
import {
|
|
14
|
-
import '
|
|
15
|
-
import '
|
|
16
|
-
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.DDUpsMYL.mjs';
|
|
14
|
+
import { distDir } from '#dirs';
|
|
17
15
|
import 'destr';
|
|
18
16
|
import 'scule';
|
|
17
|
+
import 'node:url';
|
|
18
|
+
import 'exsolve';
|
|
19
19
|
|
|
20
20
|
const PLUGIN_NAME$1 = "nuxt:vitest:mock-transform";
|
|
21
21
|
const HELPER_MOCK_IMPORT = "mockNuxtImport";
|
|
@@ -67,16 +67,16 @@ const createMockPlugin = (ctx) => createUnplugin(() => {
|
|
|
67
67
|
startOf(node)
|
|
68
68
|
);
|
|
69
69
|
}
|
|
70
|
-
const
|
|
71
|
-
|
|
70
|
+
const importTarget = node.arguments[0];
|
|
71
|
+
const name = isLiteral(importTarget) ? importTarget.value : isIdentifier(importTarget) ? importTarget.name : void 0;
|
|
72
|
+
if (typeof name !== "string") {
|
|
72
73
|
return this.error(
|
|
73
74
|
new Error(
|
|
74
|
-
`The first argument of ${HELPER_MOCK_IMPORT}() must be a string literal`
|
|
75
|
+
`The first argument of ${HELPER_MOCK_IMPORT}() must be a string literal or mocked target`
|
|
75
76
|
),
|
|
76
|
-
startOf(
|
|
77
|
+
startOf(importTarget)
|
|
77
78
|
);
|
|
78
79
|
}
|
|
79
|
-
const name = importName.value;
|
|
80
80
|
const importItem = ctx.imports.find((_) => name === (_.as || _.name));
|
|
81
81
|
if (!importItem) {
|
|
82
82
|
console.log({ imports: ctx.imports });
|
|
@@ -262,8 +262,8 @@ function endOf(node) {
|
|
|
262
262
|
return "range" in node && node.range ? node.range[1] : "end" in node ? node.end : void 0;
|
|
263
263
|
}
|
|
264
264
|
|
|
265
|
-
function setupImportMocking() {
|
|
266
|
-
const
|
|
265
|
+
async function setupImportMocking(nuxt) {
|
|
266
|
+
const { addVitePlugin } = await loadKit(nuxt.options.rootDir);
|
|
267
267
|
const ctx = {
|
|
268
268
|
components: [],
|
|
269
269
|
imports: []
|
|
@@ -295,29 +295,233 @@ function setupImportMocking() {
|
|
|
295
295
|
|
|
296
296
|
const PLUGIN_NAME = "nuxt:vitest:nuxt-root-stub";
|
|
297
297
|
const STUB_ID = "nuxt-vitest-app-entry";
|
|
298
|
-
const NuxtRootStubPlugin =
|
|
299
|
-
const
|
|
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})?$`);
|
|
300
303
|
return {
|
|
301
304
|
name: PLUGIN_NAME,
|
|
302
305
|
enforce: "pre",
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
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
|
|
308
317
|
},
|
|
309
|
-
async
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
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();
|
|
313
384
|
}
|
|
314
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 };
|
|
315
520
|
}
|
|
316
521
|
};
|
|
317
|
-
}
|
|
522
|
+
}
|
|
318
523
|
|
|
319
|
-
const
|
|
320
|
-
const module = defineNuxtModule({
|
|
524
|
+
const module$1 = defineNuxtModule({
|
|
321
525
|
meta: {
|
|
322
526
|
name: "@nuxt/test-utils",
|
|
323
527
|
configKey: "testUtils"
|
|
@@ -328,137 +532,68 @@ const module = defineNuxtModule({
|
|
|
328
532
|
},
|
|
329
533
|
async setup(options, nuxt) {
|
|
330
534
|
if (nuxt.options.test || nuxt.options.dev) {
|
|
331
|
-
setupImportMocking();
|
|
535
|
+
await setupImportMocking(nuxt);
|
|
332
536
|
}
|
|
537
|
+
const { addVitePlugin } = await loadKit(nuxt.options.rootDir);
|
|
333
538
|
const resolver = createResolver(import.meta.url);
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
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
|
+
}
|
|
338
545
|
if (!nuxt.options.test && !nuxt.options.dev) {
|
|
339
546
|
nuxt.options.vite.define ||= {};
|
|
340
547
|
nuxt.options.vite.define["import.meta.vitest"] = "undefined";
|
|
341
548
|
}
|
|
342
|
-
nuxt.hook("prepare:types", (
|
|
343
|
-
references.push({ types: "vitest/import-meta" });
|
|
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.*")));
|
|
554
|
+
if (nuxt.options.workspaceDir !== nuxt.options.rootDir) {
|
|
555
|
+
ctx.nodeTsConfig.include.push(relative(nuxt.options.buildDir, join(nuxt.options.workspaceDir, "vitest.config.*")));
|
|
556
|
+
}
|
|
557
|
+
}
|
|
344
558
|
});
|
|
345
559
|
if (!nuxt.options.dev) return;
|
|
346
560
|
if (process.env.TEST || process.env.VITE_TEST) return;
|
|
347
|
-
const
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
if (isClient) resolve(config);
|
|
351
|
-
});
|
|
352
|
-
});
|
|
353
|
-
});
|
|
354
|
-
let loaded = false;
|
|
355
|
-
let promise;
|
|
356
|
-
let ctx = void 0;
|
|
357
|
-
let testFiles = null;
|
|
358
|
-
const updateTabs = debounce(() => {
|
|
359
|
-
nuxt.callHook("devtools:customTabs:refresh");
|
|
360
|
-
}, 100);
|
|
361
|
-
let URL;
|
|
362
|
-
async function start() {
|
|
363
|
-
const { mergeConfig } = await importModule("vite", { paths: nuxt.options.modulesDir });
|
|
364
|
-
const rawViteConfig = mergeConfig({}, await rawViteConfigPromise);
|
|
365
|
-
const viteConfig = await getVitestConfigFromNuxt({ nuxt, viteConfig: defu({ test: options.vitestConfig }, rawViteConfig) });
|
|
366
|
-
viteConfig.plugins = (viteConfig.plugins || []).filter((p) => {
|
|
367
|
-
return !p || !("name" in p) || !vitePluginBlocklist.includes(p.name);
|
|
368
|
-
});
|
|
369
|
-
viteConfig.test.environmentMatchGlobs ||= [];
|
|
370
|
-
viteConfig.test.environmentMatchGlobs.push(
|
|
371
|
-
["**/*.nuxt.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}", "nuxt"],
|
|
372
|
-
["{test,tests}/nuxt/**.*", "nuxt"]
|
|
373
|
-
);
|
|
374
|
-
process.env.__NUXT_VITEST_RESOLVED__ = "true";
|
|
375
|
-
const { startVitest } = await import(pathToFileURL(await resolvePath("vitest/node")).href);
|
|
376
|
-
const customReporter = {
|
|
377
|
-
onInit(_ctx) {
|
|
378
|
-
ctx = _ctx;
|
|
379
|
-
},
|
|
380
|
-
onTaskUpdate() {
|
|
381
|
-
testFiles = ctx.state.getFiles();
|
|
382
|
-
updateTabs();
|
|
383
|
-
},
|
|
384
|
-
onFinished() {
|
|
385
|
-
testFiles = ctx.state.getFiles();
|
|
386
|
-
updateTabs();
|
|
387
|
-
}
|
|
388
|
-
};
|
|
389
|
-
const watchMode = !process.env.NUXT_VITEST_DEV_TEST && !isCI;
|
|
390
|
-
const PORT = await getPort({ port: 15555 });
|
|
391
|
-
const PROTOCOL = nuxt.options.devServer.https ? "https" : "http";
|
|
392
|
-
URL = `${PROTOCOL}://localhost:${PORT}/__vitest__/`;
|
|
393
|
-
const overrides = watchMode ? {
|
|
394
|
-
passWithNoTests: true,
|
|
395
|
-
reporters: options.logToConsole ? [
|
|
396
|
-
...toArray(options.vitestConfig?.reporters ?? ["default"]),
|
|
397
|
-
customReporter
|
|
398
|
-
] : [customReporter],
|
|
399
|
-
// do not report to console
|
|
400
|
-
watch: true,
|
|
401
|
-
ui: true,
|
|
402
|
-
open: false,
|
|
403
|
-
api: {
|
|
404
|
-
port: PORT
|
|
405
|
-
}
|
|
406
|
-
} : { watch: false };
|
|
407
|
-
const promise2 = startVitest("test", [], defu(overrides, viteConfig.test), viteConfig);
|
|
408
|
-
promise2.catch(() => process.exit(1));
|
|
409
|
-
if (watchMode) {
|
|
410
|
-
logger.info(`Vitest UI starting on ${URL}`);
|
|
411
|
-
nuxt.hook("close", () => promise2.then((v) => v?.close()));
|
|
412
|
-
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
413
|
-
} else {
|
|
414
|
-
promise2.then((v) => nuxt.close().then(() => v?.close()).then(() => process.exit()));
|
|
415
|
-
}
|
|
416
|
-
loaded = true;
|
|
417
|
-
}
|
|
418
|
-
nuxt.hook("devtools:customTabs", (tabs) => {
|
|
419
|
-
const failedCount = testFiles?.filter((f) => f.result?.state === "fail").length ?? 0;
|
|
420
|
-
const passedCount = testFiles?.filter((f) => f.result?.state === "pass").length ?? 0;
|
|
421
|
-
const totalCount = testFiles?.length ?? 0;
|
|
422
|
-
tabs.push({
|
|
423
|
-
title: "Vitest",
|
|
424
|
-
name: "vitest",
|
|
425
|
-
icon: "logos-vitest",
|
|
426
|
-
view: loaded ? {
|
|
427
|
-
type: "iframe",
|
|
428
|
-
src: URL
|
|
429
|
-
} : {
|
|
430
|
-
type: "launch",
|
|
431
|
-
description: "Start tests along with Nuxt",
|
|
432
|
-
actions: [
|
|
433
|
-
{
|
|
434
|
-
label: promise ? "Starting..." : "Start Vitest",
|
|
435
|
-
pending: !!promise,
|
|
436
|
-
handle: () => {
|
|
437
|
-
promise = promise || start();
|
|
438
|
-
return promise;
|
|
439
|
-
}
|
|
440
|
-
}
|
|
441
|
-
]
|
|
442
|
-
},
|
|
443
|
-
extraTabVNode: totalCount ? h("div", { style: { color: failedCount ? "orange" : "green" } }, [
|
|
444
|
-
h("span", {}, passedCount),
|
|
445
|
-
h("span", { style: { opacity: "0.5", fontSize: "0.9em" } }, "/"),
|
|
446
|
-
h(
|
|
447
|
-
"span",
|
|
448
|
-
{ style: { opacity: "0.8", fontSize: "0.9em" } },
|
|
449
|
-
totalCount
|
|
450
|
-
)
|
|
451
|
-
]) : void 0
|
|
452
|
-
});
|
|
561
|
+
const vitestWrapper2 = createVitestWrapper(options, nuxt);
|
|
562
|
+
nuxt.hook("devtools:before", async () => {
|
|
563
|
+
await setupDevTools(vitestWrapper2, nuxt);
|
|
453
564
|
});
|
|
454
565
|
if (options.startOnBoot) {
|
|
455
|
-
|
|
456
|
-
promise.then(updateTabs);
|
|
566
|
+
vitestWrapper2.start();
|
|
457
567
|
}
|
|
458
568
|
}
|
|
459
569
|
});
|
|
460
|
-
function
|
|
461
|
-
|
|
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;
|
|
462
597
|
}
|
|
463
598
|
|
|
464
|
-
export { module as default };
|
|
599
|
+
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.ZByFDqps.mjs';
|
|
5
5
|
import '@nuxt/schema';
|
|
6
6
|
import 'tinyexec';
|
|
7
7
|
|
package/dist/playwright.mjs
CHANGED
|
@@ -1,16 +1,20 @@
|
|
|
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.
|
|
4
|
+
import { w as waitForHydration, d as createTest } from './shared/test-utils.D2ZzXztg.mjs';
|
|
5
5
|
import 'node:path';
|
|
6
6
|
import 'ufo';
|
|
7
7
|
import 'std-env';
|
|
8
8
|
import 'consola';
|
|
9
9
|
import 'node:fs';
|
|
10
|
-
import '
|
|
11
|
-
import
|
|
10
|
+
import 'destr';
|
|
11
|
+
import 'scule';
|
|
12
|
+
import 'node:url';
|
|
13
|
+
import 'exsolve';
|
|
14
|
+
import { d as url } from './shared/test-utils.C_clWQBc.mjs';
|
|
12
15
|
import 'pathe';
|
|
13
16
|
import '#dirs';
|
|
17
|
+
import './shared/test-utils.BIY9XRkB.mjs';
|
|
14
18
|
import 'tinyexec';
|
|
15
19
|
import 'get-port-please';
|
|
16
20
|
import 'ofetch';
|
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { consola } from "consola";
|
|
2
2
|
import { createTest, exposeContextToEnv } from "@nuxt/test-utils/e2e";
|
|
3
|
-
const kit = _kit.default || _kit;
|
|
4
3
|
const options = JSON.parse(process.env.NUXT_TEST_OPTIONS || "{}");
|
|
5
4
|
const hooks = createTest(options);
|
|
6
5
|
export const setup = async () => {
|
|
7
|
-
|
|
6
|
+
consola.info("Building Nuxt app...");
|
|
8
7
|
await hooks.beforeAll();
|
|
9
8
|
exposeContextToEnv();
|
|
10
|
-
|
|
9
|
+
consola.info("Running tests...");
|
|
11
10
|
};
|
|
12
11
|
export const teardown = async () => {
|
|
13
12
|
await hooks.afterAll();
|
|
@@ -78,9 +78,6 @@ export async function setupWindow(win, environmentOptions) {
|
|
|
78
78
|
return _fetch(input, _init);
|
|
79
79
|
};
|
|
80
80
|
win.$fetch = createFetch({ fetch: win.fetch, Headers: win.Headers });
|
|
81
|
-
win.$fetch.create = (options = {}) => {
|
|
82
|
-
return createFetch({ fetch: win.fetch, Headers: win.Headers, ...options });
|
|
83
|
-
};
|
|
84
81
|
win.__registry = registry;
|
|
85
82
|
win.__app = h3App;
|
|
86
83
|
const timestamp = Date.now();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare function setupNuxt(): Promise<
|
|
1
|
+
export declare function setupNuxt(): Promise<any>;
|
|
@@ -1,7 +1,15 @@
|
|
|
1
|
+
import { getVueWrapperPlugin } from "./vue-wrapper-plugin.mjs";
|
|
1
2
|
export async function setupNuxt() {
|
|
2
3
|
const { useRouter } = await import("#app/composables/router");
|
|
3
4
|
await import("#app/nuxt-vitest-app-entry").then((r) => r.default());
|
|
4
5
|
const nuxtApp = useNuxtApp();
|
|
5
|
-
|
|
6
|
-
|
|
6
|
+
function sync() {
|
|
7
|
+
return nuxtApp._route.sync ? nuxtApp._route.sync() : nuxtApp.callHook("page:finish");
|
|
8
|
+
}
|
|
9
|
+
const { hasNuxtPage } = getVueWrapperPlugin();
|
|
10
|
+
useRouter().afterEach(() => {
|
|
11
|
+
if (hasNuxtPage()) return;
|
|
12
|
+
return sync();
|
|
13
|
+
});
|
|
14
|
+
return sync();
|
|
7
15
|
}
|
|
@@ -0,0 +1,50 @@
|
|
|
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;
|
|
47
|
+
hasNuxtPage(): boolean;
|
|
48
|
+
_hasComponent(componentName: string): boolean;
|
|
49
|
+
};
|
|
50
|
+
export {};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { config } from "@vue/test-utils";
|
|
2
|
+
const PLUGIN_NAME = "nuxt-test-utils";
|
|
3
|
+
export function getVueWrapperPlugin() {
|
|
4
|
+
const installed = config.plugins.VueWrapper.installedPlugins.find(({ options: options2 }) => options2._name === PLUGIN_NAME);
|
|
5
|
+
if (installed) return installed.options;
|
|
6
|
+
const options = createPluginOptions();
|
|
7
|
+
config.plugins.VueWrapper.install((instance, options2) => {
|
|
8
|
+
options2.addInstance(instance);
|
|
9
|
+
return {};
|
|
10
|
+
}, options);
|
|
11
|
+
return options;
|
|
12
|
+
}
|
|
13
|
+
function createPluginOptions() {
|
|
14
|
+
const options = {
|
|
15
|
+
_name: PLUGIN_NAME,
|
|
16
|
+
_instances: [],
|
|
17
|
+
get instances() {
|
|
18
|
+
const instances = [];
|
|
19
|
+
options._instances = options._instances.filter((ref) => {
|
|
20
|
+
const instance = ref.deref();
|
|
21
|
+
if (!instance) return false;
|
|
22
|
+
instances.push(instance);
|
|
23
|
+
return true;
|
|
24
|
+
});
|
|
25
|
+
return instances;
|
|
26
|
+
},
|
|
27
|
+
addInstance(instance) {
|
|
28
|
+
if (options.instances.includes(instance)) return;
|
|
29
|
+
options._instances.push(new WeakRef(instance));
|
|
30
|
+
},
|
|
31
|
+
hasNuxtPage() {
|
|
32
|
+
return options._hasComponent("NuxtPage");
|
|
33
|
+
},
|
|
34
|
+
_hasComponent(componentName) {
|
|
35
|
+
return options.instances.some(
|
|
36
|
+
(v) => v.exists() && v.findComponent({ name: componentName }).exists()
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
return options;
|
|
41
|
+
}
|