@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
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { defineEventHandler } from 'h3';
|
|
2
2
|
import { mount } from '@vue/test-utils';
|
|
3
|
-
import { reactive, h as h$1, Suspense, nextTick
|
|
3
|
+
import { reactive, h as h$1, Suspense, nextTick as nextTick$1, getCurrentInstance, onErrorCaptured, effectScope } from 'vue';
|
|
4
4
|
import { defu } from 'defu';
|
|
5
5
|
import { defineComponent, useRouter, h, tryUseNuxtApp } from '#imports';
|
|
6
6
|
import NuxtRoot from '#build/root-component.mjs';
|
|
@@ -11,16 +11,25 @@ function registerEndpoint(url, options) {
|
|
|
11
11
|
if (!app) {
|
|
12
12
|
throw new Error("registerEndpoint() can only be used in a `@nuxt/test-utils` runtime environment");
|
|
13
13
|
}
|
|
14
|
-
const config = typeof options === "function" ? { handler: options, method: void 0 } : options;
|
|
14
|
+
const config = typeof options === "function" ? { handler: options, method: void 0, once: false } : options;
|
|
15
15
|
config.handler = defineEventHandler(config.handler);
|
|
16
16
|
const hasBeenRegistered = window.__registry.has(url);
|
|
17
17
|
endpointRegistry[url] ||= [];
|
|
18
18
|
endpointRegistry[url].push(config);
|
|
19
19
|
if (!hasBeenRegistered) {
|
|
20
20
|
window.__registry.add(url);
|
|
21
|
-
app.use("/_" + url, defineEventHandler((event) => {
|
|
21
|
+
app.use("/_" + url, defineEventHandler(async (event) => {
|
|
22
22
|
const latestHandler = [...endpointRegistry[url] || []].reverse().find((config2) => config2.method ? event.method === config2.method : true);
|
|
23
|
-
|
|
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;
|
|
24
33
|
}), {
|
|
25
34
|
match(_, event) {
|
|
26
35
|
return endpointRegistry[url]?.some((config2) => config2.method ? event?.method === config2.method : true) ?? false;
|
|
@@ -34,7 +43,7 @@ function registerEndpoint(url, options) {
|
|
|
34
43
|
}
|
|
35
44
|
};
|
|
36
45
|
}
|
|
37
|
-
function mockNuxtImport(
|
|
46
|
+
function mockNuxtImport(_target, _factory) {
|
|
38
47
|
throw new Error(
|
|
39
48
|
"mockNuxtImport() is a macro and it did not get transpiled. This may be an internal bug of @nuxt/test-utils."
|
|
40
49
|
);
|
|
@@ -79,406 +88,231 @@ const RouterLink = defineComponent({
|
|
|
79
88
|
}
|
|
80
89
|
});
|
|
81
90
|
|
|
82
|
-
|
|
83
|
-
const {
|
|
84
|
-
|
|
85
|
-
attrs = {},
|
|
86
|
-
slots = {},
|
|
87
|
-
route = "/",
|
|
88
|
-
..._options
|
|
89
|
-
} = options || {};
|
|
90
|
-
for (const cleanupFunction of globalThis.__cleanup || []) {
|
|
91
|
-
cleanupFunction();
|
|
91
|
+
function cleanupAll() {
|
|
92
|
+
for (const fn of (window.__cleanup || []).splice(0)) {
|
|
93
|
+
fn();
|
|
92
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;
|
|
93
113
|
const vueApp = tryUseNuxtApp()?.vueApp || globalThis.__unctx__.get("nuxt-app").tryUse().vueApp;
|
|
94
|
-
const {
|
|
114
|
+
const {
|
|
115
|
+
render: componentRender,
|
|
116
|
+
setup: componentSetup,
|
|
117
|
+
...componentRest
|
|
118
|
+
} = component;
|
|
119
|
+
let wrappedInstance = null;
|
|
95
120
|
let setupContext;
|
|
96
121
|
let setupState;
|
|
97
122
|
const setProps = reactive({});
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
if (
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
});
|
|
123
|
+
function patchInstanceAppContext() {
|
|
124
|
+
const app = getCurrentInstance()?.appContext.app;
|
|
125
|
+
if (!app) return;
|
|
126
|
+
for (const [key, value] of Object.entries(vueApp)) {
|
|
127
|
+
if (key in app) continue;
|
|
128
|
+
app[key] = value;
|
|
105
129
|
}
|
|
106
|
-
return interceptedEmit;
|
|
107
130
|
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
componentScope = effectScope();
|
|
124
|
-
globalThis.__cleanup ||= [];
|
|
125
|
-
globalThis.__cleanup.push(() => {
|
|
126
|
-
componentScope?.stop();
|
|
127
|
-
});
|
|
128
|
-
result = await componentScope?.run(async () => {
|
|
129
|
-
return await setup(props2, setupContext2);
|
|
130
|
-
});
|
|
131
|
-
} else {
|
|
132
|
-
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
|
+
};
|
|
141
|
+
}
|
|
142
|
+
if (!componentSetup) return;
|
|
143
|
+
const result = scoped ? await runEffectScope(() => componentSetup(props2, setupContext)) : await componentSetup(props2, setupContext);
|
|
144
|
+
if (wrappedInstance?.exposed) {
|
|
145
|
+
instanceContext.expose(wrappedInstance.exposed);
|
|
133
146
|
}
|
|
134
147
|
setupState = result && typeof result === "object" ? result : {};
|
|
135
148
|
return result;
|
|
136
149
|
}
|
|
137
150
|
};
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
const scope = effectScope();
|
|
146
|
-
globalThis.__cleanup ||= [];
|
|
147
|
-
globalThis.__cleanup.push(() => {
|
|
148
|
-
scope.stop();
|
|
149
|
-
});
|
|
150
|
-
return scope.run(() => NuxtRoot.setup(props2, {
|
|
151
|
-
...ctx,
|
|
152
|
-
expose: () => {
|
|
153
|
-
}
|
|
154
|
-
}));
|
|
155
|
-
} else {
|
|
156
|
-
return NuxtRoot.setup(props2, {
|
|
157
|
-
...ctx,
|
|
158
|
-
expose: () => {
|
|
159
|
-
}
|
|
160
|
-
});
|
|
161
|
-
}
|
|
162
|
-
},
|
|
163
|
-
render: (renderContext) => h$1(
|
|
164
|
-
Suspense,
|
|
165
|
-
{
|
|
166
|
-
onResolve: () => nextTick().then(() => {
|
|
167
|
-
vm.setupState = setupState;
|
|
168
|
-
vm.__setProps = (props2) => {
|
|
169
|
-
Object.assign(setProps, props2);
|
|
170
|
-
};
|
|
171
|
-
resolve(wrappedMountedWrapper(vm));
|
|
172
|
-
})
|
|
173
|
-
},
|
|
174
|
-
{
|
|
175
|
-
default: () => h$1({
|
|
176
|
-
name: "MountSuspendedHelper",
|
|
177
|
-
async setup() {
|
|
178
|
-
const router = useRouter();
|
|
179
|
-
await router.replace(route);
|
|
180
|
-
const clonedComponent = {
|
|
181
|
-
name: "MountSuspendedComponent",
|
|
182
|
-
...component,
|
|
183
|
-
render: render ? function(_ctx, ...args) {
|
|
184
|
-
interceptEmitOnCurrentInstance();
|
|
185
|
-
if (data && typeof data === "function") {
|
|
186
|
-
const dataObject = data();
|
|
187
|
-
for (const key in dataObject) {
|
|
188
|
-
renderContext[key] = dataObject[key];
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
for (const key in setupState || {}) {
|
|
192
|
-
const warn = console.warn;
|
|
193
|
-
console.warn = () => {
|
|
194
|
-
};
|
|
195
|
-
try {
|
|
196
|
-
renderContext[key] = isReadonly(setupState[key]) ? unref(setupState[key]) : setupState[key];
|
|
197
|
-
} catch {
|
|
198
|
-
} finally {
|
|
199
|
-
console.warn = warn;
|
|
200
|
-
}
|
|
201
|
-
if (key === "props") {
|
|
202
|
-
renderContext[key] = cloneProps$1(renderContext[key]);
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
const propsContext = "props" in renderContext ? renderContext.props : renderContext;
|
|
206
|
-
for (const key in props || {}) {
|
|
207
|
-
propsContext[key] = _ctx[key];
|
|
208
|
-
}
|
|
209
|
-
for (const key in passedProps || {}) {
|
|
210
|
-
propsContext[key] = passedProps[key];
|
|
211
|
-
}
|
|
212
|
-
if (methods && typeof methods === "object") {
|
|
213
|
-
for (const [key, value] of Object.entries(methods)) {
|
|
214
|
-
renderContext[key] = value.bind(renderContext);
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
if (computed && typeof computed === "object") {
|
|
218
|
-
for (const [key, value] of Object.entries(computed)) {
|
|
219
|
-
if ("get" in value) {
|
|
220
|
-
renderContext[key] = value.get.call(renderContext);
|
|
221
|
-
} else {
|
|
222
|
-
renderContext[key] = value.call(renderContext);
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
return render.call(this, renderContext, ...args);
|
|
227
|
-
} : void 0,
|
|
228
|
-
setup: (props2) => wrappedSetup(props2, setupContext)
|
|
229
|
-
};
|
|
230
|
-
return () => h$1(clonedComponent, { ...props, ...setProps, ...attrs }, slots);
|
|
231
|
-
}
|
|
232
|
-
})
|
|
233
|
-
}
|
|
234
|
-
)
|
|
235
|
-
},
|
|
236
|
-
defu(
|
|
237
|
-
_options,
|
|
238
|
-
{
|
|
239
|
-
slots,
|
|
240
|
-
attrs,
|
|
241
|
-
global: {
|
|
242
|
-
config: {
|
|
243
|
-
globalProperties: vueApp.config.globalProperties
|
|
244
|
-
},
|
|
245
|
-
directives: vueApp._context.directives,
|
|
246
|
-
provide: vueApp._context.provides,
|
|
247
|
-
stubs: {
|
|
248
|
-
Suspense: false,
|
|
249
|
-
MountSuspendedHelper: false,
|
|
250
|
-
[component && typeof component === "object" && "name" in component && typeof component.name === "string" ? component.name : "MountSuspendedComponent"]: false
|
|
251
|
-
},
|
|
252
|
-
components: { ...vueApp._context.components, RouterLink }
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
)
|
|
256
|
-
);
|
|
257
|
-
}
|
|
258
|
-
);
|
|
259
|
-
}
|
|
260
|
-
function cloneProps$1(props) {
|
|
261
|
-
const newProps = reactive({});
|
|
262
|
-
for (const key in props) {
|
|
263
|
-
newProps[key] = props[key];
|
|
264
|
-
}
|
|
265
|
-
return newProps;
|
|
266
|
-
}
|
|
267
|
-
function wrappedMountedWrapper(wrapper) {
|
|
268
|
-
const proxy = new Proxy(wrapper, {
|
|
269
|
-
get: (target, prop, receiver) => {
|
|
270
|
-
if (prop === "element") {
|
|
271
|
-
const component = target.findComponent({ name: "MountSuspendedComponent" });
|
|
272
|
-
return component[prop];
|
|
273
|
-
} else if (prop === "vm") {
|
|
274
|
-
const vm = Reflect.get(target, prop, receiver);
|
|
275
|
-
return createVMProxy(vm, wrapper.setupState);
|
|
276
|
-
} else {
|
|
277
|
-
return Reflect.get(target, prop, receiver);
|
|
151
|
+
const SuspendedHelper = {
|
|
152
|
+
name: suspendedHelperName,
|
|
153
|
+
render: () => "",
|
|
154
|
+
async setup() {
|
|
155
|
+
if (route) {
|
|
156
|
+
const router = useRouter();
|
|
157
|
+
await router.replace(route);
|
|
278
158
|
}
|
|
279
|
-
|
|
280
|
-
});
|
|
281
|
-
for (const key of ["props"]) {
|
|
282
|
-
proxy[key] = new Proxy(wrapper[key], {
|
|
283
|
-
apply: (target, thisArg, args) => {
|
|
284
|
-
const component = thisArg.findComponent({ name: "MountSuspendedComponent" });
|
|
285
|
-
return component[key](...args);
|
|
286
|
-
}
|
|
287
|
-
});
|
|
288
|
-
}
|
|
289
|
-
return proxy;
|
|
290
|
-
}
|
|
291
|
-
function createVMProxy(vm, setupState) {
|
|
292
|
-
return new Proxy(vm, {
|
|
293
|
-
get(target, key, receiver) {
|
|
294
|
-
const value = Reflect.get(target, key, receiver);
|
|
295
|
-
if (setupState && typeof setupState === "object" && key in setupState) {
|
|
296
|
-
return unref(setupState[key]);
|
|
297
|
-
}
|
|
298
|
-
return value;
|
|
299
|
-
},
|
|
300
|
-
set(target, key, value, receiver) {
|
|
301
|
-
if (setupState && typeof setupState === "object" && key in setupState) {
|
|
302
|
-
const setupValue = setupState[key];
|
|
303
|
-
if (setupValue && isRef(setupValue)) {
|
|
304
|
-
setupValue.value = value;
|
|
305
|
-
return true;
|
|
306
|
-
}
|
|
307
|
-
return Reflect.set(setupState, key, value, receiver);
|
|
308
|
-
}
|
|
309
|
-
return Reflect.set(target, key, value, receiver);
|
|
310
|
-
}
|
|
311
|
-
});
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
const WRAPPER_EL_ID = "test-wrapper";
|
|
315
|
-
async function renderSuspended(component, options) {
|
|
316
|
-
const {
|
|
317
|
-
props = {},
|
|
318
|
-
attrs = {},
|
|
319
|
-
slots = {},
|
|
320
|
-
route = "/",
|
|
321
|
-
..._options
|
|
322
|
-
} = options || {};
|
|
323
|
-
const { render: renderFromTestingLibrary } = await import('@testing-library/vue');
|
|
324
|
-
const vueApp = tryUseNuxtApp()?.vueApp || globalThis.__unctx__.get("nuxt-app").tryUse().vueApp;
|
|
325
|
-
const { render, setup, data, computed, methods } = component;
|
|
326
|
-
let setupContext;
|
|
327
|
-
let setupState;
|
|
328
|
-
let interceptedEmit = null;
|
|
329
|
-
function getInterceptedEmitFunction(emit) {
|
|
330
|
-
if (emit !== interceptedEmit) {
|
|
331
|
-
interceptedEmit = interceptedEmit ?? ((event, ...args) => {
|
|
332
|
-
emit(event, ...args);
|
|
333
|
-
setupContext.emit(event, ...args);
|
|
334
|
-
});
|
|
335
|
-
}
|
|
336
|
-
return interceptedEmit;
|
|
337
|
-
}
|
|
338
|
-
function interceptEmitOnCurrentInstance() {
|
|
339
|
-
const currentInstance = getCurrentInstance();
|
|
340
|
-
if (!currentInstance) {
|
|
341
|
-
return;
|
|
342
|
-
}
|
|
343
|
-
currentInstance.emit = getInterceptedEmitFunction(currentInstance.emit);
|
|
344
|
-
}
|
|
345
|
-
for (const fn of window.__cleanup || []) {
|
|
346
|
-
fn();
|
|
347
|
-
}
|
|
348
|
-
document.querySelector(`#${WRAPPER_EL_ID}`)?.remove();
|
|
349
|
-
let passedProps;
|
|
350
|
-
const wrappedSetup = async (props2, setupContext2) => {
|
|
351
|
-
interceptEmitOnCurrentInstance();
|
|
352
|
-
passedProps = props2;
|
|
353
|
-
if (setup) {
|
|
354
|
-
const result = await setup(props2, setupContext2);
|
|
355
|
-
setupState = result && typeof result === "object" ? result : {};
|
|
356
|
-
return result;
|
|
159
|
+
return () => h$1(ClonedComponent, { ...props, ...setProps, ...attrs }, setupContext.slots);
|
|
357
160
|
}
|
|
358
161
|
};
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
return h$1("div", { id: WRAPPER_EL_ID }, this.$slots.default?.());
|
|
363
|
-
}
|
|
364
|
-
});
|
|
365
|
-
return new Promise((resolve) => {
|
|
366
|
-
const utils = renderFromTestingLibrary(
|
|
162
|
+
return new Promise((resolve, reject) => {
|
|
163
|
+
let isMountSettled = false;
|
|
164
|
+
const wrapper = wrapperFn(
|
|
367
165
|
{
|
|
166
|
+
inheritAttrs: false,
|
|
167
|
+
__cssModules: componentRest.__cssModules,
|
|
368
168
|
setup: (props2, ctx) => {
|
|
169
|
+
patchInstanceAppContext();
|
|
170
|
+
wrappedInstance = getCurrentInstance();
|
|
369
171
|
setupContext = ctx;
|
|
370
|
-
const
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
172
|
+
const nuxtRootSetupResult = runEffectScope(
|
|
173
|
+
() => NuxtRoot.setup(props2, {
|
|
174
|
+
...ctx,
|
|
175
|
+
expose: () => {
|
|
176
|
+
}
|
|
177
|
+
})
|
|
178
|
+
);
|
|
179
|
+
onErrorCaptured((error, ...args) => {
|
|
180
|
+
if (isMountSettled) return;
|
|
181
|
+
isMountSettled = true;
|
|
182
|
+
try {
|
|
183
|
+
wrappedInstance?.appContext.config.errorHandler?.(error, ...args);
|
|
184
|
+
reject(error);
|
|
185
|
+
} catch (error2) {
|
|
186
|
+
reject(error2);
|
|
187
|
+
}
|
|
188
|
+
return false;
|
|
374
189
|
});
|
|
375
|
-
return
|
|
376
|
-
...ctx,
|
|
377
|
-
expose: () => ({})
|
|
378
|
-
}));
|
|
190
|
+
return nuxtRootSetupResult;
|
|
379
191
|
},
|
|
380
|
-
render: (
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
onResolve: () => nextTick().then(() => {
|
|
392
|
-
utils.setupState = setupState;
|
|
393
|
-
resolve(utils);
|
|
394
|
-
})
|
|
395
|
-
},
|
|
396
|
-
{
|
|
397
|
-
default: () => h$1({
|
|
398
|
-
name: "RenderHelper",
|
|
399
|
-
async setup() {
|
|
400
|
-
const router = useRouter();
|
|
401
|
-
await router.replace(route);
|
|
402
|
-
const clonedComponent = {
|
|
403
|
-
name: "RenderSuspendedComponent",
|
|
404
|
-
...component,
|
|
405
|
-
render: render ? function(_ctx, ...args) {
|
|
406
|
-
interceptEmitOnCurrentInstance();
|
|
407
|
-
if (data && typeof data === "function") {
|
|
408
|
-
const dataObject = data();
|
|
409
|
-
for (const key in dataObject) {
|
|
410
|
-
renderContext[key] = dataObject[key];
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
for (const key in setupState || {}) {
|
|
414
|
-
const warn = console.warn;
|
|
415
|
-
console.warn = () => {
|
|
416
|
-
};
|
|
417
|
-
try {
|
|
418
|
-
renderContext[key] = isReadonly(setupState[key]) ? unref(setupState[key]) : setupState[key];
|
|
419
|
-
} catch {
|
|
420
|
-
} finally {
|
|
421
|
-
console.warn = warn;
|
|
422
|
-
}
|
|
423
|
-
if (key === "props") {
|
|
424
|
-
renderContext[key] = cloneProps(renderContext[key]);
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
const propsContext = "props" in renderContext ? renderContext.props : renderContext;
|
|
428
|
-
for (const key in props || {}) {
|
|
429
|
-
propsContext[key] = _ctx[key];
|
|
430
|
-
}
|
|
431
|
-
for (const key in passedProps || {}) {
|
|
432
|
-
propsContext[key] = passedProps[key];
|
|
433
|
-
}
|
|
434
|
-
if (methods && typeof methods === "object") {
|
|
435
|
-
for (const [key, value] of Object.entries(methods)) {
|
|
436
|
-
renderContext[key] = value.bind(renderContext);
|
|
437
|
-
}
|
|
438
|
-
}
|
|
439
|
-
if (computed && typeof computed === "object") {
|
|
440
|
-
for (const [key, value] of Object.entries(computed)) {
|
|
441
|
-
if ("get" in value) {
|
|
442
|
-
renderContext[key] = value.get.call(renderContext);
|
|
443
|
-
} else {
|
|
444
|
-
renderContext[key] = value.call(renderContext);
|
|
445
|
-
}
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
|
-
return render.call(this, renderContext, ...args);
|
|
449
|
-
} : void 0,
|
|
450
|
-
setup: (props2) => wrappedSetup(props2, setupContext)
|
|
451
|
-
};
|
|
452
|
-
return () => h$1(clonedComponent, { ...props && typeof props === "object" ? props : {}, ...attrs }, slots);
|
|
453
|
-
}
|
|
454
|
-
})
|
|
192
|
+
render: wrappedRender(() => h$1(
|
|
193
|
+
Suspense,
|
|
194
|
+
{
|
|
195
|
+
onResolve: () => nextTick$1().then(() => {
|
|
196
|
+
if (isMountSettled) return;
|
|
197
|
+
isMountSettled = true;
|
|
198
|
+
wrapper.setupState = setupState;
|
|
199
|
+
resolve({
|
|
200
|
+
wrapper,
|
|
201
|
+
setProps: (props2) => {
|
|
202
|
+
Object.assign(setProps, props2);
|
|
455
203
|
}
|
|
456
|
-
)
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
|
|
204
|
+
});
|
|
205
|
+
})
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
default: () => h$1(SuspendedHelper)
|
|
209
|
+
}
|
|
210
|
+
))
|
|
460
211
|
},
|
|
461
|
-
defu(
|
|
462
|
-
slots,
|
|
463
|
-
attrs,
|
|
212
|
+
defu(wrapperFnOptions, {
|
|
464
213
|
global: {
|
|
465
214
|
config: {
|
|
466
|
-
globalProperties:
|
|
215
|
+
globalProperties: makeAllPropertiesEnumerable(
|
|
216
|
+
vueApp.config.globalProperties
|
|
217
|
+
)
|
|
467
218
|
},
|
|
468
219
|
directives: vueApp._context.directives,
|
|
469
220
|
provide: vueApp._context.provides,
|
|
470
|
-
|
|
221
|
+
stubs: {
|
|
222
|
+
Suspense: false,
|
|
223
|
+
[SuspendedHelper.name]: false,
|
|
224
|
+
[ClonedComponent.name]: false
|
|
225
|
+
},
|
|
226
|
+
components: { ...vueApp._context.components, RouterLink }
|
|
471
227
|
}
|
|
472
228
|
})
|
|
473
229
|
);
|
|
474
230
|
});
|
|
475
231
|
}
|
|
476
|
-
function
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
232
|
+
function makeAllPropertiesEnumerable(target) {
|
|
233
|
+
return {
|
|
234
|
+
...target,
|
|
235
|
+
...Object.fromEntries(
|
|
236
|
+
Object.getOwnPropertyNames(target).map((key) => [key, target[key]])
|
|
237
|
+
)
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
async function mountSuspended(component, options = {}) {
|
|
242
|
+
const suspendedHelperName = "MountSuspendedHelper";
|
|
243
|
+
const clonedComponentName = "MountSuspendedComponent";
|
|
244
|
+
cleanupAll();
|
|
245
|
+
const { wrapper, setProps } = await wrapperSuspended(component, options, {
|
|
246
|
+
wrapperFn: mount,
|
|
247
|
+
suspendedHelperName,
|
|
248
|
+
clonedComponentName
|
|
249
|
+
});
|
|
250
|
+
Object.assign(wrapper, { __setProps: setProps });
|
|
251
|
+
const clonedComponent = wrapper.findComponent({ name: clonedComponentName });
|
|
252
|
+
return wrappedMountedWrapper(wrapper, clonedComponent);
|
|
253
|
+
}
|
|
254
|
+
function wrappedMountedWrapper(wrapper, component) {
|
|
255
|
+
const wrapperProps = [
|
|
256
|
+
"setProps",
|
|
257
|
+
"emitted",
|
|
258
|
+
"setupState",
|
|
259
|
+
"unmount"
|
|
260
|
+
];
|
|
261
|
+
return new Proxy(wrapper, {
|
|
262
|
+
get: (_, prop, receiver) => {
|
|
263
|
+
if (prop === "getCurrentComponent") return getCurrentComponentPatchedProxy;
|
|
264
|
+
const target = wrapperProps.includes(prop) ? wrapper : Reflect.has(component, prop) ? component : wrapper;
|
|
265
|
+
const value = Reflect.get(target, prop, receiver);
|
|
266
|
+
return typeof value === "function" ? value.bind(target) : value;
|
|
267
|
+
}
|
|
268
|
+
});
|
|
269
|
+
function getCurrentComponentPatchedProxy() {
|
|
270
|
+
const currentComponent = component.getCurrentComponent();
|
|
271
|
+
return new Proxy(currentComponent, {
|
|
272
|
+
get: (target, prop, receiver) => {
|
|
273
|
+
const value = Reflect.get(target, prop, receiver);
|
|
274
|
+
if (prop === "proxy" && value) {
|
|
275
|
+
return new Proxy(value, {
|
|
276
|
+
get(o, p, r) {
|
|
277
|
+
if (!Reflect.has(currentComponent.props, p)) {
|
|
278
|
+
const setupState = wrapper.setupState;
|
|
279
|
+
if (setupState && typeof setupState === "object") {
|
|
280
|
+
if (Reflect.has(setupState, p)) {
|
|
281
|
+
return Reflect.get(setupState, p, r);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
return Reflect.get(o, p, r);
|
|
286
|
+
}
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
return value;
|
|
290
|
+
}
|
|
291
|
+
});
|
|
480
292
|
}
|
|
481
|
-
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
async function renderSuspended(component, options = {}) {
|
|
296
|
+
const wrapperId = "test-wrapper";
|
|
297
|
+
const suspendedHelperName = "RenderHelper";
|
|
298
|
+
const clonedComponentName = "RenderSuspendedComponent";
|
|
299
|
+
const { render: wrapperFn } = await import('@testing-library/vue');
|
|
300
|
+
cleanupAll();
|
|
301
|
+
document.getElementById(wrapperId)?.remove();
|
|
302
|
+
const { wrapper, setProps } = await wrapperSuspended(component, options, {
|
|
303
|
+
wrapperFn,
|
|
304
|
+
wrappedRender: (render) => () => h$1({
|
|
305
|
+
inheritAttrs: false,
|
|
306
|
+
render: () => h$1("div", { id: wrapperId }, render())
|
|
307
|
+
}),
|
|
308
|
+
suspendedHelperName,
|
|
309
|
+
clonedComponentName
|
|
310
|
+
});
|
|
311
|
+
wrapper.rerender = async (props) => {
|
|
312
|
+
setProps(props);
|
|
313
|
+
await nextTick();
|
|
314
|
+
};
|
|
315
|
+
return wrapper;
|
|
482
316
|
}
|
|
483
317
|
|
|
484
318
|
export { mockComponent, mockNuxtImport, mountSuspended, registerEndpoint, renderSuspended };
|