@nuxt/test-utils 4.0.2 → 4.0.3
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/chunks/suspended.mjs +221 -0
- package/dist/config.mjs +13 -0
- package/dist/e2e.d.mts +2 -2
- package/dist/e2e.mjs +3 -3
- package/dist/experimental.mjs +1 -1
- package/dist/module.mjs +7 -1
- package/dist/playwright.d.mts +1 -1
- package/dist/playwright.mjs +2 -2
- package/dist/runtime-utils/index.mjs +5 -217
- package/dist/shared/{test-utils.BLyxqr96.d.mts → test-utils.BX46zKiB.d.mts} +7 -0
- package/dist/shared/{test-utils.BsmyE2FA.mjs → test-utils.BrQgu3Ob.mjs} +44 -21
- package/dist/shared/{test-utils.E_cAGA8l.mjs → test-utils.RVsKJA_7.mjs} +1 -1
- package/package.json +25 -25
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import { reactive, h as h$1, Suspense, nextTick, getCurrentInstance, onErrorCaptured, effectScope } from 'vue';
|
|
2
|
+
import { defineComponent, h, tryUseNuxtApp, useRouter } from '#imports';
|
|
3
|
+
import NuxtRoot from '#build/root-component.mjs';
|
|
4
|
+
import { useLink } from 'vue-router';
|
|
5
|
+
|
|
6
|
+
const RouterLink = defineComponent({
|
|
7
|
+
functional: true,
|
|
8
|
+
props: {
|
|
9
|
+
to: {
|
|
10
|
+
type: [String, Object],
|
|
11
|
+
required: true
|
|
12
|
+
},
|
|
13
|
+
custom: Boolean,
|
|
14
|
+
replace: Boolean,
|
|
15
|
+
// Not implemented
|
|
16
|
+
activeClass: String,
|
|
17
|
+
exactActiveClass: String,
|
|
18
|
+
ariaCurrentValue: String
|
|
19
|
+
},
|
|
20
|
+
setup: (props, { slots }) => {
|
|
21
|
+
const link = useLink(props);
|
|
22
|
+
return () => {
|
|
23
|
+
const route = link.route.value;
|
|
24
|
+
const href = link.href.value;
|
|
25
|
+
const isActive = link.isActive.value;
|
|
26
|
+
const isExactActive = link.isExactActive.value;
|
|
27
|
+
return props.custom ? slots.default?.({ href, navigate: link.navigate, route, isActive, isExactActive }) : h(
|
|
28
|
+
"a",
|
|
29
|
+
{
|
|
30
|
+
href,
|
|
31
|
+
onClick: (e) => {
|
|
32
|
+
e.preventDefault();
|
|
33
|
+
return link.navigate(e);
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
slots
|
|
37
|
+
);
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
function cleanupAll() {
|
|
43
|
+
for (const fn of (window.__cleanup || []).splice(0)) {
|
|
44
|
+
fn();
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
function addCleanup(fn) {
|
|
48
|
+
window.__cleanup ||= [];
|
|
49
|
+
window.__cleanup.push(fn);
|
|
50
|
+
}
|
|
51
|
+
function runEffectScope(fn) {
|
|
52
|
+
const scope = effectScope();
|
|
53
|
+
addCleanup(() => scope.stop());
|
|
54
|
+
return scope.run(fn);
|
|
55
|
+
}
|
|
56
|
+
function wrapperSuspended(component, options, {
|
|
57
|
+
wrapperFn,
|
|
58
|
+
wrappedRender = (fn) => fn,
|
|
59
|
+
suspendedHelperName,
|
|
60
|
+
clonedComponentName
|
|
61
|
+
}) {
|
|
62
|
+
const { props = {}, attrs = {} } = options;
|
|
63
|
+
const { route = "/", scoped = false, ...wrapperFnOptions } = options;
|
|
64
|
+
const vueApp = tryUseNuxtApp()?.vueApp || globalThis.__unctx__.get("nuxt-app").tryUse().vueApp;
|
|
65
|
+
const {
|
|
66
|
+
render: componentRender,
|
|
67
|
+
setup: componentSetup,
|
|
68
|
+
...componentRest
|
|
69
|
+
} = component;
|
|
70
|
+
let wrappedInstance = null;
|
|
71
|
+
let setupContext;
|
|
72
|
+
let setupState;
|
|
73
|
+
const setProps = reactive({});
|
|
74
|
+
function patchInstanceAppContext() {
|
|
75
|
+
const app = getCurrentInstance()?.appContext.app;
|
|
76
|
+
if (!app) return;
|
|
77
|
+
for (const [key, value] of Object.entries(vueApp)) {
|
|
78
|
+
if (key in app) continue;
|
|
79
|
+
app[key] = value;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
const ClonedComponent = {
|
|
83
|
+
components: {},
|
|
84
|
+
...component,
|
|
85
|
+
name: clonedComponentName,
|
|
86
|
+
async setup(props2, instanceContext) {
|
|
87
|
+
const currentInstance = getCurrentInstance();
|
|
88
|
+
if (currentInstance) {
|
|
89
|
+
currentInstance.emit = (event, ...args) => {
|
|
90
|
+
setupContext.emit(event, ...args);
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
if (!componentSetup) return;
|
|
94
|
+
const result = scoped ? await runEffectScope(() => componentSetup(props2, setupContext)) : await componentSetup(props2, setupContext);
|
|
95
|
+
if (wrappedInstance?.exposed) {
|
|
96
|
+
instanceContext.expose(wrappedInstance.exposed);
|
|
97
|
+
}
|
|
98
|
+
setupState = result && typeof result === "object" ? result : {};
|
|
99
|
+
return result;
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
const SuspendedHelper = {
|
|
103
|
+
name: suspendedHelperName,
|
|
104
|
+
render: () => "",
|
|
105
|
+
async setup() {
|
|
106
|
+
if (route) {
|
|
107
|
+
const router = useRouter();
|
|
108
|
+
await router.replace(route);
|
|
109
|
+
}
|
|
110
|
+
return () => h$1(ClonedComponent, { ...props, ...setProps, ...attrs }, setupContext.slots);
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
return new Promise((resolve, reject) => {
|
|
114
|
+
let isMountSettled = false;
|
|
115
|
+
const wrapper = wrapperFn(
|
|
116
|
+
{
|
|
117
|
+
inheritAttrs: false,
|
|
118
|
+
__cssModules: componentRest.__cssModules,
|
|
119
|
+
setup: (props2, ctx) => {
|
|
120
|
+
patchInstanceAppContext();
|
|
121
|
+
wrappedInstance = getCurrentInstance();
|
|
122
|
+
setupContext = ctx;
|
|
123
|
+
const nuxtRootSetupResult = runEffectScope(
|
|
124
|
+
() => NuxtRoot.setup(props2, {
|
|
125
|
+
...ctx,
|
|
126
|
+
expose: () => {
|
|
127
|
+
}
|
|
128
|
+
})
|
|
129
|
+
);
|
|
130
|
+
onErrorCaptured((error, ...args) => {
|
|
131
|
+
if (isMountSettled) return;
|
|
132
|
+
isMountSettled = true;
|
|
133
|
+
try {
|
|
134
|
+
wrappedInstance?.appContext.config.errorHandler?.(error, ...args);
|
|
135
|
+
reject(error);
|
|
136
|
+
} catch (error2) {
|
|
137
|
+
reject(error2);
|
|
138
|
+
}
|
|
139
|
+
return false;
|
|
140
|
+
});
|
|
141
|
+
return nuxtRootSetupResult;
|
|
142
|
+
},
|
|
143
|
+
render: wrappedRender(() => h$1(
|
|
144
|
+
Suspense,
|
|
145
|
+
{
|
|
146
|
+
onResolve: () => nextTick().then(() => {
|
|
147
|
+
if (isMountSettled) return;
|
|
148
|
+
isMountSettled = true;
|
|
149
|
+
wrapper.setupState = setupState;
|
|
150
|
+
resolve({
|
|
151
|
+
wrapper,
|
|
152
|
+
setProps: (props2) => {
|
|
153
|
+
Object.assign(setProps, props2);
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
})
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
default: () => h$1(SuspendedHelper)
|
|
160
|
+
}
|
|
161
|
+
))
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
...wrapperFnOptions,
|
|
165
|
+
global: mergeComponentMountingGlobalOptions(wrapperFnOptions.global, {
|
|
166
|
+
config: {
|
|
167
|
+
globalProperties: makeAllPropertiesEnumerable(
|
|
168
|
+
vueApp.config.globalProperties
|
|
169
|
+
)
|
|
170
|
+
},
|
|
171
|
+
directives: vueApp._context.directives,
|
|
172
|
+
provide: vueApp._context.provides,
|
|
173
|
+
stubs: {
|
|
174
|
+
Suspense: false,
|
|
175
|
+
[SuspendedHelper.name]: false,
|
|
176
|
+
[ClonedComponent.name]: false
|
|
177
|
+
},
|
|
178
|
+
components: { ...vueApp._context.components, RouterLink }
|
|
179
|
+
})
|
|
180
|
+
}
|
|
181
|
+
);
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
function mergeComponentMountingGlobalOptions(options = {}, defaults = {}) {
|
|
185
|
+
const compilerOptions = {
|
|
186
|
+
...defaults.config?.compilerOptions,
|
|
187
|
+
...options.config?.compilerOptions
|
|
188
|
+
};
|
|
189
|
+
return {
|
|
190
|
+
...options,
|
|
191
|
+
mixins: [...defaults.mixins || [], ...options.mixins || []],
|
|
192
|
+
stubs: {
|
|
193
|
+
...defaults.stubs,
|
|
194
|
+
...Array.isArray(options.stubs) ? Object.fromEntries(options.stubs.map((n) => [n, true])) : options.stubs
|
|
195
|
+
},
|
|
196
|
+
plugins: [...defaults.plugins || [], ...options.plugins || []],
|
|
197
|
+
components: { ...defaults.components, ...options.components },
|
|
198
|
+
provide: { ...defaults.provide, ...options.provide },
|
|
199
|
+
mocks: { ...defaults.mocks, ...options.mocks },
|
|
200
|
+
config: {
|
|
201
|
+
...defaults.config,
|
|
202
|
+
...options.config,
|
|
203
|
+
...Object.keys(compilerOptions).length ? { compilerOptions } : void 0,
|
|
204
|
+
globalProperties: {
|
|
205
|
+
...defaults.config?.globalProperties,
|
|
206
|
+
...options.config?.globalProperties
|
|
207
|
+
}
|
|
208
|
+
},
|
|
209
|
+
directives: { ...defaults.directives, ...options.directives }
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
function makeAllPropertiesEnumerable(target) {
|
|
213
|
+
return {
|
|
214
|
+
...target,
|
|
215
|
+
...Object.fromEntries(
|
|
216
|
+
Object.getOwnPropertyNames(target).map((key) => [key, target[key]])
|
|
217
|
+
)
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
export { cleanupAll, wrapperSuspended };
|
package/dist/config.mjs
CHANGED
|
@@ -290,9 +290,22 @@ function defineVitestConfig(config = {}) {
|
|
|
290
290
|
return resolvedConfig;
|
|
291
291
|
});
|
|
292
292
|
}
|
|
293
|
+
function isCoverageEnabled(config) {
|
|
294
|
+
if (config.test && "coverage" in config.test && config.test.coverage?.enabled) {
|
|
295
|
+
return true;
|
|
296
|
+
}
|
|
297
|
+
return process.argv.some((arg) => arg === "--coverage" || arg === "--coverage.enabled" || arg === "--coverage=true" || arg === "--coverage.enabled=true");
|
|
298
|
+
}
|
|
293
299
|
async function resolveConfig(config) {
|
|
294
300
|
const overrides = config.test?.environmentOptions?.nuxt?.overrides || {};
|
|
295
301
|
overrides.rootDir = config.test?.environmentOptions?.nuxt?.rootDir;
|
|
302
|
+
if (isCoverageEnabled(config)) {
|
|
303
|
+
if (overrides.sourcemap === void 0) {
|
|
304
|
+
overrides.sourcemap = { client: true };
|
|
305
|
+
} else if (typeof overrides.sourcemap === "object" && overrides.sourcemap.client === void 0) {
|
|
306
|
+
overrides.sourcemap.client = true;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
296
309
|
if (config.test?.setupFiles && !Array.isArray(config.test.setupFiles)) {
|
|
297
310
|
config.test.setupFiles = [config.test.setupFiles].filter(Boolean);
|
|
298
311
|
}
|
package/dist/e2e.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { T as TestOptions, b as TestContext, a as TestHooks } from './shared/test-utils.
|
|
2
|
-
export { $ as $fetch, G as GotoOptions, N as NuxtPage, S as StartServerOptions, c as TestRunner, d as createBrowser, e as createPage, f as fetch, g as getBrowser, s as startServer, h as stopServer, u as url, w as waitForHydration } from './shared/test-utils.
|
|
1
|
+
import { T as TestOptions, b as TestContext, a as TestHooks } from './shared/test-utils.BX46zKiB.mjs';
|
|
2
|
+
export { $ as $fetch, G as GotoOptions, N as NuxtPage, S as StartServerOptions, c as TestRunner, d as createBrowser, e as createPage, f as fetch, g as getBrowser, s as startServer, h as stopServer, u as url, w as waitForHydration } from './shared/test-utils.BX46zKiB.mjs';
|
|
3
3
|
import { LogType } from 'consola';
|
|
4
4
|
import 'playwright-core';
|
|
5
5
|
import '@nuxt/schema';
|
package/dist/e2e.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export { b as buildFixture, c as createBrowser, a as createPage, d as createTest, g as getBrowser, l as loadFixture, s as setup, e as setupMaps, w as waitForHydration } from './shared/test-utils.
|
|
2
|
-
import { u as useTestContext } from './shared/test-utils.
|
|
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.
|
|
1
|
+
export { b as buildFixture, c as createBrowser, a as createPage, d as createTest, g as getBrowser, l as loadFixture, s as setup, e as setupMaps, w as waitForHydration } from './shared/test-utils.RVsKJA_7.mjs';
|
|
2
|
+
import { u as useTestContext } from './shared/test-utils.BrQgu3Ob.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.BrQgu3Ob.mjs';
|
|
4
4
|
import { consola } from 'consola';
|
|
5
5
|
import { resolve } from 'pathe';
|
|
6
6
|
import { distDir } from '#dirs';
|
package/dist/experimental.mjs
CHANGED
|
@@ -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.
|
|
3
|
+
import { $ as $fetch, u as useTestContext } from './shared/test-utils.BrQgu3Ob.mjs';
|
|
4
4
|
import 'tinyexec';
|
|
5
5
|
import 'get-port-please';
|
|
6
6
|
import 'ofetch';
|
package/dist/module.mjs
CHANGED
|
@@ -263,6 +263,9 @@ function endOf(node) {
|
|
|
263
263
|
return "range" in node && node.range ? node.range[1] : "end" in node ? node.end : void 0;
|
|
264
264
|
}
|
|
265
265
|
|
|
266
|
+
function isTestPluginFile(src) {
|
|
267
|
+
return src.includes(".spec.") || src.includes(".test.");
|
|
268
|
+
}
|
|
266
269
|
async function setupImportMocking(nuxt) {
|
|
267
270
|
const { addVitePlugin } = await loadKit(nuxt.options.rootDir);
|
|
268
271
|
const ctx = {
|
|
@@ -291,6 +294,9 @@ async function setupImportMocking(nuxt) {
|
|
|
291
294
|
nuxt._ignore.add(`!${pattern}`);
|
|
292
295
|
}
|
|
293
296
|
}
|
|
297
|
+
nuxt.hook("app:resolve", (app) => {
|
|
298
|
+
app.plugins = app.plugins.filter((plugin) => !isTestPluginFile(plugin.src));
|
|
299
|
+
});
|
|
294
300
|
addVitePlugin(createMockPlugin(ctx).vite());
|
|
295
301
|
}
|
|
296
302
|
|
|
@@ -952,7 +958,7 @@ function vitestWrapper(options) {
|
|
|
952
958
|
};
|
|
953
959
|
}
|
|
954
960
|
|
|
955
|
-
const version = "4.0.
|
|
961
|
+
const version = "4.0.3";
|
|
956
962
|
const pkg = {
|
|
957
963
|
version: version};
|
|
958
964
|
|
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, a as TestHooks } from './shared/test-utils.
|
|
4
|
+
import { T as TestOptions$1, G as GotoOptions, a as TestHooks } from './shared/test-utils.BX46zKiB.mjs';
|
|
5
5
|
import '@nuxt/schema';
|
|
6
6
|
import 'tinyexec';
|
|
7
7
|
import 'ofetch';
|
package/dist/playwright.mjs
CHANGED
|
@@ -2,7 +2,7 @@ import defu from 'defu';
|
|
|
2
2
|
import { test as test$1 } from '@playwright/test';
|
|
3
3
|
export { expect } from '@playwright/test';
|
|
4
4
|
import { isWindows } from 'std-env';
|
|
5
|
-
import { w as waitForHydration, d as createTest } from './shared/test-utils.
|
|
5
|
+
import { w as waitForHydration, d as createTest } from './shared/test-utils.RVsKJA_7.mjs';
|
|
6
6
|
import 'node:path';
|
|
7
7
|
import 'ufo';
|
|
8
8
|
import 'consola';
|
|
@@ -11,7 +11,7 @@ import 'destr';
|
|
|
11
11
|
import 'scule';
|
|
12
12
|
import 'node:url';
|
|
13
13
|
import 'exsolve';
|
|
14
|
-
import { d as url } from './shared/test-utils.
|
|
14
|
+
import { d as url } from './shared/test-utils.BrQgu3Ob.mjs';
|
|
15
15
|
import 'pathe';
|
|
16
16
|
import '#dirs';
|
|
17
17
|
import './shared/test-utils.BIY9XRkB.mjs';
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import { mount } from '@vue/test-utils';
|
|
2
|
-
import {
|
|
3
|
-
import { defineComponent, useRouter, h, tryUseNuxtApp } from '#imports';
|
|
4
|
-
import NuxtRoot from '#build/root-component.mjs';
|
|
2
|
+
import { h, nextTick } from 'vue';
|
|
5
3
|
|
|
6
4
|
function getEndpointRegistry() {
|
|
7
5
|
const app = window.__app ?? {};
|
|
@@ -75,219 +73,8 @@ function registerGlobalHandler(app) {
|
|
|
75
73
|
return true;
|
|
76
74
|
}
|
|
77
75
|
|
|
78
|
-
const RouterLink = defineComponent({
|
|
79
|
-
functional: true,
|
|
80
|
-
props: {
|
|
81
|
-
to: {
|
|
82
|
-
type: [String, Object],
|
|
83
|
-
required: true
|
|
84
|
-
},
|
|
85
|
-
custom: Boolean,
|
|
86
|
-
replace: Boolean,
|
|
87
|
-
// Not implemented
|
|
88
|
-
activeClass: String,
|
|
89
|
-
exactActiveClass: String,
|
|
90
|
-
ariaCurrentValue: String
|
|
91
|
-
},
|
|
92
|
-
setup: (props, { slots }) => {
|
|
93
|
-
const navigate = () => {
|
|
94
|
-
};
|
|
95
|
-
return () => {
|
|
96
|
-
const route = useRouter().resolve(props.to);
|
|
97
|
-
return props.custom ? slots.default?.({ href: route.href, navigate, route }) : h(
|
|
98
|
-
"a",
|
|
99
|
-
{
|
|
100
|
-
href: route.href,
|
|
101
|
-
onClick: (e) => {
|
|
102
|
-
e.preventDefault();
|
|
103
|
-
return navigate();
|
|
104
|
-
}
|
|
105
|
-
},
|
|
106
|
-
slots
|
|
107
|
-
);
|
|
108
|
-
};
|
|
109
|
-
}
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
function cleanupAll() {
|
|
113
|
-
for (const fn of (window.__cleanup || []).splice(0)) {
|
|
114
|
-
fn();
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
function addCleanup(fn) {
|
|
118
|
-
window.__cleanup ||= [];
|
|
119
|
-
window.__cleanup.push(fn);
|
|
120
|
-
}
|
|
121
|
-
function runEffectScope(fn) {
|
|
122
|
-
const scope = effectScope();
|
|
123
|
-
addCleanup(() => scope.stop());
|
|
124
|
-
return scope.run(fn);
|
|
125
|
-
}
|
|
126
|
-
function wrapperSuspended(component, options, {
|
|
127
|
-
wrapperFn,
|
|
128
|
-
wrappedRender = (fn) => fn,
|
|
129
|
-
suspendedHelperName,
|
|
130
|
-
clonedComponentName
|
|
131
|
-
}) {
|
|
132
|
-
const { props = {}, attrs = {} } = options;
|
|
133
|
-
const { route = "/", scoped = false, ...wrapperFnOptions } = options;
|
|
134
|
-
const vueApp = tryUseNuxtApp()?.vueApp || globalThis.__unctx__.get("nuxt-app").tryUse().vueApp;
|
|
135
|
-
const {
|
|
136
|
-
render: componentRender,
|
|
137
|
-
setup: componentSetup,
|
|
138
|
-
...componentRest
|
|
139
|
-
} = component;
|
|
140
|
-
let wrappedInstance = null;
|
|
141
|
-
let setupContext;
|
|
142
|
-
let setupState;
|
|
143
|
-
const setProps = reactive({});
|
|
144
|
-
function patchInstanceAppContext() {
|
|
145
|
-
const app = getCurrentInstance()?.appContext.app;
|
|
146
|
-
if (!app) return;
|
|
147
|
-
for (const [key, value] of Object.entries(vueApp)) {
|
|
148
|
-
if (key in app) continue;
|
|
149
|
-
app[key] = value;
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
const ClonedComponent = {
|
|
153
|
-
components: {},
|
|
154
|
-
...component,
|
|
155
|
-
name: clonedComponentName,
|
|
156
|
-
async setup(props2, instanceContext) {
|
|
157
|
-
const currentInstance = getCurrentInstance();
|
|
158
|
-
if (currentInstance) {
|
|
159
|
-
currentInstance.emit = (event, ...args) => {
|
|
160
|
-
setupContext.emit(event, ...args);
|
|
161
|
-
};
|
|
162
|
-
}
|
|
163
|
-
if (!componentSetup) return;
|
|
164
|
-
const result = scoped ? await runEffectScope(() => componentSetup(props2, setupContext)) : await componentSetup(props2, setupContext);
|
|
165
|
-
if (wrappedInstance?.exposed) {
|
|
166
|
-
instanceContext.expose(wrappedInstance.exposed);
|
|
167
|
-
}
|
|
168
|
-
setupState = result && typeof result === "object" ? result : {};
|
|
169
|
-
return result;
|
|
170
|
-
}
|
|
171
|
-
};
|
|
172
|
-
const SuspendedHelper = {
|
|
173
|
-
name: suspendedHelperName,
|
|
174
|
-
render: () => "",
|
|
175
|
-
async setup() {
|
|
176
|
-
if (route) {
|
|
177
|
-
const router = useRouter();
|
|
178
|
-
await router.replace(route);
|
|
179
|
-
}
|
|
180
|
-
return () => h$1(ClonedComponent, { ...props, ...setProps, ...attrs }, setupContext.slots);
|
|
181
|
-
}
|
|
182
|
-
};
|
|
183
|
-
return new Promise((resolve, reject) => {
|
|
184
|
-
let isMountSettled = false;
|
|
185
|
-
const wrapper = wrapperFn(
|
|
186
|
-
{
|
|
187
|
-
inheritAttrs: false,
|
|
188
|
-
__cssModules: componentRest.__cssModules,
|
|
189
|
-
setup: (props2, ctx) => {
|
|
190
|
-
patchInstanceAppContext();
|
|
191
|
-
wrappedInstance = getCurrentInstance();
|
|
192
|
-
setupContext = ctx;
|
|
193
|
-
const nuxtRootSetupResult = runEffectScope(
|
|
194
|
-
() => NuxtRoot.setup(props2, {
|
|
195
|
-
...ctx,
|
|
196
|
-
expose: () => {
|
|
197
|
-
}
|
|
198
|
-
})
|
|
199
|
-
);
|
|
200
|
-
onErrorCaptured((error, ...args) => {
|
|
201
|
-
if (isMountSettled) return;
|
|
202
|
-
isMountSettled = true;
|
|
203
|
-
try {
|
|
204
|
-
wrappedInstance?.appContext.config.errorHandler?.(error, ...args);
|
|
205
|
-
reject(error);
|
|
206
|
-
} catch (error2) {
|
|
207
|
-
reject(error2);
|
|
208
|
-
}
|
|
209
|
-
return false;
|
|
210
|
-
});
|
|
211
|
-
return nuxtRootSetupResult;
|
|
212
|
-
},
|
|
213
|
-
render: wrappedRender(() => h$1(
|
|
214
|
-
Suspense,
|
|
215
|
-
{
|
|
216
|
-
onResolve: () => nextTick().then(() => {
|
|
217
|
-
if (isMountSettled) return;
|
|
218
|
-
isMountSettled = true;
|
|
219
|
-
wrapper.setupState = setupState;
|
|
220
|
-
resolve({
|
|
221
|
-
wrapper,
|
|
222
|
-
setProps: (props2) => {
|
|
223
|
-
Object.assign(setProps, props2);
|
|
224
|
-
}
|
|
225
|
-
});
|
|
226
|
-
})
|
|
227
|
-
},
|
|
228
|
-
{
|
|
229
|
-
default: () => h$1(SuspendedHelper)
|
|
230
|
-
}
|
|
231
|
-
))
|
|
232
|
-
},
|
|
233
|
-
{
|
|
234
|
-
...wrapperFnOptions,
|
|
235
|
-
global: mergeComponentMountingGlobalOptions(wrapperFnOptions.global, {
|
|
236
|
-
config: {
|
|
237
|
-
globalProperties: makeAllPropertiesEnumerable(
|
|
238
|
-
vueApp.config.globalProperties
|
|
239
|
-
)
|
|
240
|
-
},
|
|
241
|
-
directives: vueApp._context.directives,
|
|
242
|
-
provide: vueApp._context.provides,
|
|
243
|
-
stubs: {
|
|
244
|
-
Suspense: false,
|
|
245
|
-
[SuspendedHelper.name]: false,
|
|
246
|
-
[ClonedComponent.name]: false
|
|
247
|
-
},
|
|
248
|
-
components: { ...vueApp._context.components, RouterLink }
|
|
249
|
-
})
|
|
250
|
-
}
|
|
251
|
-
);
|
|
252
|
-
});
|
|
253
|
-
}
|
|
254
|
-
function mergeComponentMountingGlobalOptions(options = {}, defaults = {}) {
|
|
255
|
-
return {
|
|
256
|
-
...options,
|
|
257
|
-
mixins: [...defaults.mixins || [], ...options.mixins || []],
|
|
258
|
-
stubs: {
|
|
259
|
-
...defaults.stubs,
|
|
260
|
-
...Array.isArray(options.stubs) ? Object.fromEntries(options.stubs.map((n) => [n, true])) : options.stubs
|
|
261
|
-
},
|
|
262
|
-
plugins: [...defaults.plugins || [], ...options.plugins || []],
|
|
263
|
-
components: { ...defaults.components, ...options.components },
|
|
264
|
-
provide: { ...defaults.provide, ...options.provide },
|
|
265
|
-
mocks: { ...defaults.mocks, ...options.mocks },
|
|
266
|
-
config: {
|
|
267
|
-
...defaults.config,
|
|
268
|
-
...options.config,
|
|
269
|
-
compilerOptions: {
|
|
270
|
-
...defaults.config?.compilerOptions,
|
|
271
|
-
...options.config?.compilerOptions
|
|
272
|
-
},
|
|
273
|
-
globalProperties: {
|
|
274
|
-
...defaults.config?.globalProperties,
|
|
275
|
-
...options.config?.globalProperties
|
|
276
|
-
}
|
|
277
|
-
},
|
|
278
|
-
directives: { ...defaults.directives, ...options.directives }
|
|
279
|
-
};
|
|
280
|
-
}
|
|
281
|
-
function makeAllPropertiesEnumerable(target) {
|
|
282
|
-
return {
|
|
283
|
-
...target,
|
|
284
|
-
...Object.fromEntries(
|
|
285
|
-
Object.getOwnPropertyNames(target).map((key) => [key, target[key]])
|
|
286
|
-
)
|
|
287
|
-
};
|
|
288
|
-
}
|
|
289
|
-
|
|
290
76
|
async function mountSuspended(component, options = {}) {
|
|
77
|
+
const { cleanupAll, wrapperSuspended } = await import('../chunks/suspended.mjs');
|
|
291
78
|
const suspendedHelperName = "MountSuspendedHelper";
|
|
292
79
|
const clonedComponentName = "MountSuspendedComponent";
|
|
293
80
|
cleanupAll();
|
|
@@ -342,6 +129,7 @@ function wrappedMountedWrapper(wrapper, component) {
|
|
|
342
129
|
}
|
|
343
130
|
|
|
344
131
|
async function renderSuspended(component, options = {}) {
|
|
132
|
+
const { cleanupAll, wrapperSuspended } = await import('../chunks/suspended.mjs');
|
|
345
133
|
const wrapperId = "test-wrapper";
|
|
346
134
|
const suspendedHelperName = "RenderHelper";
|
|
347
135
|
const clonedComponentName = "RenderSuspendedComponent";
|
|
@@ -350,9 +138,9 @@ async function renderSuspended(component, options = {}) {
|
|
|
350
138
|
document.getElementById(wrapperId)?.remove();
|
|
351
139
|
const { wrapper, setProps } = await wrapperSuspended(component, options, {
|
|
352
140
|
wrapperFn,
|
|
353
|
-
wrappedRender: (render) => () => h
|
|
141
|
+
wrappedRender: (render) => () => h({
|
|
354
142
|
inheritAttrs: false,
|
|
355
|
-
render: () => h
|
|
143
|
+
render: () => h("div", { id: wrapperId }, render())
|
|
356
144
|
}),
|
|
357
145
|
suspendedHelperName,
|
|
358
146
|
clonedComponentName
|
|
@@ -56,6 +56,13 @@ interface TestOptions {
|
|
|
56
56
|
* @default 30000
|
|
57
57
|
*/
|
|
58
58
|
teardownTimeout: number;
|
|
59
|
+
/**
|
|
60
|
+
* The amount of time (in milliseconds) to wait for the dev or built server to become ready (i.e. respond successfully on the configured base URL) before failing.
|
|
61
|
+
*
|
|
62
|
+
* This is bounded by `setupTimeout`, so increasing this is only useful in combination with a sufficiently large `setupTimeout`.
|
|
63
|
+
* @default 120000 // on windows; otherwise 60000
|
|
64
|
+
*/
|
|
65
|
+
serverStartTimeout: number;
|
|
59
66
|
waitFor: number;
|
|
60
67
|
/**
|
|
61
68
|
* Under the hood, Nuxt test utils uses [`playwright`](https://playwright.dev) to carry out browser testing. If this option is set, a browser will be launched and can be controlled in the subsequent test suite.
|
|
@@ -15,6 +15,7 @@ function createTestContext(options) {
|
|
|
15
15
|
configFile: "nuxt.config",
|
|
16
16
|
setupTimeout: isWindows ? 24e4 : 12e4,
|
|
17
17
|
teardownTimeout: isWindows ? 6e4 : 3e4,
|
|
18
|
+
serverStartTimeout: isWindows ? 12e4 : 6e4,
|
|
18
19
|
dev: !!JSON.parse(process.env.NUXT_TEST_DEV || "false"),
|
|
19
20
|
logLevel: 1,
|
|
20
21
|
server: true,
|
|
@@ -97,24 +98,6 @@ async function startServer(options = {}) {
|
|
|
97
98
|
}
|
|
98
99
|
}
|
|
99
100
|
});
|
|
100
|
-
await waitForPort(port, { retries: 32, host }).catch(() => {
|
|
101
|
-
});
|
|
102
|
-
let lastError;
|
|
103
|
-
for (let i = 0; i < 150; i++) {
|
|
104
|
-
await new Promise((resolve2) => setTimeout(resolve2, 100));
|
|
105
|
-
try {
|
|
106
|
-
const res = await $fetch(ctx.nuxt.options.app.baseURL, {
|
|
107
|
-
responseType: "text"
|
|
108
|
-
});
|
|
109
|
-
if (!res.includes("__NUXT_LOADING__")) {
|
|
110
|
-
return;
|
|
111
|
-
}
|
|
112
|
-
} catch (e) {
|
|
113
|
-
lastError = e;
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
ctx.serverProcess.kill();
|
|
117
|
-
throw lastError || new Error("Timeout waiting for dev server!");
|
|
118
101
|
} else {
|
|
119
102
|
const outputDir = ctx.nuxt ? ctx.nuxt.options.nitro.output.dir : ctx.options.nuxtConfig.nitro.output.dir;
|
|
120
103
|
ctx.serverProcess = x(
|
|
@@ -135,13 +118,53 @@ async function startServer(options = {}) {
|
|
|
135
118
|
}
|
|
136
119
|
}
|
|
137
120
|
);
|
|
138
|
-
await waitForPort(port, { retries: 20, host });
|
|
139
121
|
}
|
|
122
|
+
await waitForServer({ host, port, dev: ctx.options.dev });
|
|
123
|
+
}
|
|
124
|
+
async function waitForServer({ host, port, dev }) {
|
|
125
|
+
const ctx = useTestContext();
|
|
126
|
+
const baseURL = ctx.nuxt?.options.app.baseURL ?? "/";
|
|
127
|
+
const deadline = Date.now() + ctx.options.serverStartTimeout;
|
|
128
|
+
await waitForPort(port, { retries: 8, host }).catch(() => {
|
|
129
|
+
});
|
|
130
|
+
let lastError;
|
|
131
|
+
while (Date.now() < deadline) {
|
|
132
|
+
if (ctx.serverProcess && (ctx.serverProcess.killed || ctx.serverProcess.exitCode != null)) {
|
|
133
|
+
throw new Error(`Server process exited before becoming ready (exit code: ${ctx.serverProcess.exitCode ?? "unknown"})`);
|
|
134
|
+
}
|
|
135
|
+
try {
|
|
136
|
+
const res = await globalFetch(joinURL(ctx.url, baseURL), { signal: AbortSignal.timeout(1e4) });
|
|
137
|
+
if (dev && res.status === 503) {
|
|
138
|
+
lastError = new Error(`Server responded with ${res.status} ${res.statusText}`);
|
|
139
|
+
} else if (dev && (await res.text()).includes("__NUXT_LOADING__")) {
|
|
140
|
+
lastError = new Error("Dev server is still starting up");
|
|
141
|
+
} else {
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
} catch (e) {
|
|
145
|
+
lastError = e;
|
|
146
|
+
}
|
|
147
|
+
await new Promise((resolve2) => setTimeout(resolve2, 100));
|
|
148
|
+
}
|
|
149
|
+
await stopServer();
|
|
150
|
+
throw lastError instanceof Error ? lastError : new Error(`Timeout (${ctx.options.serverStartTimeout}ms) waiting for ${dev ? "dev" : "built"} server to become ready at ${ctx.url}`);
|
|
140
151
|
}
|
|
141
152
|
async function stopServer() {
|
|
142
153
|
const ctx = useTestContext();
|
|
143
|
-
|
|
144
|
-
|
|
154
|
+
const proc = ctx.serverProcess;
|
|
155
|
+
if (!proc) {
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
ctx.serverProcess = void 0;
|
|
159
|
+
const exited = Promise.resolve(proc).then(() => {
|
|
160
|
+
}, () => {
|
|
161
|
+
});
|
|
162
|
+
const sleep = (ms) => new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
163
|
+
proc.kill();
|
|
164
|
+
await Promise.race([exited, sleep(5e3)]);
|
|
165
|
+
if (proc.exitCode == null) {
|
|
166
|
+
proc.kill("SIGKILL");
|
|
167
|
+
await Promise.race([exited, sleep(5e3)]);
|
|
145
168
|
}
|
|
146
169
|
}
|
|
147
170
|
function fetch(path, options) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { u as useTestContext, d as url, c as createTestContext, a as startServer, b as stopServer, s as setTestContext } from './test-utils.
|
|
1
|
+
import { u as useTestContext, d as url, c as createTestContext, a as startServer, b as stopServer, s as setTestContext } from './test-utils.BrQgu3Ob.mjs';
|
|
2
2
|
import { existsSync, promises } from 'node:fs';
|
|
3
3
|
import { resolve } from 'node:path';
|
|
4
4
|
import { defu } from 'defu';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nuxt/test-utils",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.3",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/nuxt/test-utils.git"
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
"@nuxt/kit": "^3.21.2",
|
|
60
60
|
"c12": "^3.3.4",
|
|
61
61
|
"consola": "^3.4.2",
|
|
62
|
-
"defu": "^6.1.
|
|
62
|
+
"defu": "^6.1.7",
|
|
63
63
|
"destr": "^2.0.5",
|
|
64
64
|
"estree-walker": "^3.0.3",
|
|
65
65
|
"exsolve": "^1.0.8",
|
|
@@ -71,52 +71,52 @@
|
|
|
71
71
|
"magic-string": "^0.30.21",
|
|
72
72
|
"node-fetch-native": "^1.6.7",
|
|
73
73
|
"node-mock-http": "^1.0.4",
|
|
74
|
-
"nypm": "^0.6.
|
|
74
|
+
"nypm": "^0.6.6",
|
|
75
75
|
"ofetch": "^1.5.1",
|
|
76
76
|
"pathe": "^2.0.3",
|
|
77
77
|
"perfect-debounce": "^2.1.0",
|
|
78
78
|
"radix3": "^1.1.2",
|
|
79
79
|
"scule": "^1.3.0",
|
|
80
|
-
"std-env": "^4.
|
|
80
|
+
"std-env": "^4.1.0",
|
|
81
81
|
"tinyexec": "^1.1.1",
|
|
82
82
|
"ufo": "^1.6.3",
|
|
83
83
|
"unplugin": "^3.0.0",
|
|
84
|
-
"vue": "^3.5.
|
|
84
|
+
"vue": "^3.5.33",
|
|
85
85
|
"vitest-environment-nuxt": "2.0.0"
|
|
86
86
|
},
|
|
87
87
|
"devDependencies": {
|
|
88
|
-
"@cucumber/cucumber": "12.
|
|
88
|
+
"@cucumber/cucumber": "12.8.2",
|
|
89
89
|
"@jest/globals": "30.3.0",
|
|
90
90
|
"@nuxt/eslint-config": "1.15.2",
|
|
91
91
|
"@nuxt/schema": "4.4.2",
|
|
92
92
|
"@playwright/test": "1.59.1",
|
|
93
93
|
"@testing-library/vue": "8.1.0",
|
|
94
|
-
"@types/bun": "1.3.
|
|
94
|
+
"@types/bun": "1.3.13",
|
|
95
95
|
"@types/estree": "1.0.8",
|
|
96
96
|
"@types/jsdom": "28.0.1",
|
|
97
97
|
"@types/node": "latest",
|
|
98
98
|
"@types/semver": "7.7.1",
|
|
99
|
-
"@vitest/browser-playwright": "4.1.
|
|
100
|
-
"@vue/test-utils": "2.4.
|
|
99
|
+
"@vitest/browser-playwright": "4.1.5",
|
|
100
|
+
"@vue/test-utils": "2.4.9",
|
|
101
101
|
"changelogen": "0.6.2",
|
|
102
102
|
"compatx": "0.2.0",
|
|
103
|
-
"eslint": "10.2.
|
|
103
|
+
"eslint": "10.2.1",
|
|
104
104
|
"installed-check": "10.0.1",
|
|
105
|
-
"knip": "6.
|
|
105
|
+
"knip": "6.7.0",
|
|
106
106
|
"nitropack": "2.13.3",
|
|
107
107
|
"nuxt": "4.4.2",
|
|
108
|
-
"oxc-parser": "0.
|
|
109
|
-
"pkg-pr-new": "0.0.
|
|
108
|
+
"oxc-parser": "0.127.0",
|
|
109
|
+
"pkg-pr-new": "0.0.67",
|
|
110
110
|
"playwright-core": "1.59.1",
|
|
111
|
-
"rollup": "4.60.
|
|
111
|
+
"rollup": "4.60.2",
|
|
112
112
|
"semver": "7.7.4",
|
|
113
|
-
"typescript": "6.0.
|
|
113
|
+
"typescript": "6.0.3",
|
|
114
114
|
"unbuild": "latest",
|
|
115
|
-
"unimport": "6.
|
|
116
|
-
"vite": "8.0.
|
|
117
|
-
"vitest": "4.1.
|
|
118
|
-
"vue-router": "5.0.
|
|
119
|
-
"vue-tsc": "3.2.
|
|
115
|
+
"unimport": "6.1.1",
|
|
116
|
+
"vite": "8.0.10",
|
|
117
|
+
"vitest": "4.1.5",
|
|
118
|
+
"vue-router": "5.0.6",
|
|
119
|
+
"vue-tsc": "3.2.7"
|
|
120
120
|
},
|
|
121
121
|
"peerDependencies": {
|
|
122
122
|
"@cucumber/cucumber": ">=11.0.0",
|
|
@@ -162,16 +162,16 @@
|
|
|
162
162
|
}
|
|
163
163
|
},
|
|
164
164
|
"resolutions": {
|
|
165
|
-
"@cucumber/cucumber": "12.
|
|
165
|
+
"@cucumber/cucumber": "12.8.2",
|
|
166
166
|
"@nuxt/schema": "4.4.2",
|
|
167
167
|
"@nuxt/test-utils": "workspace:*",
|
|
168
168
|
"@types/node": "24.12.2",
|
|
169
169
|
"nitro": "https://pkg.pr.new/nitrojs/nitro@00598a8",
|
|
170
|
-
"rollup": "4.60.
|
|
171
|
-
"vite": "8.0.
|
|
170
|
+
"rollup": "4.60.2",
|
|
171
|
+
"vite": "8.0.10",
|
|
172
172
|
"vite-node": "6.0.0",
|
|
173
|
-
"vitest": "4.1.
|
|
174
|
-
"vue": "^3.5.
|
|
173
|
+
"vitest": "4.1.5",
|
|
174
|
+
"vue": "^3.5.33"
|
|
175
175
|
},
|
|
176
176
|
"engines": {
|
|
177
177
|
"node": "^20.19.0 || ^22.12.0 || >=24.0.0"
|