@nuxt/test-utils 3.21.0 → 3.23.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 +3 -3
- package/dist/config.mjs +40 -21
- package/dist/e2e.d.mts +3 -2
- package/dist/e2e.mjs +17 -13
- package/dist/experimental.mjs +1 -1
- package/dist/module.mjs +721 -148
- package/dist/playwright.d.mts +2 -1
- package/dist/playwright.mjs +3 -3
- package/dist/runtime/shared/environment.mjs +11 -66
- package/dist/runtime/shared/h3-v1.d.ts +6 -0
- package/dist/runtime/shared/h3-v1.mjs +69 -0
- package/dist/runtime/shared/h3-v2.d.ts +6 -0
- package/dist/runtime/shared/h3-v2.mjs +35 -0
- package/dist/runtime/shared/h3.d.ts +3 -0
- package/dist/runtime/shared/h3.mjs +3 -0
- 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 +26 -25
- package/dist/runtime-utils/index.mjs +185 -272
- package/dist/shared/{test-utils.3NR-so9-.mjs → test-utils.5cnw0YZR.mjs} +2 -2
- package/dist/shared/{test-utils.G1ew4kEe.mjs → test-utils.BIY9XRkB.mjs} +1 -1
- package/dist/shared/{test-utils.CtwoJP76.mjs → test-utils.BsmyE2FA.mjs} +10 -8
- package/dist/shared/{test-utils.20kU0tZa.d.mts → test-utils.C9GKP_T5.d.mts} +3 -2
- package/dist/shared/test-utils.DDUpsMYL.mjs +32 -0
- package/dist/vitest-environment.d.mts +15 -3
- package/dist/vitest-environment.mjs +118 -66
- package/dist/vitest-wrapper/cli.d.mts +2 -0
- package/dist/vitest-wrapper/cli.mjs +78 -0
- package/package.json +32 -26
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { defineEventHandler } from 'h3';
|
|
2
1
|
import { mount } from '@vue/test-utils';
|
|
3
|
-
import { reactive, h as h$1, Suspense, nextTick, getCurrentInstance,
|
|
2
|
+
import { reactive, h as h$1, Suspense, nextTick as nextTick$1, getCurrentInstance, onErrorCaptured, effectScope } from 'vue';
|
|
4
3
|
import { defu } from 'defu';
|
|
5
4
|
import { defineComponent, useRouter, h, tryUseNuxtApp } from '#imports';
|
|
6
5
|
import NuxtRoot from '#build/root-component.mjs';
|
|
@@ -12,30 +11,11 @@ function registerEndpoint(url, options) {
|
|
|
12
11
|
throw new Error("registerEndpoint() can only be used in a `@nuxt/test-utils` runtime environment");
|
|
13
12
|
}
|
|
14
13
|
const config = typeof options === "function" ? { handler: options, method: void 0, once: false } : options;
|
|
15
|
-
config.handler =
|
|
16
|
-
const hasBeenRegistered = window.__registry.has(url);
|
|
14
|
+
config.handler = Object.assign(config.handler, { __is_handler__: true });
|
|
17
15
|
endpointRegistry[url] ||= [];
|
|
18
16
|
endpointRegistry[url].push(config);
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
app.use("/_" + url, defineEventHandler(async (event) => {
|
|
22
|
-
const latestHandler = [...endpointRegistry[url] || []].reverse().find((config2) => config2.method ? event.method === config2.method : true);
|
|
23
|
-
if (!latestHandler) return;
|
|
24
|
-
const result = await latestHandler.handler(event);
|
|
25
|
-
if (!latestHandler.once) return result;
|
|
26
|
-
const index = endpointRegistry[url]?.indexOf(latestHandler);
|
|
27
|
-
if (index === void 0 || index === -1) return result;
|
|
28
|
-
endpointRegistry[url]?.splice(index, 1);
|
|
29
|
-
if (endpointRegistry[url]?.length === 0) {
|
|
30
|
-
window.__registry.delete(url);
|
|
31
|
-
}
|
|
32
|
-
return result;
|
|
33
|
-
}), {
|
|
34
|
-
match(_, event) {
|
|
35
|
-
return endpointRegistry[url]?.some((config2) => config2.method ? event?.method === config2.method : true) ?? false;
|
|
36
|
-
}
|
|
37
|
-
});
|
|
38
|
-
}
|
|
17
|
+
window.__registry.add(url);
|
|
18
|
+
app._registered ||= registerGlobalHandler(app);
|
|
39
19
|
return () => {
|
|
40
20
|
endpointRegistry[url]?.splice(endpointRegistry[url].indexOf(config), 1);
|
|
41
21
|
if (endpointRegistry[url]?.length === 0) {
|
|
@@ -53,6 +33,31 @@ function mockComponent(_path, _component) {
|
|
|
53
33
|
"mockComponent() is a macro and it did not get transpiled. This may be an internal bug of @nuxt/test-utils."
|
|
54
34
|
);
|
|
55
35
|
}
|
|
36
|
+
const handler = Object.assign(async (event) => {
|
|
37
|
+
const url = "url" in event && event.url ? event.url.pathname.replace(/^\/_/, "") : event.path.replace(/[?#].*$/, "").replace(/^\/_/, "");
|
|
38
|
+
const latestHandler = [...endpointRegistry[url] || []].reverse().find((config) => config.method ? event.method === config.method : true);
|
|
39
|
+
if (!latestHandler) return;
|
|
40
|
+
const result = await latestHandler.handler(event);
|
|
41
|
+
if (!latestHandler.once) return result;
|
|
42
|
+
const index = endpointRegistry[url]?.indexOf(latestHandler);
|
|
43
|
+
if (index === void 0 || index === -1) return result;
|
|
44
|
+
endpointRegistry[url]?.splice(index, 1);
|
|
45
|
+
if (endpointRegistry[url]?.length === 0) {
|
|
46
|
+
window.__registry.delete(url);
|
|
47
|
+
}
|
|
48
|
+
return result;
|
|
49
|
+
}, { __is_handler__: true });
|
|
50
|
+
function registerGlobalHandler(app) {
|
|
51
|
+
app.use(handler, {
|
|
52
|
+
match: (...args) => {
|
|
53
|
+
const [eventOrPath, _event = eventOrPath] = args;
|
|
54
|
+
const url = typeof eventOrPath === "string" ? eventOrPath.replace(/^\/_/, "").replace(/[?#].*$/, "") : eventOrPath.url.pathname.replace(/^\/_/, "");
|
|
55
|
+
const event = _event;
|
|
56
|
+
return endpointRegistry[url]?.some((config) => config.method ? event?.method === config.method : true) ?? false;
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
56
61
|
|
|
57
62
|
const RouterLink = defineComponent({
|
|
58
63
|
functional: true,
|
|
@@ -88,19 +93,34 @@ const RouterLink = defineComponent({
|
|
|
88
93
|
}
|
|
89
94
|
});
|
|
90
95
|
|
|
91
|
-
|
|
92
|
-
const {
|
|
93
|
-
|
|
94
|
-
attrs = {},
|
|
95
|
-
slots = {},
|
|
96
|
-
route = "/",
|
|
97
|
-
..._options
|
|
98
|
-
} = options || {};
|
|
99
|
-
for (const cleanupFunction of globalThis.__cleanup || []) {
|
|
100
|
-
cleanupFunction();
|
|
96
|
+
function cleanupAll() {
|
|
97
|
+
for (const fn of (window.__cleanup || []).splice(0)) {
|
|
98
|
+
fn();
|
|
101
99
|
}
|
|
100
|
+
}
|
|
101
|
+
function addCleanup(fn) {
|
|
102
|
+
window.__cleanup ||= [];
|
|
103
|
+
window.__cleanup.push(fn);
|
|
104
|
+
}
|
|
105
|
+
function runEffectScope(fn) {
|
|
106
|
+
const scope = effectScope();
|
|
107
|
+
addCleanup(() => scope.stop());
|
|
108
|
+
return scope.run(fn);
|
|
109
|
+
}
|
|
110
|
+
function wrapperSuspended(component, options, {
|
|
111
|
+
wrapperFn,
|
|
112
|
+
wrappedRender = (fn) => fn,
|
|
113
|
+
suspendedHelperName,
|
|
114
|
+
clonedComponentName
|
|
115
|
+
}) {
|
|
116
|
+
const { props = {}, attrs = {} } = options;
|
|
117
|
+
const { route = "/", scoped = false, ...wrapperFnOptions } = options;
|
|
102
118
|
const vueApp = tryUseNuxtApp()?.vueApp || globalThis.__unctx__.get("nuxt-app").tryUse().vueApp;
|
|
103
|
-
const {
|
|
119
|
+
const {
|
|
120
|
+
render: componentRender,
|
|
121
|
+
setup: componentSetup,
|
|
122
|
+
...componentRest
|
|
123
|
+
} = component;
|
|
104
124
|
let wrappedInstance = null;
|
|
105
125
|
let setupContext;
|
|
106
126
|
let setupState;
|
|
@@ -113,28 +133,19 @@ async function mountSuspended(component, options) {
|
|
|
113
133
|
app[key] = value;
|
|
114
134
|
}
|
|
115
135
|
}
|
|
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);
|
|
136
|
+
const ClonedComponent = {
|
|
137
|
+
components: {},
|
|
138
|
+
...component,
|
|
139
|
+
name: clonedComponentName,
|
|
140
|
+
async setup(props2, instanceContext) {
|
|
141
|
+
const currentInstance = getCurrentInstance();
|
|
142
|
+
if (currentInstance) {
|
|
143
|
+
currentInstance.emit = (event, ...args) => {
|
|
144
|
+
setupContext.emit(event, ...args);
|
|
145
|
+
};
|
|
137
146
|
}
|
|
147
|
+
if (!componentSetup) return;
|
|
148
|
+
const result = scoped ? await runEffectScope(() => componentSetup(props2, setupContext)) : await componentSetup(props2, setupContext);
|
|
138
149
|
if (wrappedInstance?.exposed) {
|
|
139
150
|
instanceContext.expose(wrappedInstance.exposed);
|
|
140
151
|
}
|
|
@@ -142,97 +153,110 @@ async function mountSuspended(component, options) {
|
|
|
142
153
|
return result;
|
|
143
154
|
}
|
|
144
155
|
};
|
|
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
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
{
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
};
|
|
182
|
-
resolve(wrappedMountedWrapper(vm));
|
|
183
|
-
})
|
|
184
|
-
},
|
|
185
|
-
{
|
|
186
|
-
default: () => h$1({
|
|
187
|
-
name: "MountSuspendedHelper",
|
|
188
|
-
async setup() {
|
|
189
|
-
const router = useRouter();
|
|
190
|
-
await router.replace(route);
|
|
191
|
-
const clonedComponent = {
|
|
192
|
-
components: {},
|
|
193
|
-
...component,
|
|
194
|
-
name: "MountSuspendedComponent",
|
|
195
|
-
setup: (props2, ctx) => wrappedSetup(props2, setupContext, ctx)
|
|
196
|
-
};
|
|
197
|
-
return () => h$1(clonedComponent, { ...props, ...setProps, ...attrs }, setupContext.slots);
|
|
198
|
-
}
|
|
199
|
-
})
|
|
156
|
+
const SuspendedHelper = {
|
|
157
|
+
name: suspendedHelperName,
|
|
158
|
+
render: () => "",
|
|
159
|
+
async setup() {
|
|
160
|
+
if (route) {
|
|
161
|
+
const router = useRouter();
|
|
162
|
+
await router.replace(route);
|
|
163
|
+
}
|
|
164
|
+
return () => h$1(ClonedComponent, { ...props, ...setProps, ...attrs }, setupContext.slots);
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
return new Promise((resolve, reject) => {
|
|
168
|
+
let isMountSettled = false;
|
|
169
|
+
const wrapper = wrapperFn(
|
|
170
|
+
{
|
|
171
|
+
inheritAttrs: false,
|
|
172
|
+
__cssModules: componentRest.__cssModules,
|
|
173
|
+
setup: (props2, ctx) => {
|
|
174
|
+
patchInstanceAppContext();
|
|
175
|
+
wrappedInstance = getCurrentInstance();
|
|
176
|
+
setupContext = ctx;
|
|
177
|
+
const nuxtRootSetupResult = runEffectScope(
|
|
178
|
+
() => NuxtRoot.setup(props2, {
|
|
179
|
+
...ctx,
|
|
180
|
+
expose: () => {
|
|
181
|
+
}
|
|
182
|
+
})
|
|
183
|
+
);
|
|
184
|
+
onErrorCaptured((error, ...args) => {
|
|
185
|
+
if (isMountSettled) return;
|
|
186
|
+
isMountSettled = true;
|
|
187
|
+
try {
|
|
188
|
+
wrappedInstance?.appContext.config.errorHandler?.(error, ...args);
|
|
189
|
+
reject(error);
|
|
190
|
+
} catch (error2) {
|
|
191
|
+
reject(error2);
|
|
200
192
|
}
|
|
201
|
-
|
|
193
|
+
return false;
|
|
194
|
+
});
|
|
195
|
+
return nuxtRootSetupResult;
|
|
202
196
|
},
|
|
203
|
-
|
|
204
|
-
|
|
197
|
+
render: wrappedRender(() => h$1(
|
|
198
|
+
Suspense,
|
|
205
199
|
{
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
...Object.fromEntries(
|
|
215
|
-
Object.getOwnPropertyNames(vueApp.config.globalProperties).map((key) => [key, vueApp.config.globalProperties[key]])
|
|
216
|
-
)
|
|
200
|
+
onResolve: () => nextTick$1().then(() => {
|
|
201
|
+
if (isMountSettled) return;
|
|
202
|
+
isMountSettled = true;
|
|
203
|
+
wrapper.setupState = setupState;
|
|
204
|
+
resolve({
|
|
205
|
+
wrapper,
|
|
206
|
+
setProps: (props2) => {
|
|
207
|
+
Object.assign(setProps, props2);
|
|
217
208
|
}
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
MountSuspendedHelper: false,
|
|
224
|
-
[component && typeof component === "object" && "name" in component && typeof component.name === "string" ? component.name : "MountSuspendedComponent"]: false
|
|
225
|
-
},
|
|
226
|
-
components: { ...vueApp._context.components, RouterLink }
|
|
227
|
-
}
|
|
209
|
+
});
|
|
210
|
+
})
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
default: () => h$1(SuspendedHelper)
|
|
228
214
|
}
|
|
229
|
-
)
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
215
|
+
))
|
|
216
|
+
},
|
|
217
|
+
defu(wrapperFnOptions, {
|
|
218
|
+
global: {
|
|
219
|
+
config: {
|
|
220
|
+
globalProperties: makeAllPropertiesEnumerable(
|
|
221
|
+
vueApp.config.globalProperties
|
|
222
|
+
)
|
|
223
|
+
},
|
|
224
|
+
directives: vueApp._context.directives,
|
|
225
|
+
provide: vueApp._context.provides,
|
|
226
|
+
stubs: {
|
|
227
|
+
Suspense: false,
|
|
228
|
+
[SuspendedHelper.name]: false,
|
|
229
|
+
[ClonedComponent.name]: false
|
|
230
|
+
},
|
|
231
|
+
components: { ...vueApp._context.components, RouterLink }
|
|
232
|
+
}
|
|
233
|
+
})
|
|
234
|
+
);
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
function makeAllPropertiesEnumerable(target) {
|
|
238
|
+
return {
|
|
239
|
+
...target,
|
|
240
|
+
...Object.fromEntries(
|
|
241
|
+
Object.getOwnPropertyNames(target).map((key) => [key, target[key]])
|
|
242
|
+
)
|
|
243
|
+
};
|
|
233
244
|
}
|
|
234
|
-
|
|
235
|
-
|
|
245
|
+
|
|
246
|
+
async function mountSuspended(component, options = {}) {
|
|
247
|
+
const suspendedHelperName = "MountSuspendedHelper";
|
|
248
|
+
const clonedComponentName = "MountSuspendedComponent";
|
|
249
|
+
cleanupAll();
|
|
250
|
+
const { wrapper, setProps } = await wrapperSuspended(component, options, {
|
|
251
|
+
wrapperFn: mount,
|
|
252
|
+
suspendedHelperName,
|
|
253
|
+
clonedComponentName
|
|
254
|
+
});
|
|
255
|
+
Object.assign(wrapper, { __setProps: setProps });
|
|
256
|
+
const clonedComponent = wrapper.findComponent({ name: clonedComponentName });
|
|
257
|
+
return wrappedMountedWrapper(wrapper, clonedComponent);
|
|
258
|
+
}
|
|
259
|
+
function wrappedMountedWrapper(wrapper, component) {
|
|
236
260
|
const wrapperProps = [
|
|
237
261
|
"setProps",
|
|
238
262
|
"emitted",
|
|
@@ -273,138 +297,27 @@ function wrappedMountedWrapper(wrapper) {
|
|
|
273
297
|
}
|
|
274
298
|
}
|
|
275
299
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
const
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
const setProps = reactive({});
|
|
292
|
-
function patchInstanceAppContext() {
|
|
293
|
-
const app = getCurrentInstance()?.appContext.app;
|
|
294
|
-
if (!app) return;
|
|
295
|
-
for (const [key, value] of Object.entries(vueApp)) {
|
|
296
|
-
if (key in app) continue;
|
|
297
|
-
app[key] = value;
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
for (const fn of window.__cleanup || []) {
|
|
301
|
-
fn();
|
|
302
|
-
}
|
|
303
|
-
document.querySelector(`#${WRAPPER_EL_ID}`)?.remove();
|
|
304
|
-
const wrappedSetup = async (props2, setupContext2, instanceContext) => {
|
|
305
|
-
const currentInstance = getCurrentInstance();
|
|
306
|
-
if (currentInstance) {
|
|
307
|
-
currentInstance.emit = (event, ...args) => {
|
|
308
|
-
setupContext2.emit(event, ...args);
|
|
309
|
-
};
|
|
310
|
-
}
|
|
311
|
-
if (setup) {
|
|
312
|
-
const result = await setup(props2, setupContext2);
|
|
313
|
-
setupState = result && typeof result === "object" ? result : {};
|
|
314
|
-
if (wrappedInstance?.exposed) {
|
|
315
|
-
instanceContext.expose(wrappedInstance.exposed);
|
|
316
|
-
}
|
|
317
|
-
return result;
|
|
318
|
-
}
|
|
319
|
-
};
|
|
320
|
-
const WrapperComponent = defineComponent$1({
|
|
321
|
-
inheritAttrs: false,
|
|
322
|
-
render() {
|
|
323
|
-
return h$1("div", { id: WRAPPER_EL_ID }, this.$slots.default?.());
|
|
324
|
-
}
|
|
325
|
-
});
|
|
326
|
-
return new Promise((resolve) => {
|
|
327
|
-
const utils = renderFromTestingLibrary(
|
|
328
|
-
{
|
|
329
|
-
__cssModules: componentRest.__cssModules,
|
|
330
|
-
inheritAttrs: false,
|
|
331
|
-
setup: (props2, ctx) => {
|
|
332
|
-
patchInstanceAppContext();
|
|
333
|
-
wrappedInstance = getCurrentInstance();
|
|
334
|
-
setupContext = ctx;
|
|
335
|
-
const scope = effectScope();
|
|
336
|
-
window.__cleanup ||= [];
|
|
337
|
-
window.__cleanup.push(() => {
|
|
338
|
-
scope.stop();
|
|
339
|
-
});
|
|
340
|
-
return scope.run(() => NuxtRoot.setup(props2, {
|
|
341
|
-
...ctx,
|
|
342
|
-
expose: () => ({})
|
|
343
|
-
}));
|
|
344
|
-
},
|
|
345
|
-
render: () => (
|
|
346
|
-
// See discussions in https://github.com/testing-library/vue-testing-library/issues/230
|
|
347
|
-
// we add this additional root element because otherwise testing-library breaks
|
|
348
|
-
// because there's no root element while Suspense is resolving
|
|
349
|
-
h$1(
|
|
350
|
-
WrapperComponent,
|
|
351
|
-
{},
|
|
352
|
-
{
|
|
353
|
-
default: () => h$1(
|
|
354
|
-
Suspense,
|
|
355
|
-
{
|
|
356
|
-
onResolve: () => nextTick().then(() => {
|
|
357
|
-
utils.setupState = setupState;
|
|
358
|
-
utils.rerender = async (props2) => {
|
|
359
|
-
Object.assign(setProps, props2);
|
|
360
|
-
await nextTick();
|
|
361
|
-
};
|
|
362
|
-
resolve(utils);
|
|
363
|
-
})
|
|
364
|
-
},
|
|
365
|
-
{
|
|
366
|
-
default: () => h$1({
|
|
367
|
-
name: "RenderHelper",
|
|
368
|
-
async setup() {
|
|
369
|
-
const router = useRouter();
|
|
370
|
-
await router.replace(route);
|
|
371
|
-
const clonedComponent = {
|
|
372
|
-
components: {},
|
|
373
|
-
...component,
|
|
374
|
-
name: "RenderSuspendedComponent",
|
|
375
|
-
render,
|
|
376
|
-
setup: (props2, ctx) => wrappedSetup(props2, setupContext, ctx)
|
|
377
|
-
};
|
|
378
|
-
return () => h$1(clonedComponent, { ...props && typeof props === "object" ? props : {}, ...setProps, ...attrs }, setupContext.slots);
|
|
379
|
-
}
|
|
380
|
-
})
|
|
381
|
-
}
|
|
382
|
-
)
|
|
383
|
-
}
|
|
384
|
-
)
|
|
385
|
-
)
|
|
386
|
-
},
|
|
387
|
-
defu(_options, {
|
|
388
|
-
props,
|
|
389
|
-
slots,
|
|
390
|
-
attrs,
|
|
391
|
-
global: {
|
|
392
|
-
config: {
|
|
393
|
-
globalProperties: {
|
|
394
|
-
...vueApp.config.globalProperties,
|
|
395
|
-
// make all properties/keys enumerable.
|
|
396
|
-
...Object.fromEntries(
|
|
397
|
-
Object.getOwnPropertyNames(vueApp.config.globalProperties).map((key) => [key, vueApp.config.globalProperties[key]])
|
|
398
|
-
)
|
|
399
|
-
}
|
|
400
|
-
},
|
|
401
|
-
directives: vueApp._context.directives,
|
|
402
|
-
provide: vueApp._context.provides,
|
|
403
|
-
components: { RouterLink }
|
|
404
|
-
}
|
|
405
|
-
})
|
|
406
|
-
);
|
|
300
|
+
async function renderSuspended(component, options = {}) {
|
|
301
|
+
const wrapperId = "test-wrapper";
|
|
302
|
+
const suspendedHelperName = "RenderHelper";
|
|
303
|
+
const clonedComponentName = "RenderSuspendedComponent";
|
|
304
|
+
const { render: wrapperFn } = await import('@testing-library/vue');
|
|
305
|
+
cleanupAll();
|
|
306
|
+
document.getElementById(wrapperId)?.remove();
|
|
307
|
+
const { wrapper, setProps } = await wrapperSuspended(component, options, {
|
|
308
|
+
wrapperFn,
|
|
309
|
+
wrappedRender: (render) => () => h$1({
|
|
310
|
+
inheritAttrs: false,
|
|
311
|
+
render: () => h$1("div", { id: wrapperId }, render())
|
|
312
|
+
}),
|
|
313
|
+
suspendedHelperName,
|
|
314
|
+
clonedComponentName
|
|
407
315
|
});
|
|
316
|
+
wrapper.rerender = async (props) => {
|
|
317
|
+
setProps(props);
|
|
318
|
+
await nextTick();
|
|
319
|
+
};
|
|
320
|
+
return wrapper;
|
|
408
321
|
}
|
|
409
322
|
|
|
410
323
|
export { mockComponent, mockNuxtImport, mountSuspended, registerEndpoint, renderSuspended };
|
|
@@ -1,8 +1,8 @@
|
|
|
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.BsmyE2FA.mjs';
|
|
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.
|
|
5
|
+
import { l as loadKit } from './test-utils.BIY9XRkB.mjs';
|
|
6
6
|
|
|
7
7
|
async function createBrowser() {
|
|
8
8
|
const ctx = useTestContext();
|
|
@@ -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;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { x } from 'tinyexec';
|
|
2
2
|
import { getRandomPort, waitForPort } from 'get-port-please';
|
|
3
|
-
import {
|
|
3
|
+
import { createFetch, fetch as fetch$1 } from 'ofetch';
|
|
4
4
|
import { resolve as resolve$1 } from 'pathe';
|
|
5
5
|
import { withTrailingSlash, joinURL } from 'ufo';
|
|
6
6
|
import { resolve } from 'node:path';
|
|
@@ -72,6 +72,7 @@ function exposeContextToEnv() {
|
|
|
72
72
|
process.env.NUXT_TEST_CONTEXT = JSON.stringify({ options, browser, url });
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
+
const globalFetch = globalThis.fetch || fetch$1;
|
|
75
76
|
async function startServer(options = {}) {
|
|
76
77
|
const ctx = useTestContext();
|
|
77
78
|
await stopServer();
|
|
@@ -91,8 +92,8 @@ async function startServer(options = {}) {
|
|
|
91
92
|
PORT: String(port),
|
|
92
93
|
HOST: host,
|
|
93
94
|
NODE_ENV: "development",
|
|
94
|
-
...options.env,
|
|
95
|
-
...
|
|
95
|
+
...ctx.options.env,
|
|
96
|
+
...options.env
|
|
96
97
|
}
|
|
97
98
|
}
|
|
98
99
|
});
|
|
@@ -128,8 +129,8 @@ async function startServer(options = {}) {
|
|
|
128
129
|
PORT: String(port),
|
|
129
130
|
HOST: host,
|
|
130
131
|
NODE_ENV: "test",
|
|
131
|
-
...options.env,
|
|
132
|
-
...
|
|
132
|
+
...ctx.options.env,
|
|
133
|
+
...options.env
|
|
133
134
|
}
|
|
134
135
|
}
|
|
135
136
|
}
|
|
@@ -144,10 +145,11 @@ async function stopServer() {
|
|
|
144
145
|
}
|
|
145
146
|
}
|
|
146
147
|
function fetch(path, options) {
|
|
147
|
-
return
|
|
148
|
+
return globalFetch(url(path), options);
|
|
148
149
|
}
|
|
149
|
-
const $fetch =
|
|
150
|
-
|
|
150
|
+
const _$fetch = createFetch({ fetch: globalFetch });
|
|
151
|
+
const $fetch = function $fetch2(path, options) {
|
|
152
|
+
return _$fetch(url(path), options);
|
|
151
153
|
};
|
|
152
154
|
function url(path) {
|
|
153
155
|
const ctx = useTestContext();
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Browser, Page, Response as Response$1, BrowserContextOptions, LaunchOptions } from 'playwright-core';
|
|
2
2
|
import { NuxtConfig, Nuxt } from '@nuxt/schema';
|
|
3
3
|
import { exec } from 'tinyexec';
|
|
4
|
+
import { $Fetch } from 'ofetch';
|
|
4
5
|
|
|
5
6
|
declare function createBrowser(): Promise<void>;
|
|
6
7
|
declare function getBrowser(): Promise<Browser>;
|
|
@@ -20,7 +21,7 @@ interface StartServerOptions {
|
|
|
20
21
|
declare function startServer(options?: StartServerOptions): Promise<void>;
|
|
21
22
|
declare function stopServer(): Promise<void>;
|
|
22
23
|
declare function fetch(path: string, options?: RequestInit): Promise<Response>;
|
|
23
|
-
declare const $fetch:
|
|
24
|
+
declare const $fetch: "$fetch" extends keyof typeof globalThis ? typeof globalThis.$fetch : $Fetch;
|
|
24
25
|
declare function url(path: string): string;
|
|
25
26
|
|
|
26
27
|
type TestRunner = 'vitest' | 'jest' | 'cucumber' | 'bun';
|
|
@@ -116,4 +117,4 @@ interface TestHooks {
|
|
|
116
117
|
}
|
|
117
118
|
|
|
118
119
|
export { $fetch as $, createBrowser as c, createPage as d, stopServer as e, fetch as f, getBrowser as g, startServer as s, url as u, waitForHydration as w };
|
|
119
|
-
export type { GotoOptions as G, NuxtPage as N, StartServerOptions as S, TestOptions as T,
|
|
120
|
+
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,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 };
|
|
@@ -1,13 +1,25 @@
|
|
|
1
1
|
import { Environment } from 'vitest/environments';
|
|
2
|
-
import {
|
|
2
|
+
import { H3Event as H3Event$1 } from 'h3';
|
|
3
|
+
import { H3Event } from 'h3-next';
|
|
3
4
|
import { $Fetch } from 'nitropack';
|
|
4
5
|
import { JSDOMOptions, HappyDOMOptions } from 'vitest/node';
|
|
5
6
|
|
|
6
7
|
declare const _default: Environment;
|
|
7
8
|
|
|
8
9
|
type NuxtBuiltinEnvironment = 'happy-dom' | 'jsdom';
|
|
10
|
+
interface GenericAppUse {
|
|
11
|
+
(route: string, handler: (event: H3Event | H3Event$1) => unknown, options?: {
|
|
12
|
+
match: (...args: [string, H3Event$1 | undefined] | [H3Event]) => boolean;
|
|
13
|
+
}): void;
|
|
14
|
+
(handler: (event: H3Event | H3Event$1) => unknown, options?: {
|
|
15
|
+
match: (...args: [string, H3Event$1 | undefined] | [H3Event]) => boolean;
|
|
16
|
+
}): void;
|
|
17
|
+
}
|
|
18
|
+
interface GenericApp {
|
|
19
|
+
use: GenericAppUse;
|
|
20
|
+
}
|
|
9
21
|
interface NuxtWindow extends Window {
|
|
10
|
-
__app
|
|
22
|
+
__app?: GenericApp;
|
|
11
23
|
__registry: Set<string>;
|
|
12
24
|
__NUXT_VITEST_ENVIRONMENT__?: boolean;
|
|
13
25
|
__NUXT__: Record<string, unknown>;
|
|
@@ -26,4 +38,4 @@ type EnvironmentNuxt = (global: typeof globalThis, options: EnvironmentNuxtOptio
|
|
|
26
38
|
}>;
|
|
27
39
|
|
|
28
40
|
export { _default as default };
|
|
29
|
-
export type { EnvironmentNuxt, EnvironmentNuxtOptions, NuxtBuiltinEnvironment, NuxtWindow };
|
|
41
|
+
export type { EnvironmentNuxt, EnvironmentNuxtOptions, GenericApp, NuxtBuiltinEnvironment, NuxtWindow };
|