From 3ecde9e25adb2e3f2da309e1d4fa00a89ba8f1b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=83=9D=E6=99=A8=E5=85=89?= <2293885211@qq.com> Date: Mon, 18 Mar 2024 15:45:49 +0800 Subject: [PATCH 1/2] fix: allow unmounting with no wrapper element (#312) * fix: check wrapper element to fix #311 --- src/__tests__/render.js | 15 ++++++++++++++- src/render.js | 5 +---- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/__tests__/render.js b/src/__tests__/render.js index 151bd8bc..ea55817f 100644 --- a/src/__tests__/render.js +++ b/src/__tests__/render.js @@ -1,4 +1,5 @@ -import {render} from '..' +import {render, cleanup} from '..' +import {h, defineComponent} from 'vue' import '@testing-library/jest-dom' test('baseElement defaults to document.body', () => { @@ -87,3 +88,15 @@ test('unmounts', () => { expect(queryByTestId('node')).not.toBeInTheDocument() }) + +test('unmounts when no wrapper element is present', () => { + const Comp = defineComponent((_, ctx) => () => ctx.slots.default?.()) + + const {unmount} = render({ + render: () => h(Comp, () => h('div')), + }) + + unmount() + + expect(() => cleanup()).not.toThrow() +}) diff --git a/src/render.js b/src/render.js index 6f635cb2..997ba4c0 100644 --- a/src/render.js +++ b/src/render.js @@ -60,10 +60,7 @@ function cleanup() { } function cleanupAtWrapper(wrapper) { - if ( - wrapper.element.parentNode && - wrapper.element.parentNode.parentNode === document.body - ) { + if (wrapper.element?.parentNode?.parentNode === document.body) { document.body.removeChild(wrapper.element.parentNode) } From d46ed8f757e77fe85b369847c21d394bb9706066 Mon Sep 17 00:00:00 2001 From: Chris Heyer Date: Sat, 18 May 2024 10:14:03 +0200 Subject: [PATCH 2/2] feat: Add types for props and slots in render function * Add types for render function * Fix lint errors --- package.json | 2 ++ src/__tests__/render.js | 2 +- types/index.d.ts | 27 ++++++++++++++++++++++----- types/index.test-d.ts | 2 +- 4 files changed, 26 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index 3c2760a6..a3b7b084 100644 --- a/package.json +++ b/package.json @@ -68,9 +68,11 @@ "lodash.merge": "^4.6.2", "msw": "^1.3.2", "tsd": "^0.29.0", + "type-fest": "~2.19", "typescript": "^5.2.2", "vee-validate": "^4.11.8", "vue": "^3.3.5", + "vue-component-type-helpers": "^2.0.19", "vue-eslint-parser": "^9.3.2", "vue-i18n": "^9.5.0", "vue-router": "^4.2.5", diff --git a/src/__tests__/render.js b/src/__tests__/render.js index ea55817f..235210e3 100644 --- a/src/__tests__/render.js +++ b/src/__tests__/render.js @@ -1,6 +1,6 @@ -import {render, cleanup} from '..' import {h, defineComponent} from 'vue' import '@testing-library/jest-dom' +import {render, cleanup} from '..' test('baseElement defaults to document.body', () => { const {baseElement} = render({template: '
'}) diff --git a/types/index.d.ts b/types/index.d.ts index c6c157d7..d4edc3bf 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -1,10 +1,13 @@ // Minimum TypeScript Version: 4.0 /* eslint-disable @typescript-eslint/no-explicit-any */ +import {VNodeChild} from 'vue' import {MountingOptions} from '@vue/test-utils' import {queries, EventType, BoundFunctions} from '@testing-library/dom' // eslint-disable-next-line import/no-extraneous-dependencies import {OptionsReceived as PrettyFormatOptions} from 'pretty-format' +import {ComponentProps, ComponentSlots} from 'vue-component-type-helpers' +import {RemoveIndexSignature} from 'type-fest' // NOTE: fireEvent is overridden below export * from '@testing-library/dom' @@ -44,12 +47,26 @@ interface VueTestingLibraryRenderOptions { container?: Element baseElement?: Element } -export type RenderOptions = VueTestingLibraryRenderOptions & - VueTestUtilsRenderOptions -export function render( - TestComponent: any, // this makes me sad :sob: - options?: RenderOptions, +type AllowNonFunctionSlots = { + [K in keyof Slots]: Slots[K] | VNodeChild +} +type ExtractSlots = AllowNonFunctionSlots< + Partial>> +> + +export interface RenderOptions + extends Omit< + VueTestingLibraryRenderOptions & VueTestUtilsRenderOptions, + 'props' | 'slots' + > { + props?: ComponentProps + slots?: ExtractSlots +} + +export function render( + TestComponent: C, + options?: RenderOptions, ): RenderResult export type AsyncFireObject = { diff --git a/types/index.test-d.ts b/types/index.test-d.ts index 5a0253d7..02e9e187 100644 --- a/types/index.test-d.ts +++ b/types/index.test-d.ts @@ -68,7 +68,7 @@ export async function testWaitFor() { export function testOptions() { render(SomeComponent, { attrs: {a: 1}, - props: {c: 1}, // ideally it would fail because `c` is not an existing prop… + props: {foo: 1}, data: () => ({b: 2}), slots: { default: '
',