@nuxt/test-utils-nightly 3.21.0-20251031-123045-c452751 → 3.21.0-20251204-130449-b6179fd
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/module.mjs +17 -10
- package/dist/runtime-utils/index.d.mts +19 -11
- package/dist/runtime-utils/index.mjs +104 -194
- package/package.json +17 -17
package/dist/module.mjs
CHANGED
|
@@ -10,7 +10,7 @@ import { walk } from 'estree-walker';
|
|
|
10
10
|
import MagicString from 'magic-string';
|
|
11
11
|
import { createUnplugin } from 'unplugin';
|
|
12
12
|
import { readFileSync } from 'node:fs';
|
|
13
|
-
import { extname, join, dirname } from 'pathe';
|
|
13
|
+
import { extname, join, dirname, relative } from 'pathe';
|
|
14
14
|
import 'node:process';
|
|
15
15
|
import 'vite';
|
|
16
16
|
import 'c12';
|
|
@@ -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 });
|
|
@@ -317,7 +317,7 @@ const NuxtRootStubPlugin = createUnplugin((options) => {
|
|
|
317
317
|
});
|
|
318
318
|
|
|
319
319
|
const vitePluginBlocklist = ["vite-plugin-vue-inspector", "vite-plugin-vue-inspector:post", "vite-plugin-inspect", "nuxt:type-check"];
|
|
320
|
-
const module = defineNuxtModule({
|
|
320
|
+
const module$1 = defineNuxtModule({
|
|
321
321
|
meta: {
|
|
322
322
|
name: "@nuxt/test-utils",
|
|
323
323
|
configKey: "testUtils"
|
|
@@ -339,8 +339,15 @@ const module = defineNuxtModule({
|
|
|
339
339
|
nuxt.options.vite.define ||= {};
|
|
340
340
|
nuxt.options.vite.define["import.meta.vitest"] = "undefined";
|
|
341
341
|
}
|
|
342
|
-
nuxt.hook("prepare:types", (
|
|
343
|
-
references.push({ types: "vitest/import-meta" });
|
|
342
|
+
nuxt.hook("prepare:types", (ctx2) => {
|
|
343
|
+
ctx2.references.push({ types: "vitest/import-meta" });
|
|
344
|
+
if (ctx2.nodeTsConfig) {
|
|
345
|
+
ctx2.nodeTsConfig.include ||= [];
|
|
346
|
+
ctx2.nodeTsConfig.include.push(relative(nuxt.options.buildDir, join(nuxt.options.rootDir, "vitest.config.*")));
|
|
347
|
+
if (nuxt.options.workspaceDir !== nuxt.options.rootDir) {
|
|
348
|
+
ctx2.nodeTsConfig.include.push(relative(nuxt.options.buildDir, join(nuxt.options.workspaceDir, "vitest.config.*")));
|
|
349
|
+
}
|
|
350
|
+
}
|
|
344
351
|
});
|
|
345
352
|
if (!nuxt.options.dev) return;
|
|
346
353
|
if (process.env.TEST || process.env.VITE_TEST) return;
|
|
@@ -461,4 +468,4 @@ function toArray(value) {
|
|
|
461
468
|
return Array.isArray(value) ? value : [value];
|
|
462
469
|
}
|
|
463
470
|
|
|
464
|
-
export { module as default };
|
|
471
|
+
export { module$1 as default };
|
|
@@ -2,8 +2,7 @@ import { EventHandler, HTTPMethod } from 'h3';
|
|
|
2
2
|
import { SetupContext, RenderFunction, ComputedOptions, MethodOptions, ComponentOptionsMixin, EmitsOptions, ComponentInjectOptions, ComponentOptionsWithoutProps, ComponentOptionsWithArrayProps, ComponentPropsOptions, ComponentOptionsWithObjectProps } from 'vue';
|
|
3
3
|
import { ComponentMountingOptions, mount } from '@vue/test-utils';
|
|
4
4
|
import { RouteLocationRaw } from 'vue-router';
|
|
5
|
-
import
|
|
6
|
-
import { RenderOptions as RenderOptions$1 } from '@testing-library/vue';
|
|
5
|
+
import { RenderOptions, RenderResult } from '@testing-library/vue';
|
|
7
6
|
|
|
8
7
|
type Awaitable<T> = T | Promise<T>;
|
|
9
8
|
type OptionalFunction<T> = T | (() => Awaitable<T>);
|
|
@@ -37,7 +36,7 @@ declare function registerEndpoint(url: string, options: EventHandler | {
|
|
|
37
36
|
}): () => void;
|
|
38
37
|
/**
|
|
39
38
|
* `mockNuxtImport` allows you to mock Nuxt's auto import functionality.
|
|
40
|
-
* @param
|
|
39
|
+
* @param _target - name of an import to mock or mocked target.
|
|
41
40
|
* @param _factory - factory function that returns mocked import.
|
|
42
41
|
* @example
|
|
43
42
|
* ```ts
|
|
@@ -48,10 +47,17 @@ declare function registerEndpoint(url: string, options: EventHandler | {
|
|
|
48
47
|
* return { value: 'mocked storage' }
|
|
49
48
|
* }
|
|
50
49
|
* })
|
|
50
|
+
*
|
|
51
|
+
* // With mocked target
|
|
52
|
+
* mockNuxtImport(useStorage, () => {
|
|
53
|
+
* return () => {
|
|
54
|
+
* return { value: 'mocked storage' }
|
|
55
|
+
* }
|
|
56
|
+
* })
|
|
51
57
|
* ```
|
|
52
58
|
* @see https://nuxt.com/docs/getting-started/testing#mocknuxtimport
|
|
53
59
|
*/
|
|
54
|
-
declare function mockNuxtImport<T = unknown>(
|
|
60
|
+
declare function mockNuxtImport<T = unknown>(_target: string | T, _factory: () => T | Promise<T>): void;
|
|
55
61
|
/**
|
|
56
62
|
* `mockComponent` allows you to mock Nuxt's component.
|
|
57
63
|
* @param path - component name in PascalCase, or the relative path of the component.
|
|
@@ -93,6 +99,9 @@ type MountSuspendedOptions<T> = ComponentMountingOptions<T> & {
|
|
|
93
99
|
route?: RouteLocationRaw;
|
|
94
100
|
scoped?: boolean;
|
|
95
101
|
};
|
|
102
|
+
type MountSuspendedResult<T> = ReturnType<typeof mount<T>> & {
|
|
103
|
+
setupState: SetupState$1;
|
|
104
|
+
};
|
|
96
105
|
type SetupState$1 = Record<string, any>;
|
|
97
106
|
/**
|
|
98
107
|
* `mountSuspended` allows you to mount any vue component within the Nuxt environment, allowing async setup and access to injections from your Nuxt plugins. For example:
|
|
@@ -120,16 +129,17 @@ type SetupState$1 = Record<string, any>;
|
|
|
120
129
|
* @param component the component to be tested
|
|
121
130
|
* @param options optional options to set up your component
|
|
122
131
|
*/
|
|
123
|
-
declare function mountSuspended<T>(component: T, options?: MountSuspendedOptions<T>): Promise<
|
|
124
|
-
setupState: SetupState$1;
|
|
125
|
-
}>;
|
|
132
|
+
declare function mountSuspended<T>(component: T, options?: MountSuspendedOptions<T>): Promise<MountSuspendedResult<T>>;
|
|
126
133
|
declare global {
|
|
127
134
|
var __cleanup: Array<() => void> | undefined;
|
|
128
135
|
}
|
|
129
136
|
|
|
130
|
-
type
|
|
137
|
+
type RenderSuspendeOptions<T> = RenderOptions<T> & {
|
|
131
138
|
route?: RouteLocationRaw;
|
|
132
139
|
};
|
|
140
|
+
type RenderSuspendeResult = RenderResult & {
|
|
141
|
+
setupState: SetupState;
|
|
142
|
+
};
|
|
133
143
|
type SetupState = Record<string, any>;
|
|
134
144
|
/**
|
|
135
145
|
* `renderSuspended` allows you to mount any vue component within the Nuxt environment, allowing async setup and access to injections from your Nuxt plugins.
|
|
@@ -161,9 +171,7 @@ type SetupState = Record<string, any>;
|
|
|
161
171
|
* @param component the component to be tested
|
|
162
172
|
* @param options optional options to set up your component
|
|
163
173
|
*/
|
|
164
|
-
declare function renderSuspended<T>(component: T, options?:
|
|
165
|
-
setupState: SetupState;
|
|
166
|
-
}>;
|
|
174
|
+
declare function renderSuspended<T>(component: T, options?: RenderSuspendeOptions<T>): Promise<RenderSuspendeResult>;
|
|
167
175
|
declare global {
|
|
168
176
|
interface Window {
|
|
169
177
|
__cleanup?: Array<() => void>;
|
|
@@ -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, getCurrentInstance, effectScope, defineComponent as defineComponent$1 } 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';
|
|
@@ -43,7 +43,7 @@ function registerEndpoint(url, options) {
|
|
|
43
43
|
}
|
|
44
44
|
};
|
|
45
45
|
}
|
|
46
|
-
function mockNuxtImport(
|
|
46
|
+
function mockNuxtImport(_target, _factory) {
|
|
47
47
|
throw new Error(
|
|
48
48
|
"mockNuxtImport() is a macro and it did not get transpiled. This may be an internal bug of @nuxt/test-utils."
|
|
49
49
|
);
|
|
@@ -100,32 +100,27 @@ async function mountSuspended(component, options) {
|
|
|
100
100
|
cleanupFunction();
|
|
101
101
|
}
|
|
102
102
|
const vueApp = tryUseNuxtApp()?.vueApp || globalThis.__unctx__.get("nuxt-app").tryUse().vueApp;
|
|
103
|
-
const { render, setup,
|
|
103
|
+
const { render, setup, ...componentRest } = component;
|
|
104
|
+
let wrappedInstance = null;
|
|
104
105
|
let setupContext;
|
|
105
106
|
let setupState;
|
|
106
107
|
const setProps = reactive({});
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
if (
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
});
|
|
108
|
+
function patchInstanceAppContext() {
|
|
109
|
+
const app = getCurrentInstance()?.appContext.app;
|
|
110
|
+
if (!app) return;
|
|
111
|
+
for (const [key, value] of Object.entries(vueApp)) {
|
|
112
|
+
if (key in app) continue;
|
|
113
|
+
app[key] = value;
|
|
114
114
|
}
|
|
115
|
-
return interceptedEmit;
|
|
116
115
|
}
|
|
117
|
-
|
|
116
|
+
let componentScope = null;
|
|
117
|
+
const wrappedSetup = async (props2, setupContext2, instanceContext) => {
|
|
118
118
|
const currentInstance = getCurrentInstance();
|
|
119
|
-
if (
|
|
120
|
-
|
|
119
|
+
if (currentInstance) {
|
|
120
|
+
currentInstance.emit = (event, ...args) => {
|
|
121
|
+
setupContext2.emit(event, ...args);
|
|
122
|
+
};
|
|
121
123
|
}
|
|
122
|
-
currentInstance.emit = getInterceptedEmitFunction(currentInstance.emit);
|
|
123
|
-
}
|
|
124
|
-
let passedProps;
|
|
125
|
-
let componentScope = null;
|
|
126
|
-
const wrappedSetup = async (props2, setupContext2) => {
|
|
127
|
-
interceptEmitOnCurrentInstance();
|
|
128
|
-
passedProps = props2;
|
|
129
124
|
if (setup) {
|
|
130
125
|
let result;
|
|
131
126
|
if (options?.scoped) {
|
|
@@ -140,6 +135,9 @@ async function mountSuspended(component, options) {
|
|
|
140
135
|
} else {
|
|
141
136
|
result = await setup(props2, setupContext2);
|
|
142
137
|
}
|
|
138
|
+
if (wrappedInstance?.exposed) {
|
|
139
|
+
instanceContext.expose(wrappedInstance.exposed);
|
|
140
|
+
}
|
|
143
141
|
setupState = result && typeof result === "object" ? result : {};
|
|
144
142
|
return result;
|
|
145
143
|
}
|
|
@@ -149,7 +147,10 @@ async function mountSuspended(component, options) {
|
|
|
149
147
|
const vm = mount(
|
|
150
148
|
{
|
|
151
149
|
__cssModules: componentRest.__cssModules,
|
|
150
|
+
inheritAttrs: false,
|
|
152
151
|
setup: (props2, ctx) => {
|
|
152
|
+
patchInstanceAppContext();
|
|
153
|
+
wrappedInstance = getCurrentInstance();
|
|
153
154
|
setupContext = ctx;
|
|
154
155
|
if (options?.scoped) {
|
|
155
156
|
const scope = effectScope();
|
|
@@ -170,7 +171,7 @@ async function mountSuspended(component, options) {
|
|
|
170
171
|
});
|
|
171
172
|
}
|
|
172
173
|
},
|
|
173
|
-
render: (
|
|
174
|
+
render: () => h$1(
|
|
174
175
|
Suspense,
|
|
175
176
|
{
|
|
176
177
|
onResolve: () => nextTick().then(() => {
|
|
@@ -188,56 +189,12 @@ async function mountSuspended(component, options) {
|
|
|
188
189
|
const router = useRouter();
|
|
189
190
|
await router.replace(route);
|
|
190
191
|
const clonedComponent = {
|
|
191
|
-
|
|
192
|
+
components: {},
|
|
192
193
|
...component,
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
if (data && typeof data === "function") {
|
|
196
|
-
const dataObject = data();
|
|
197
|
-
for (const key in dataObject) {
|
|
198
|
-
renderContext[key] = dataObject[key];
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
for (const key in setupState || {}) {
|
|
202
|
-
const warn = console.warn;
|
|
203
|
-
console.warn = () => {
|
|
204
|
-
};
|
|
205
|
-
try {
|
|
206
|
-
renderContext[key] = isReadonly(setupState[key]) ? unref(setupState[key]) : setupState[key];
|
|
207
|
-
} catch {
|
|
208
|
-
} finally {
|
|
209
|
-
console.warn = warn;
|
|
210
|
-
}
|
|
211
|
-
if (key === "props") {
|
|
212
|
-
renderContext[key] = cloneProps$1(renderContext[key]);
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
const propsContext = "props" in renderContext ? renderContext.props : renderContext;
|
|
216
|
-
for (const key in props || {}) {
|
|
217
|
-
propsContext[key] = _ctx[key];
|
|
218
|
-
}
|
|
219
|
-
for (const key in passedProps || {}) {
|
|
220
|
-
propsContext[key] = passedProps[key];
|
|
221
|
-
}
|
|
222
|
-
if (methods && typeof methods === "object") {
|
|
223
|
-
for (const [key, value] of Object.entries(methods)) {
|
|
224
|
-
renderContext[key] = value.bind(renderContext);
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
if (computed && typeof computed === "object") {
|
|
228
|
-
for (const [key, value] of Object.entries(computed)) {
|
|
229
|
-
if ("get" in value) {
|
|
230
|
-
renderContext[key] = value.get.call(renderContext);
|
|
231
|
-
} else {
|
|
232
|
-
renderContext[key] = value.call(renderContext);
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
return render.call(this, renderContext, ...args);
|
|
237
|
-
} : void 0,
|
|
238
|
-
setup: (props2) => wrappedSetup(props2, setupContext)
|
|
194
|
+
name: "MountSuspendedComponent",
|
|
195
|
+
setup: (props2, ctx) => wrappedSetup(props2, setupContext, ctx)
|
|
239
196
|
};
|
|
240
|
-
return () => h$1(clonedComponent, { ...props, ...setProps, ...attrs }, slots);
|
|
197
|
+
return () => h$1(clonedComponent, { ...props, ...setProps, ...attrs }, setupContext.slots);
|
|
241
198
|
}
|
|
242
199
|
})
|
|
243
200
|
}
|
|
@@ -246,11 +203,18 @@ async function mountSuspended(component, options) {
|
|
|
246
203
|
defu(
|
|
247
204
|
_options,
|
|
248
205
|
{
|
|
206
|
+
props,
|
|
249
207
|
slots,
|
|
250
208
|
attrs,
|
|
251
209
|
global: {
|
|
252
210
|
config: {
|
|
253
|
-
globalProperties:
|
|
211
|
+
globalProperties: {
|
|
212
|
+
...vueApp.config.globalProperties,
|
|
213
|
+
// make all properties/keys enumerable.
|
|
214
|
+
...Object.fromEntries(
|
|
215
|
+
Object.getOwnPropertyNames(vueApp.config.globalProperties).map((key) => [key, vueApp.config.globalProperties[key]])
|
|
216
|
+
)
|
|
217
|
+
}
|
|
254
218
|
},
|
|
255
219
|
directives: vueApp._context.directives,
|
|
256
220
|
provide: vueApp._context.provides,
|
|
@@ -267,58 +231,46 @@ async function mountSuspended(component, options) {
|
|
|
267
231
|
}
|
|
268
232
|
);
|
|
269
233
|
}
|
|
270
|
-
function cloneProps$1(props) {
|
|
271
|
-
const newProps = reactive({});
|
|
272
|
-
for (const key in props) {
|
|
273
|
-
newProps[key] = props[key];
|
|
274
|
-
}
|
|
275
|
-
return newProps;
|
|
276
|
-
}
|
|
277
234
|
function wrappedMountedWrapper(wrapper) {
|
|
278
|
-
const
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
235
|
+
const component = wrapper.findComponent({ name: "MountSuspendedComponent" });
|
|
236
|
+
const wrapperProps = [
|
|
237
|
+
"setProps",
|
|
238
|
+
"emitted",
|
|
239
|
+
"setupState",
|
|
240
|
+
"unmount"
|
|
241
|
+
];
|
|
242
|
+
return new Proxy(wrapper, {
|
|
243
|
+
get: (_, prop, receiver) => {
|
|
244
|
+
if (prop === "getCurrentComponent") return getCurrentComponentPatchedProxy;
|
|
245
|
+
const target = wrapperProps.includes(prop) ? wrapper : Reflect.has(component, prop) ? component : wrapper;
|
|
246
|
+
const value = Reflect.get(target, prop, receiver);
|
|
247
|
+
return typeof value === "function" ? value.bind(target) : value;
|
|
289
248
|
}
|
|
290
249
|
});
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
250
|
+
function getCurrentComponentPatchedProxy() {
|
|
251
|
+
const currentComponent = component.getCurrentComponent();
|
|
252
|
+
return new Proxy(currentComponent, {
|
|
253
|
+
get: (target, prop, receiver) => {
|
|
254
|
+
const value = Reflect.get(target, prop, receiver);
|
|
255
|
+
if (prop === "proxy" && value) {
|
|
256
|
+
return new Proxy(value, {
|
|
257
|
+
get(o, p, r) {
|
|
258
|
+
if (!Reflect.has(currentComponent.props, p)) {
|
|
259
|
+
const setupState = wrapper.setupState;
|
|
260
|
+
if (setupState && typeof setupState === "object") {
|
|
261
|
+
if (Reflect.has(setupState, p)) {
|
|
262
|
+
return Reflect.get(setupState, p, r);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
return Reflect.get(o, p, r);
|
|
267
|
+
}
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
return value;
|
|
296
271
|
}
|
|
297
272
|
});
|
|
298
273
|
}
|
|
299
|
-
return proxy;
|
|
300
|
-
}
|
|
301
|
-
function createVMProxy(vm, setupState) {
|
|
302
|
-
return new Proxy(vm, {
|
|
303
|
-
get(target, key, receiver) {
|
|
304
|
-
const value = Reflect.get(target, key, receiver);
|
|
305
|
-
if (setupState && typeof setupState === "object" && key in setupState) {
|
|
306
|
-
return unref(setupState[key]);
|
|
307
|
-
}
|
|
308
|
-
return value;
|
|
309
|
-
},
|
|
310
|
-
set(target, key, value, receiver) {
|
|
311
|
-
if (setupState && typeof setupState === "object" && key in setupState) {
|
|
312
|
-
const setupValue = setupState[key];
|
|
313
|
-
if (setupValue && isRef(setupValue)) {
|
|
314
|
-
setupValue.value = value;
|
|
315
|
-
return true;
|
|
316
|
-
}
|
|
317
|
-
return Reflect.set(setupState, key, value, receiver);
|
|
318
|
-
}
|
|
319
|
-
return Reflect.set(target, key, value, receiver);
|
|
320
|
-
}
|
|
321
|
-
});
|
|
322
274
|
}
|
|
323
275
|
|
|
324
276
|
const WRAPPER_EL_ID = "test-wrapper";
|
|
@@ -332,38 +284,36 @@ async function renderSuspended(component, options) {
|
|
|
332
284
|
} = options || {};
|
|
333
285
|
const { render: renderFromTestingLibrary } = await import('@testing-library/vue');
|
|
334
286
|
const vueApp = tryUseNuxtApp()?.vueApp || globalThis.__unctx__.get("nuxt-app").tryUse().vueApp;
|
|
335
|
-
const { render, setup,
|
|
287
|
+
const { render, setup, ...componentRest } = component;
|
|
288
|
+
let wrappedInstance = null;
|
|
336
289
|
let setupContext;
|
|
337
290
|
let setupState;
|
|
338
291
|
const setProps = reactive({});
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
if (
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
});
|
|
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;
|
|
346
298
|
}
|
|
347
|
-
return interceptedEmit;
|
|
348
|
-
}
|
|
349
|
-
function interceptEmitOnCurrentInstance() {
|
|
350
|
-
const currentInstance = getCurrentInstance();
|
|
351
|
-
if (!currentInstance) {
|
|
352
|
-
return;
|
|
353
|
-
}
|
|
354
|
-
currentInstance.emit = getInterceptedEmitFunction(currentInstance.emit);
|
|
355
299
|
}
|
|
356
300
|
for (const fn of window.__cleanup || []) {
|
|
357
301
|
fn();
|
|
358
302
|
}
|
|
359
303
|
document.querySelector(`#${WRAPPER_EL_ID}`)?.remove();
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
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
|
+
}
|
|
364
311
|
if (setup) {
|
|
365
312
|
const result = await setup(props2, setupContext2);
|
|
366
313
|
setupState = result && typeof result === "object" ? result : {};
|
|
314
|
+
if (wrappedInstance?.exposed) {
|
|
315
|
+
instanceContext.expose(wrappedInstance.exposed);
|
|
316
|
+
}
|
|
367
317
|
return result;
|
|
368
318
|
}
|
|
369
319
|
};
|
|
@@ -377,7 +327,10 @@ async function renderSuspended(component, options) {
|
|
|
377
327
|
const utils = renderFromTestingLibrary(
|
|
378
328
|
{
|
|
379
329
|
__cssModules: componentRest.__cssModules,
|
|
330
|
+
inheritAttrs: false,
|
|
380
331
|
setup: (props2, ctx) => {
|
|
332
|
+
patchInstanceAppContext();
|
|
333
|
+
wrappedInstance = getCurrentInstance();
|
|
381
334
|
setupContext = ctx;
|
|
382
335
|
const scope = effectScope();
|
|
383
336
|
window.__cleanup ||= [];
|
|
@@ -389,7 +342,7 @@ async function renderSuspended(component, options) {
|
|
|
389
342
|
expose: () => ({})
|
|
390
343
|
}));
|
|
391
344
|
},
|
|
392
|
-
render: (
|
|
345
|
+
render: () => (
|
|
393
346
|
// See discussions in https://github.com/testing-library/vue-testing-library/issues/230
|
|
394
347
|
// we add this additional root element because otherwise testing-library breaks
|
|
395
348
|
// because there's no root element while Suspense is resolving
|
|
@@ -416,56 +369,13 @@ async function renderSuspended(component, options) {
|
|
|
416
369
|
const router = useRouter();
|
|
417
370
|
await router.replace(route);
|
|
418
371
|
const clonedComponent = {
|
|
419
|
-
|
|
372
|
+
components: {},
|
|
420
373
|
...component,
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
const dataObject = data();
|
|
425
|
-
for (const key in dataObject) {
|
|
426
|
-
renderContext[key] = dataObject[key];
|
|
427
|
-
}
|
|
428
|
-
}
|
|
429
|
-
for (const key in setupState || {}) {
|
|
430
|
-
const warn = console.warn;
|
|
431
|
-
console.warn = () => {
|
|
432
|
-
};
|
|
433
|
-
try {
|
|
434
|
-
renderContext[key] = isReadonly(setupState[key]) ? unref(setupState[key]) : setupState[key];
|
|
435
|
-
} catch {
|
|
436
|
-
} finally {
|
|
437
|
-
console.warn = warn;
|
|
438
|
-
}
|
|
439
|
-
if (key === "props") {
|
|
440
|
-
renderContext[key] = cloneProps(renderContext[key]);
|
|
441
|
-
}
|
|
442
|
-
}
|
|
443
|
-
const propsContext = "props" in renderContext ? renderContext.props : renderContext;
|
|
444
|
-
for (const key in props || {}) {
|
|
445
|
-
propsContext[key] = _ctx[key];
|
|
446
|
-
}
|
|
447
|
-
for (const key in passedProps || {}) {
|
|
448
|
-
propsContext[key] = passedProps[key];
|
|
449
|
-
}
|
|
450
|
-
if (methods && typeof methods === "object") {
|
|
451
|
-
for (const [key, value] of Object.entries(methods)) {
|
|
452
|
-
renderContext[key] = value.bind(renderContext);
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
if (computed && typeof computed === "object") {
|
|
456
|
-
for (const [key, value] of Object.entries(computed)) {
|
|
457
|
-
if ("get" in value) {
|
|
458
|
-
renderContext[key] = value.get.call(renderContext);
|
|
459
|
-
} else {
|
|
460
|
-
renderContext[key] = value.call(renderContext);
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
|
-
}
|
|
464
|
-
return render.call(this, renderContext, ...args);
|
|
465
|
-
} : void 0,
|
|
466
|
-
setup: (props2) => wrappedSetup(props2, setupContext)
|
|
374
|
+
name: "RenderSuspendedComponent",
|
|
375
|
+
render,
|
|
376
|
+
setup: (props2, ctx) => wrappedSetup(props2, setupContext, ctx)
|
|
467
377
|
};
|
|
468
|
-
return () => h$1(clonedComponent, { ...props && typeof props === "object" ? props : {}, ...setProps, ...attrs }, slots);
|
|
378
|
+
return () => h$1(clonedComponent, { ...props && typeof props === "object" ? props : {}, ...setProps, ...attrs }, setupContext.slots);
|
|
469
379
|
}
|
|
470
380
|
})
|
|
471
381
|
}
|
|
@@ -475,11 +385,18 @@ async function renderSuspended(component, options) {
|
|
|
475
385
|
)
|
|
476
386
|
},
|
|
477
387
|
defu(_options, {
|
|
388
|
+
props,
|
|
478
389
|
slots,
|
|
479
390
|
attrs,
|
|
480
391
|
global: {
|
|
481
392
|
config: {
|
|
482
|
-
globalProperties:
|
|
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
|
+
}
|
|
483
400
|
},
|
|
484
401
|
directives: vueApp._context.directives,
|
|
485
402
|
provide: vueApp._context.provides,
|
|
@@ -489,12 +406,5 @@ async function renderSuspended(component, options) {
|
|
|
489
406
|
);
|
|
490
407
|
});
|
|
491
408
|
}
|
|
492
|
-
function cloneProps(props) {
|
|
493
|
-
const newProps = reactive({});
|
|
494
|
-
for (const key in props) {
|
|
495
|
-
newProps[key] = props[key];
|
|
496
|
-
}
|
|
497
|
-
return newProps;
|
|
498
|
-
}
|
|
499
409
|
|
|
500
410
|
export { mockComponent, mockNuxtImport, mountSuspended, registerEndpoint, renderSuspended };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nuxt/test-utils-nightly",
|
|
3
|
-
"version": "3.21.0-
|
|
3
|
+
"version": "3.21.0-20251204-130449-b6179fd",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/nuxt/test-utils.git"
|
|
@@ -73,34 +73,34 @@
|
|
|
73
73
|
"defu": "^6.1.4",
|
|
74
74
|
"destr": "^2.0.5",
|
|
75
75
|
"estree-walker": "^3.0.3",
|
|
76
|
-
"fake-indexeddb": "^6.2.
|
|
76
|
+
"fake-indexeddb": "^6.2.5",
|
|
77
77
|
"get-port-please": "^3.2.0",
|
|
78
78
|
"h3": "^1.15.4",
|
|
79
79
|
"local-pkg": "^1.1.2",
|
|
80
80
|
"magic-string": "^0.30.21",
|
|
81
81
|
"node-fetch-native": "^1.6.7",
|
|
82
82
|
"node-mock-http": "^1.0.3",
|
|
83
|
-
"ofetch": "^1.
|
|
83
|
+
"ofetch": "^1.5.1",
|
|
84
84
|
"pathe": "^2.0.3",
|
|
85
85
|
"perfect-debounce": "^2.0.0",
|
|
86
86
|
"radix3": "^1.1.2",
|
|
87
87
|
"scule": "^1.3.0",
|
|
88
88
|
"std-env": "^3.10.0",
|
|
89
|
-
"tinyexec": "^1.0.
|
|
89
|
+
"tinyexec": "^1.0.2",
|
|
90
90
|
"ufo": "^1.6.1",
|
|
91
91
|
"unplugin": "^2.3.10",
|
|
92
92
|
"vitest-environment-nuxt": "^1.0.1",
|
|
93
|
-
"vue": "^3.5.
|
|
93
|
+
"vue": "^3.5.24"
|
|
94
94
|
},
|
|
95
95
|
"devDependencies": {
|
|
96
96
|
"@cucumber/cucumber": "12.2.0",
|
|
97
97
|
"@jest/globals": "30.2.0",
|
|
98
98
|
"@nuxt/devtools-kit": "2.7.0",
|
|
99
|
-
"@nuxt/eslint-config": "1.
|
|
99
|
+
"@nuxt/eslint-config": "1.10.0",
|
|
100
100
|
"@nuxt/schema": "4.1.3",
|
|
101
101
|
"@playwright/test": "1.56.1",
|
|
102
102
|
"@testing-library/vue": "8.1.0",
|
|
103
|
-
"@types/bun": "1.3.
|
|
103
|
+
"@types/bun": "1.3.2",
|
|
104
104
|
"@types/estree": "1.0.8",
|
|
105
105
|
"@types/jsdom": "27.0.0",
|
|
106
106
|
"@types/node": "latest",
|
|
@@ -108,22 +108,22 @@
|
|
|
108
108
|
"@vue/test-utils": "2.4.6",
|
|
109
109
|
"changelogen": "0.6.2",
|
|
110
110
|
"compatx": "0.2.0",
|
|
111
|
-
"eslint": "9.
|
|
111
|
+
"eslint": "9.39.1",
|
|
112
112
|
"installed-check": "9.3.0",
|
|
113
|
-
"knip": "5.
|
|
114
|
-
"nitropack": "2.12.
|
|
113
|
+
"knip": "5.68.0",
|
|
114
|
+
"nitropack": "2.12.9",
|
|
115
115
|
"nuxt": "4.1.3",
|
|
116
116
|
"pkg-pr-new": "0.0.60",
|
|
117
117
|
"playwright-core": "1.56.1",
|
|
118
|
-
"rollup": "4.
|
|
118
|
+
"rollup": "4.53.2",
|
|
119
119
|
"semver": "7.7.3",
|
|
120
120
|
"typescript": "5.9.3",
|
|
121
121
|
"unbuild": "latest",
|
|
122
122
|
"unimport": "5.5.0",
|
|
123
|
-
"vite": "7.
|
|
123
|
+
"vite": "7.2.2",
|
|
124
124
|
"vitest": "3.2.4",
|
|
125
125
|
"vue-router": "4.6.3",
|
|
126
|
-
"vue-tsc": "3.1.
|
|
126
|
+
"vue-tsc": "3.1.3"
|
|
127
127
|
},
|
|
128
128
|
"peerDependencies": {
|
|
129
129
|
"@cucumber/cucumber": "^10.3.1 || >=11.0.0",
|
|
@@ -174,14 +174,14 @@
|
|
|
174
174
|
"@nuxt/schema": "4.1.3",
|
|
175
175
|
"@nuxt/test-utils": "workspace:*",
|
|
176
176
|
"@types/node": "22.18.8",
|
|
177
|
-
"rollup": "4.
|
|
178
|
-
"vite": "7.
|
|
177
|
+
"rollup": "4.53.2",
|
|
178
|
+
"vite": "7.2.2",
|
|
179
179
|
"vite-node": "3.2.4",
|
|
180
180
|
"vitest": "3.2.4",
|
|
181
|
-
"vue": "^3.5.
|
|
181
|
+
"vue": "^3.5.24"
|
|
182
182
|
},
|
|
183
183
|
"engines": {
|
|
184
184
|
"node": "^20.0.0 || ^22.0.0 || >=24.0.0"
|
|
185
185
|
},
|
|
186
|
-
"packageManager": "pnpm@10.
|
|
186
|
+
"packageManager": "pnpm@10.21.0"
|
|
187
187
|
}
|