diff --git a/packages/@headlessui-vue/src/components/combobox/combobox.test.ts b/packages/@headlessui-vue/src/components/combobox/combobox.test.ts index ca10160e43..e2da3e3d93 100644 --- a/packages/@headlessui-vue/src/components/combobox/combobox.test.ts +++ b/packages/@headlessui-vue/src/components/combobox/combobox.test.ts @@ -9,7 +9,7 @@ import { computed, PropType, } from 'vue' -import { render } from '../../test-utils/vue-testing-library' +import { createRenderTemplate, render } from '../../test-utils/vue-testing-library' import { Combobox, ComboboxInput, @@ -89,21 +89,7 @@ function getDefaultComponents() { } } -function renderTemplate(input: string | Partial) { - let defaultComponents = getDefaultComponents() - - if (typeof input === 'string') { - return render(defineComponent({ template: input, components: defaultComponents })) - } - - return render( - defineComponent( - Object.assign({}, input, { - components: { ...defaultComponents, ...input.components }, - }) as Parameters[0] - ) - ) -} +const renderTemplate = createRenderTemplate(getDefaultComponents()) describe('safeguards', () => { it.each([ diff --git a/packages/@headlessui-vue/src/components/dialog/dialog.test.ts b/packages/@headlessui-vue/src/components/dialog/dialog.test.ts index 0ba781c473..d74188c9a8 100644 --- a/packages/@headlessui-vue/src/components/dialog/dialog.test.ts +++ b/packages/@headlessui-vue/src/components/dialog/dialog.test.ts @@ -7,7 +7,7 @@ import { ConcreteComponent, onMounted, } from 'vue' -import { render } from '../../test-utils/vue-testing-library' +import { createRenderTemplate, render } from '../../test-utils/vue-testing-library' import { Dialog, @@ -58,29 +58,15 @@ beforeAll(() => { afterAll(() => jest.restoreAllMocks()) -function renderTemplate(input: string | ComponentOptionsWithoutProps) { - let defaultComponents = { - Dialog, - DialogOverlay, - DialogBackdrop, - DialogPanel, - DialogTitle, - DialogDescription, - TabSentinel, - } - - if (typeof input === 'string') { - return render(defineComponent({ template: input, components: defaultComponents })) - } - - return render( - defineComponent( - Object.assign({}, input, { - components: { ...defaultComponents, ...input.components }, - }) as Parameters[0] - ) - ) -} +const renderTemplate = createRenderTemplate({ + Dialog, + DialogOverlay, + DialogBackdrop, + DialogPanel, + DialogTitle, + DialogDescription, + TabSentinel, +}) describe('Safe guards', () => { it.each([ diff --git a/packages/@headlessui-vue/src/components/disclosure/disclosure.test.ts b/packages/@headlessui-vue/src/components/disclosure/disclosure.test.ts index 36cb854405..b2420fab7b 100644 --- a/packages/@headlessui-vue/src/components/disclosure/disclosure.test.ts +++ b/packages/@headlessui-vue/src/components/disclosure/disclosure.test.ts @@ -1,5 +1,5 @@ import { defineComponent, nextTick, ref, watch, h, ComponentOptionsWithoutProps } from 'vue' -import { render } from '../../test-utils/vue-testing-library' +import { createRenderTemplate, render } from '../../test-utils/vue-testing-library' import { Disclosure, DisclosureButton, DisclosurePanel } from './disclosure' import { suppressConsoleLogs } from '../../test-utils/suppress-console-logs' import { @@ -19,21 +19,11 @@ jest.mock('../../hooks/use-id') afterAll(() => jest.restoreAllMocks()) -function renderTemplate(input: string | ComponentOptionsWithoutProps) { - let defaultComponents = { Disclosure, DisclosureButton, DisclosurePanel } - - if (typeof input === 'string') { - return render(defineComponent({ template: input, components: defaultComponents })) - } - - return render( - defineComponent( - Object.assign({}, input, { - components: { ...defaultComponents, ...input.components }, - }) as Parameters[0] - ) - ) -} +const renderTemplate = createRenderTemplate({ + Disclosure, + DisclosureButton, + DisclosurePanel, +}) describe('Safe guards', () => { it.each([ diff --git a/packages/@headlessui-vue/src/components/focus-trap/focus-trap.test.ts b/packages/@headlessui-vue/src/components/focus-trap/focus-trap.test.ts index 1b24930ce7..8f67694d0b 100644 --- a/packages/@headlessui-vue/src/components/focus-trap/focus-trap.test.ts +++ b/packages/@headlessui-vue/src/components/focus-trap/focus-trap.test.ts @@ -3,7 +3,7 @@ import { defineComponent, ref, nextTick, onMounted, ComponentOptionsWithoutProps import { FocusTrap } from './focus-trap' import { assertActiveElement, getByText } from '../../test-utils/accessibility-assertions' import { suppressConsoleLogs } from '../../test-utils/suppress-console-logs' -import { render } from '../../test-utils/vue-testing-library' +import { createRenderTemplate, render } from '../../test-utils/vue-testing-library' import { click, press, shift, Keys } from '../../test-utils/interactions' import { html } from '../../test-utils/html' @@ -16,21 +16,9 @@ beforeAll(() => { afterAll(() => jest.restoreAllMocks()) -function renderTemplate(input: string | ComponentOptionsWithoutProps) { - let defaultComponents = { FocusTrap } - - if (typeof input === 'string') { - return render(defineComponent({ template: input, components: defaultComponents })) - } - - return render( - defineComponent( - Object.assign({}, input, { - components: { ...defaultComponents, ...input.components }, - }) as Parameters[0] - ) - ) -} +const renderTemplate = createRenderTemplate({ + FocusTrap, +}) it('should focus the first focusable element inside the FocusTrap', async () => { renderTemplate( diff --git a/packages/@headlessui-vue/src/components/listbox/listbox.test.tsx b/packages/@headlessui-vue/src/components/listbox/listbox.test.tsx index 7fa2814158..4877b8aed7 100644 --- a/packages/@headlessui-vue/src/components/listbox/listbox.test.tsx +++ b/packages/@headlessui-vue/src/components/listbox/listbox.test.tsx @@ -7,7 +7,7 @@ import { reactive, ComponentOptionsWithoutProps, } from 'vue' -import { render } from '../../test-utils/vue-testing-library' +import { createRenderTemplate, render } from '../../test-utils/vue-testing-library' import { Listbox, ListboxLabel, ListboxButton, ListboxOptions, ListboxOption } from './listbox' import { suppressConsoleLogs } from '../../test-utils/suppress-console-logs' import { @@ -66,21 +66,13 @@ function nextFrame() { }) } -function renderTemplate(input: string | ComponentOptionsWithoutProps) { - let defaultComponents = { Listbox, ListboxLabel, ListboxButton, ListboxOptions, ListboxOption } - - if (typeof input === 'string') { - return render(defineComponent({ template: input, components: defaultComponents })) - } - - return render( - defineComponent( - Object.assign({}, input, { - components: { ...defaultComponents, ...input.components }, - }) as Parameters[0] - ) - ) -} +const renderTemplate = createRenderTemplate({ + Listbox, + ListboxLabel, + ListboxButton, + ListboxOptions, + ListboxOption, +}) describe('safeguards', () => { it.each([ diff --git a/packages/@headlessui-vue/src/components/menu/menu.test.tsx b/packages/@headlessui-vue/src/components/menu/menu.test.tsx index fbd6a915e4..4f0714060b 100644 --- a/packages/@headlessui-vue/src/components/menu/menu.test.tsx +++ b/packages/@headlessui-vue/src/components/menu/menu.test.tsx @@ -7,7 +7,7 @@ import { ref, watch, } from 'vue' -import { render } from '../../test-utils/vue-testing-library' +import { createRenderTemplate, render } from '../../test-utils/vue-testing-library' import { Menu, MenuButton, MenuItems, MenuItem } from './menu' import { TransitionChild } from '../transitions/transition' import { suppressConsoleLogs } from '../../test-utils/suppress-console-logs' @@ -61,21 +61,7 @@ function nextFrame() { }) } -function renderTemplate(input: string | ComponentOptionsWithoutProps) { - let defaultComponents = { Menu, MenuButton, MenuItems, MenuItem } - - if (typeof input === 'string') { - return render(defineComponent({ template: input, components: defaultComponents })) - } - - return render( - defineComponent( - Object.assign({}, input, { - components: { ...defaultComponents, ...input.components }, - }) as Parameters[0] - ) - ) -} +const renderTemplate = createRenderTemplate({ Menu, MenuButton, MenuItems, MenuItem }) describe('Safe guards', () => { it.each([ diff --git a/packages/@headlessui-vue/src/components/popover/popover.test.ts b/packages/@headlessui-vue/src/components/popover/popover.test.ts index a5fcfaa356..54a730fe89 100644 --- a/packages/@headlessui-vue/src/components/popover/popover.test.ts +++ b/packages/@headlessui-vue/src/components/popover/popover.test.ts @@ -1,5 +1,5 @@ import { defineComponent, nextTick, ref, watch, h, ComponentOptionsWithoutProps } from 'vue' -import { render } from '../../test-utils/vue-testing-library' +import { createRenderTemplate, render } from '../../test-utils/vue-testing-library' import { Popover, PopoverGroup, PopoverButton, PopoverPanel, PopoverOverlay } from './popover' import { Portal } from '../portal/portal' @@ -28,8 +28,8 @@ beforeAll(() => { afterAll(() => jest.restoreAllMocks()) -function renderTemplate(input: string | ComponentOptionsWithoutProps) { - let defaultComponents = { +function getDefaultComponents() { + return { Popover, PopoverGroup, PopoverButton, @@ -37,20 +37,10 @@ function renderTemplate(input: string | ComponentOptionsWithoutProps) { PopoverOverlay, Portal, } - - if (typeof input === 'string') { - return render(defineComponent({ template: input, components: defaultComponents })) - } - - return render( - defineComponent( - Object.assign({}, input, { - components: { ...defaultComponents, ...input.components }, - }) as Parameters[0] - ) - ) } +const renderTemplate = createRenderTemplate(getDefaultComponents()) + describe('Safe guards', () => { it.each([ ['PopoverButton', PopoverButton], diff --git a/packages/@headlessui-vue/src/components/portal/portal.test.ts b/packages/@headlessui-vue/src/components/portal/portal.test.ts index e0baae06d0..ff8f2c942a 100644 --- a/packages/@headlessui-vue/src/components/portal/portal.test.ts +++ b/packages/@headlessui-vue/src/components/portal/portal.test.ts @@ -1,6 +1,6 @@ import { h, defineComponent, ref, nextTick, ComponentOptionsWithoutProps, createSSRApp } from 'vue' -import { render } from '../../test-utils/vue-testing-library' +import { createRenderTemplate, render } from '../../test-utils/vue-testing-library' import { renderToString } from 'vue/server-renderer' import { Portal, PortalGroup } from './portal' import { click } from '../../test-utils/interactions' @@ -23,21 +23,7 @@ beforeAll(() => { afterAll(() => jest.restoreAllMocks()) -function renderTemplate(input: string | ComponentOptionsWithoutProps) { - let defaultComponents = { Portal, PortalGroup } - - if (typeof input === 'string') { - return render(defineComponent({ template: input, components: defaultComponents })) - } - - return render( - defineComponent( - Object.assign({}, input, { - components: { ...defaultComponents, ...input.components }, - }) as Parameters[0] - ) - ) -} +const renderTemplate = createRenderTemplate({ Portal, PortalGroup }) async function ssrRenderTemplate(input: string | ComponentOptionsWithoutProps) { let defaultComponents = { Portal, PortalGroup } diff --git a/packages/@headlessui-vue/src/components/radio-group/radio-group.test.ts b/packages/@headlessui-vue/src/components/radio-group/radio-group.test.ts index e6aca27595..148c87273c 100644 --- a/packages/@headlessui-vue/src/components/radio-group/radio-group.test.ts +++ b/packages/@headlessui-vue/src/components/radio-group/radio-group.test.ts @@ -1,5 +1,5 @@ import { defineComponent, nextTick, ref, watch, reactive, ComponentOptionsWithoutProps } from 'vue' -import { render } from '../../test-utils/vue-testing-library' +import { createRenderTemplate, render } from '../../test-utils/vue-testing-library' import { RadioGroup, RadioGroupOption, RadioGroupLabel, RadioGroupDescription } from './radio-group' @@ -34,21 +34,12 @@ function nextFrame() { }) } -function renderTemplate(input: string | ComponentOptionsWithoutProps) { - let defaultComponents = { RadioGroup, RadioGroupOption, RadioGroupLabel, RadioGroupDescription } - - if (typeof input === 'string') { - return render(defineComponent({ template: input, components: defaultComponents })) - } - - return render( - defineComponent( - Object.assign({}, input, { - components: { ...defaultComponents, ...input.components }, - }) as Parameters[0] - ) - ) -} +const renderTemplate = createRenderTemplate({ + RadioGroup, + RadioGroupOption, + RadioGroupLabel, + RadioGroupDescription, +}) describe('Safe guards', () => { it.each([['RadioGroupOption', RadioGroupOption]])( diff --git a/packages/@headlessui-vue/src/components/switch/switch.test.tsx b/packages/@headlessui-vue/src/components/switch/switch.test.tsx index 67e83416de..bf65a3e66e 100644 --- a/packages/@headlessui-vue/src/components/switch/switch.test.tsx +++ b/packages/@headlessui-vue/src/components/switch/switch.test.tsx @@ -1,5 +1,5 @@ import { defineComponent, ref, watch, h, ComponentOptionsWithoutProps } from 'vue' -import { render } from '../../test-utils/vue-testing-library' +import { createRenderTemplate, render } from '../../test-utils/vue-testing-library' import { Switch, SwitchLabel, SwitchDescription, SwitchGroup } from './switch' import { @@ -16,21 +16,7 @@ import { suppressConsoleLogs } from '../../test-utils/suppress-console-logs' jest.mock('../../hooks/use-id') -function renderTemplate(input: string | ComponentOptionsWithoutProps) { - let defaultComponents = { Switch, SwitchLabel, SwitchDescription, SwitchGroup } - - if (typeof input === 'string') { - return render(defineComponent({ template: input, components: defaultComponents })) - } - - return render( - defineComponent( - Object.assign({}, input, { - components: { ...defaultComponents, ...input.components }, - }) as Parameters[0] - ) - ) -} +const renderTemplate = createRenderTemplate({ Switch, SwitchLabel, SwitchDescription, SwitchGroup }) describe('Safe guards', () => { it('should be possible to render a Switch without crashing', () => { diff --git a/packages/@headlessui-vue/src/components/tabs/tabs.test.ts b/packages/@headlessui-vue/src/components/tabs/tabs.test.ts index 2ec3f3027a..75709043f3 100644 --- a/packages/@headlessui-vue/src/components/tabs/tabs.test.ts +++ b/packages/@headlessui-vue/src/components/tabs/tabs.test.ts @@ -1,5 +1,5 @@ import { ComponentOptionsWithoutProps, defineComponent, nextTick, ref } from 'vue' -import { render } from '../../test-utils/vue-testing-library' +import { createRenderTemplate, render } from '../../test-utils/vue-testing-library' import { TabGroup, TabList, Tab, TabPanels, TabPanel } from './tabs' import { suppressConsoleLogs } from '../../test-utils/suppress-console-logs' import { @@ -20,21 +20,7 @@ beforeAll(() => { afterAll(() => jest.restoreAllMocks()) -function renderTemplate(input: string | ComponentOptionsWithoutProps) { - let defaultComponents = { TabGroup, TabList, Tab, TabPanels, TabPanel } - - if (typeof input === 'string') { - return render(defineComponent({ template: input, components: defaultComponents })) - } - - return render( - defineComponent( - Object.assign({}, input, { - components: { ...defaultComponents, ...input.components }, - }) as Parameters[0] - ) - ) -} +const renderTemplate = createRenderTemplate({ TabGroup, TabList, Tab, TabPanels, TabPanel }) describe('safeguards', () => { it.each([ diff --git a/packages/@headlessui-vue/src/components/transitions/transition.test.ts b/packages/@headlessui-vue/src/components/transitions/transition.test.ts index ea01ade06b..01eae6fd3c 100644 --- a/packages/@headlessui-vue/src/components/transitions/transition.test.ts +++ b/packages/@headlessui-vue/src/components/transitions/transition.test.ts @@ -1,5 +1,5 @@ import { defineComponent, ref, onMounted, ComponentOptionsWithoutProps } from 'vue' -import { render, fireEvent } from '../../test-utils/vue-testing-library' +import { render, fireEvent, createRenderTemplate } from '../../test-utils/vue-testing-library' import { suppressConsoleLogs } from '../../test-utils/suppress-console-logs' import { TransitionRoot, TransitionChild } from './transition' @@ -11,21 +11,7 @@ jest.mock('../../hooks/use-id') afterAll(() => jest.restoreAllMocks()) -function renderTemplate(input: string | ComponentOptionsWithoutProps) { - let defaultComponents = { TransitionRoot, TransitionChild } - - if (typeof input === 'string') { - return render(defineComponent({ template: input, components: defaultComponents })) - } - - return render( - defineComponent( - Object.assign({}, input, { - components: { ...defaultComponents, ...input.components }, - }) as Parameters[0] - ) - ) -} +const renderTemplate = createRenderTemplate({ TransitionRoot, TransitionChild }) function getByTestId(id: string) { return document.querySelector(`[data-testid="${id}"]`)! as HTMLElement diff --git a/packages/@headlessui-vue/src/test-utils/vue-testing-library.ts b/packages/@headlessui-vue/src/test-utils/vue-testing-library.ts index 81eb7bbb66..a2d64a2205 100644 --- a/packages/@headlessui-vue/src/test-utils/vue-testing-library.ts +++ b/packages/@headlessui-vue/src/test-utils/vue-testing-library.ts @@ -1,5 +1,6 @@ import { mount } from '@vue/test-utils' import { logDOM, fireEvent, screen } from '@testing-library/dom' +import { DefineComponent, ComponentOptionsWithoutProps, defineComponent } from 'vue' let mountedWrappers = new Set() @@ -13,6 +14,24 @@ function resolveContainer(): HTMLElement { return attachTo } +// It's not the most elegant type +// but Props and Emits need to be typed as any and not `{}` +type AnyComponent = DefineComponent + +export function createRenderTemplate(defaultComponents: Record) { + return (input: string | ComponentOptionsWithoutProps) => { + if (typeof input === 'string') { + input = { template: input } + } + + let component: ComponentOptionsWithoutProps = Object.assign({}, input, { + components: { ...defaultComponents, ...input.components }, + }) + + return render(defineComponent(component)) + } +} + export function render(TestComponent: any, options?: Parameters[1] | undefined) { let wrapper = mount(TestComponent, { ...options, diff --git a/packages/@headlessui-vue/src/utils/render.test.ts b/packages/@headlessui-vue/src/utils/render.test.ts index 287ce0ff30..ddec4c01ef 100644 --- a/packages/@headlessui-vue/src/utils/render.test.ts +++ b/packages/@headlessui-vue/src/utils/render.test.ts @@ -1,5 +1,5 @@ import { defineComponent, ComponentOptionsWithoutProps } from 'vue' -import { render as testRender } from '../test-utils/vue-testing-library' +import { createRenderTemplate, render as testRender } from '../test-utils/vue-testing-library' import { render } from './render' import { html } from '../test-utils/html' @@ -13,21 +13,7 @@ let Dummy = defineComponent({ }, }) -function renderTemplate(input: string | ComponentOptionsWithoutProps) { - let defaultComponents = { Dummy } - - if (typeof input === 'string') { - return testRender(defineComponent({ template: input, components: defaultComponents })) - } - - return testRender( - defineComponent( - Object.assign({}, input, { - components: { ...defaultComponents, ...input.components }, - }) as Parameters[0] - ) - ) -} +const renderTemplate = createRenderTemplate({ Dummy }) describe('Validation', () => { it('should error when using an as="template" with additional props', () => {