diff --git a/packages/vitest-environment-nuxt/src/runtime/mount.ts b/packages/vitest-environment-nuxt/src/runtime/mount.ts index 40142e7b..0ff68fa1 100644 --- a/packages/vitest-environment-nuxt/src/runtime/mount.ts +++ b/packages/vitest-environment-nuxt/src/runtime/mount.ts @@ -1,5 +1,5 @@ import { mount, VueWrapper, MountingOptions } from '@vue/test-utils' -import { h, DefineComponent, Suspense, nextTick } from 'vue' +import { h, DefineComponent, Suspense, nextTick, SetupContext } from 'vue' import { defu } from 'defu' import type { RouteLocationRaw } from 'vue-router' @@ -26,11 +26,20 @@ export async function mountSuspended< // @ts-expect-error untyped global __unctx__ const vueApp = globalThis.__unctx__.get('nuxt-app').tryUse().vueApp + const { render, setup } = component + + let setupContext: SetupContext return new Promise>>(resolve => { const vm = mount( { - setup: NuxtRoot.setup, - render: () => + setup: (props, ctx) => { + setupContext = ctx + return NuxtRoot.setup(props, { + ...ctx, + expose: () => {}, + }) + }, + render: (renderContext: any) => h( Suspense, { onResolve: () => nextTick().then(() => resolve(vm as any)) }, @@ -40,13 +49,22 @@ export async function mountSuspended< async setup() { const router = useRouter() await router.replace(route) - return () => h(component, { ...props, ...attrs }, slots) + + // Proxy top-level setup/render context so test wrapper resolves child component + const clonedComponent = { + ...component, + render: render ? (_ctx: any, ...args: any[]) => render(renderContext, ...args) : undefined, + setup: setup ? (props: Record, ctx: Record) => setup(props, setupContext) : undefined + } + + return () => h(clonedComponent, { ...props, ...attrs }, slots) }, }), } ), }, defu(_options, { + slots, global: { config: { globalProperties: vueApp.config.globalProperties, diff --git a/playground/components/WrapperTests.vue b/playground/components/WrapperTests.vue new file mode 100644 index 00000000..1dc856ad --- /dev/null +++ b/playground/components/WrapperTests.vue @@ -0,0 +1,20 @@ + + + diff --git a/playground/tests/nuxt/index.spec.ts b/playground/tests/nuxt/index.spec.ts index b2d62451..03b2d78e 100644 --- a/playground/tests/nuxt/index.spec.ts +++ b/playground/tests/nuxt/index.spec.ts @@ -5,6 +5,7 @@ import { mountSuspended, registerEndpoint } from 'vitest-environment-nuxt/utils' import App from '~/app.vue' import FetchComponent from '~/components/FetchComponent.vue' import OptionsComponent from '~/components/OptionsComponent.vue' +import { WrapperTests } from '#components' describe('client-side nuxt features', () => { it('can use core nuxt composables within test file', () => { @@ -80,6 +81,23 @@ describe('test utils', () => { ) }) + it('can receive emitted events from components mounted within nuxt suspense', async () => { + const component = await mountSuspended(WrapperTests) + component.find('button').trigger('click') + expect(component.emitted()).toMatchInlineSnapshot(` + { + "customEvent": [ + [ + "foo", + ], + ], + "otherEvent": [ + [], + ], + } + `) + }) + it('can mock fetch requests', async () => { registerEndpoint('https://jsonplaceholder.typicode.com/todos/1', () => ({ title: 'title from mocked api',