Skip to content
This repository has been archived by the owner on Dec 19, 2023. It is now read-only.

Commit

Permalink
fix(utils): proxy context to capture emitted events in wrapper
Browse files Browse the repository at this point in the history
resolves #175
  • Loading branch information
danielroe committed May 30, 2023
1 parent f217a94 commit 8bf8037
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 4 deletions.
26 changes: 22 additions & 4 deletions packages/vitest-environment-nuxt/src/runtime/mount.ts
Original file line number Diff line number Diff line change
@@ -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'

Expand All @@ -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<VueWrapper<InstanceType<T>>>(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)) },
Expand All @@ -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<string, any>, ctx: Record<string, any>) => setup(props, setupContext) : undefined
}

return () => h(clonedComponent, { ...props, ...attrs }, slots)
},
}),
}
),
},
defu(_options, {
slots,
global: {
config: {
globalProperties: vueApp.config.globalProperties,
Expand Down
20 changes: 20 additions & 0 deletions playground/components/WrapperTests.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<script setup lang="ts">
const emit = defineEmits<{
customEvent: [id: string]
otherEvent: []
}>()
function testExpose () {
return 'expose was successful'
}
defineExpose({
testExpose
})
</script>

<template>
<div>
<button @click="emit('customEvent', 'foo'); $emit('otherEvent')">Click me!</button>
</div>
</template>
18 changes: 18 additions & 0 deletions playground/tests/nuxt/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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', () => {
Expand Down Expand Up @@ -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',
Expand Down

0 comments on commit 8bf8037

Please sign in to comment.