Skip to content

Commit

Permalink
fix(runtime): improve types for renderSuspended and mountSuspended
Browse files Browse the repository at this point in the history
  • Loading branch information
danielroe committed Apr 17, 2024
1 parent 21aa7a2 commit 1636ced
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 21 deletions.
38 changes: 22 additions & 16 deletions src/runtime-utils/mount.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export type MountSuspendedOptions<T> = ComponentMountingOptions<T> & {
export async function mountSuspended<T>(
component: T,
options?: MountSuspendedOptions<T>,
): Promise<ReturnType<typeof mount<T>> & { setupState: any }> {
): Promise<ReturnType<typeof mount<T>> & { setupState: Record<string, unknown> }> {
const {
props = {},
attrs = {},
Expand All @@ -55,46 +55,47 @@ export async function mountSuspended<T>(

// @ts-expect-error untyped global __unctx__
const vueApp = globalThis.__unctx__.get('nuxt-app').tryUse().vueApp
const { render, setup } = component as DefineComponent<any, any>
const { render, setup } = component as DefineComponent<Record<string, unknown>, Record <string, unknown>>

let setupContext: SetupContext
let setupState: any
const setProps = reactive<Record<string, any>>({})
let setupState: Record<string, unknown>
const setProps = reactive<Record<string, unknown>>({})

let passedProps: Record<string, any>
let passedProps: Record<string, unknown>
const wrappedSetup = async (
props: Record<string, any>,
props: Record<string, unknown>,
setupContext: SetupContext,
) => {
passedProps = props
if (setup) {
setupState = await setup(props, setupContext)
const result = await setup(props, setupContext)
setupState = result && typeof result === 'object' ? result : {}
return setupState
}
}

return new Promise<ReturnType<typeof mount<T>> & { setupState: any }>(
return new Promise<ReturnType<typeof mount<T>> & { setupState: Record<string, unknown> }>(
(resolve) => {
const vm = mount(
{
setup: (props: Record<string, any>, ctx: SetupContext) => {
setup: (props: Record<string, unknown>, ctx: SetupContext) => {
setupContext = ctx
return NuxtRoot.setup(props, {
...ctx,
expose: () => {},
})
},
render: (renderContext: any) =>
render: (renderContext: Record<string, unknown>) =>
h(
Suspense,
{
onResolve: () =>
nextTick().then(() => {
(vm as any).setupState = setupState;
(vm as any).__setProps = (props: Record<string, any>) => {
(vm as unknown as AugmentedVueInstance).setupState = setupState;
(vm as unknown as AugmentedVueInstance).__setProps = (props: Record<string, unknown>) => {
Object.assign(setProps, props)
}
resolve(vm as any)
resolve(vm as ReturnType<typeof mount<T>> & { setupState: Record<string, unknown> })
}),
},
{
Expand All @@ -110,7 +111,7 @@ export async function mountSuspended<T>(
name: 'MountSuspendedComponent',
...component,
render: render
? function (this: any, _ctx: any, ...args: any[]) {
? function (this: unknown, _ctx: Record<string, unknown>, ...args: unknown[]) {
for (const key in setupState || {}) {
renderContext[key] = isReadonly(setupState[key]) ? unref(setupState[key]) : setupState[key]
}
Expand All @@ -123,7 +124,7 @@ export async function mountSuspended<T>(
return render.call(this, renderContext, ...args)
}
: undefined,
setup: setup ? (props: Record<string, any>) => wrappedSetup(props, setupContext) : undefined,
setup: setup ? (props: Record<string, unknown>) => wrappedSetup(props, setupContext) : undefined,
}

return () => h(clonedComponent, { ...defu(setProps, props) as typeof props, ...attrs }, slots)
Expand All @@ -144,7 +145,7 @@ export async function mountSuspended<T>(
stubs: {
Suspense: false,
MountSuspendedHelper: false,
[typeof (component as any).name === 'string' ? (component as any).name : 'MountSuspendedComponent']: false,
[component && typeof component === 'object' && 'name' in component && typeof component.name === 'string' ? component.name : 'MountSuspendedComponent']: false,
},
components: { RouterLink },
},
Expand All @@ -154,3 +155,8 @@ export async function mountSuspended<T>(
},
)
}

interface AugmentedVueInstance {
setupState?: Record<string, unknown>
__setProps?: (props: Record<string, unknown>) => void
}
10 changes: 5 additions & 5 deletions src/runtime-utils/render.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ export async function renderSuspended<T>(

// @ts-expect-error untyped global __unctx__
const { vueApp } = globalThis.__unctx__.get('nuxt-app').tryUse()
const { render, setup } = component as DefineComponent<any, any>
const { render, setup } = component as DefineComponent<Record<string, unknown>, Record <string, unknown>>

// cleanup previously mounted test wrappers
document.querySelector(`#${WRAPPER_EL_ID}`)?.remove()
Expand All @@ -80,15 +80,15 @@ export async function renderSuspended<T>(
const utils = renderFromTestingLibrary(
{

setup: (props: any, ctx: any) => {
setup: (props: Record<string, unknown>, ctx: SetupContext) => {
setupContext = ctx

return NuxtRoot.setup(props, {
...ctx,
expose: () => {},
})
},
render: (renderContext: any) =>
render: (renderContext: unknown) =>
// See discussions in https://github.com/testing-library/vue-testing-library/issues/230
// we add this additional root element because otherwise testing-library breaks
// because there's no root element while Suspense is resolving
Expand All @@ -109,11 +109,11 @@ export async function renderSuspended<T>(
const clonedComponent = {
...component,
render: render
? (_ctx: any, ...args: any[]) =>
? (_ctx: unknown, ...args: unknown[]) =>
render(renderContext, ...args)
: undefined,
setup: setup
? (props: Record<string, any>) =>
? (props: Record<string, unknown>) =>
setup(props, setupContext)
: undefined,
}
Expand Down

0 comments on commit 1636ced

Please sign in to comment.