diff --git a/package-lock.json b/package-lock.json index 902b1907..643d5b43 100644 --- a/package-lock.json +++ b/package-lock.json @@ -82,7 +82,6 @@ "prop-types": "^15.8.1", "react": "^18.2.0", "react-dom": "^18.2.0", - "react-select-event": "^5.5.1", "sass": "^1.75.0", "sass-loader": "^14.2.0", "storybook": "^8.3.5", @@ -18110,15 +18109,6 @@ "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, - "node_modules/react-select-event": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/react-select-event/-/react-select-event-5.5.1.tgz", - "integrity": "sha512-goAx28y0+iYrbqZA2FeRTreHHs/ZtSuKxtA+J5jpKT5RHPCbVZJ4MqACfPnWyFXsEec+3dP5bCrNTxIX8oYe9A==", - "dev": true, - "dependencies": { - "@testing-library/dom": ">=7" - } - }, "node_modules/react-signature-canvas": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/react-signature-canvas/-/react-signature-canvas-1.0.6.tgz", @@ -34628,15 +34618,6 @@ "use-isomorphic-layout-effect": "^1.1.2" } }, - "react-select-event": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/react-select-event/-/react-select-event-5.5.1.tgz", - "integrity": "sha512-goAx28y0+iYrbqZA2FeRTreHHs/ZtSuKxtA+J5jpKT5RHPCbVZJ4MqACfPnWyFXsEec+3dP5bCrNTxIX8oYe9A==", - "dev": true, - "requires": { - "@testing-library/dom": ">=7" - } - }, "react-signature-canvas": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/react-signature-canvas/-/react-signature-canvas-1.0.6.tgz", diff --git a/package.json b/package.json index 4fe33e94..2bc7eb30 100644 --- a/package.json +++ b/package.json @@ -106,7 +106,6 @@ "prop-types": "^15.8.1", "react": "^18.2.0", "react-dom": "^18.2.0", - "react-select-event": "^5.5.1", "sass": "^1.75.0", "sass-loader": "^14.2.0", "storybook": "^8.3.5", diff --git a/src/components/formio/radio.tsx b/src/components/formio/radio.tsx index 90a50409..cc5387d1 100644 --- a/src/components/formio/radio.tsx +++ b/src/components/formio/radio.tsx @@ -1,7 +1,6 @@ import clsx from 'clsx'; import {Field, useFormikContext} from 'formik'; import {ExtendedComponentSchema} from 'formiojs'; -import {ReactNode} from 'react'; import {FormattedMessage} from 'react-intl'; import {useValidationErrors} from '@/utils/errors'; @@ -35,7 +34,7 @@ export const RadioInput: React.FC = ({name, value, label, descr export interface Option { value: string; - label: ReactNode; + label: React.ReactNode; description?: string; } diff --git a/src/components/formio/select.tsx b/src/components/formio/select.tsx index 06d732c9..66553267 100644 --- a/src/components/formio/select.tsx +++ b/src/components/formio/select.tsx @@ -1,6 +1,5 @@ import {useField} from 'formik'; import React from 'react'; -import {ReactNode} from 'react'; import ReactSelect from 'react-select'; import type { GroupBase, @@ -38,7 +37,7 @@ export interface SelectProps< export interface Option { value: string; - label: ReactNode; + label: React.ReactNode; description?: string; } diff --git a/src/components/formio/selectboxes.tsx b/src/components/formio/selectboxes.tsx index b6808ba7..75fe6934 100644 --- a/src/components/formio/selectboxes.tsx +++ b/src/components/formio/selectboxes.tsx @@ -1,12 +1,10 @@ -import {ReactNode} from 'react'; - import {CheckboxInput} from './checkbox'; import Component from './component'; import Description from './description'; export interface Option { value: string; - label: ReactNode; + label: React.ReactNode; description?: string; } diff --git a/src/registry/radio/radio-referentielijsten.stories.ts b/src/registry/radio/radio-referentielijsten.stories.ts index 3cce586b..622c40b9 100644 --- a/src/registry/radio/radio-referentielijsten.stories.ts +++ b/src/registry/radio/radio-referentielijsten.stories.ts @@ -51,13 +51,13 @@ export const StoreValuesInComponent: Story = { await step('Fill in options', async () => { const dataSourceInput = canvas.getByLabelText('Data source'); - await rsSelect(dataSourceInput, 'Referentielijsten API'); + await rsSelect(canvas, dataSourceInput, 'Referentielijsten API'); const serviceInput = canvas.getByLabelText('Referentielijsten service'); - await rsSelect(serviceInput, 'Referentielijsten'); + await rsSelect(canvas, serviceInput, 'Referentielijsten'); const codeInput = canvas.getByLabelText('Referentielijsten table code'); - await rsSelect(codeInput, 'Tabel 2 (niet meer geldig)'); + await rsSelect(canvas, codeInput, 'Tabel 2 (niet meer geldig)'); await userEvent.click(canvas.getByRole('button', {name: 'Save'})); @@ -83,15 +83,15 @@ export const SwitchToVariableResetOptions: Story = { await step('Fill in options', async () => { const dataSourceInput = canvas.getByLabelText('Data source'); - await rsSelect(dataSourceInput, 'Referentielijsten API'); + await rsSelect(canvas, dataSourceInput, 'Referentielijsten API'); const serviceInput = canvas.getByLabelText('Referentielijsten service'); - await rsSelect(serviceInput, 'Referentielijsten'); + await rsSelect(canvas, serviceInput, 'Referentielijsten'); const codeInput = canvas.getByLabelText('Referentielijsten table code'); - await rsSelect(codeInput, 'Tabel 2 (niet meer geldig)'); + await rsSelect(canvas, codeInput, 'Tabel 2 (niet meer geldig)'); - await rsSelect(dataSourceInput, 'From variable'); + await rsSelect(canvas, dataSourceInput, 'From variable'); const itemsExpressionInput = canvas.getByTestId('jsonEdit'); await userEvent.clear(itemsExpressionInput); @@ -120,15 +120,15 @@ export const SwitchToManualResetOptions: Story = { await step('Fill in options', async () => { const dataSourceInput = canvas.getByLabelText('Data source'); - await rsSelect(dataSourceInput, 'Referentielijsten API'); + await rsSelect(canvas, dataSourceInput, 'Referentielijsten API'); const serviceInput = canvas.getByLabelText('Referentielijsten service'); - await rsSelect(serviceInput, 'Referentielijsten'); + await rsSelect(canvas, serviceInput, 'Referentielijsten'); const codeInput = canvas.getByLabelText('Referentielijsten table code'); - await rsSelect(codeInput, 'Tabel 2 (niet meer geldig)'); + await rsSelect(canvas, codeInput, 'Tabel 2 (niet meer geldig)'); - await rsSelect(dataSourceInput, 'Manually fill in'); + await rsSelect(canvas, dataSourceInput, 'Manually fill in'); const labelInput = canvas.getByTestId('input-values[0].label'); await userEvent.type(labelInput, 'Foo'); @@ -178,7 +178,7 @@ export const AutoSelectIfOnlyOneReferentielijstenService: Story = { await step('Fill in options', async () => { const dataSourceInput = canvas.getByLabelText('Data source'); - await rsSelect(dataSourceInput, 'Referentielijsten API'); + await rsSelect(canvas, dataSourceInput, 'Referentielijsten API'); const serviceInput = canvas.getByLabelText('Referentielijsten service'); diff --git a/src/registry/select/select-referentielijsten.stories.ts b/src/registry/select/select-referentielijsten.stories.ts index ecc55918..233dec93 100644 --- a/src/registry/select/select-referentielijsten.stories.ts +++ b/src/registry/select/select-referentielijsten.stories.ts @@ -51,13 +51,13 @@ export const StoreValuesInComponent: Story = { await step('Fill in options', async () => { const dataSourceInput = canvas.getByLabelText('Data source'); - await rsSelect(dataSourceInput, 'Referentielijsten API'); + await rsSelect(canvas, dataSourceInput, 'Referentielijsten API'); const serviceInput = canvas.getByLabelText('Referentielijsten service'); - await rsSelect(serviceInput, 'Referentielijsten'); + await rsSelect(canvas, serviceInput, 'Referentielijsten'); const codeInput = canvas.getByLabelText('Referentielijsten table code'); - await rsSelect(codeInput, 'Tabel 2 (niet meer geldig)'); + await rsSelect(canvas, codeInput, 'Tabel 2 (niet meer geldig)'); await userEvent.click(canvas.getByRole('button', {name: 'Save'})); @@ -83,15 +83,15 @@ export const SwitchToVariableResetOptions: Story = { await step('Fill in options', async () => { const dataSourceInput = canvas.getByLabelText('Data source'); - await rsSelect(dataSourceInput, 'Referentielijsten API'); + await rsSelect(canvas, dataSourceInput, 'Referentielijsten API'); const serviceInput = canvas.getByLabelText('Referentielijsten service'); - await rsSelect(serviceInput, 'Referentielijsten'); + await rsSelect(canvas, serviceInput, 'Referentielijsten'); const codeInput = canvas.getByLabelText('Referentielijsten table code'); - await rsSelect(codeInput, 'Tabel 2 (niet meer geldig)'); + await rsSelect(canvas, codeInput, 'Tabel 2 (niet meer geldig)'); - await rsSelect(dataSourceInput, 'From variable'); + await rsSelect(canvas, dataSourceInput, 'From variable'); const itemsExpressionInput = canvas.getByTestId('jsonEdit'); await userEvent.clear(itemsExpressionInput); @@ -120,15 +120,15 @@ export const SwitchToManualResetOptions: Story = { await step('Fill in options', async () => { const dataSourceInput = canvas.getByLabelText('Data source'); - await rsSelect(dataSourceInput, 'Referentielijsten API'); + await rsSelect(canvas, dataSourceInput, 'Referentielijsten API'); const serviceInput = canvas.getByLabelText('Referentielijsten service'); - await rsSelect(serviceInput, 'Referentielijsten'); + await rsSelect(canvas, serviceInput, 'Referentielijsten'); const codeInput = canvas.getByLabelText('Referentielijsten table code'); - await rsSelect(codeInput, 'Tabel 2 (niet meer geldig)'); + await rsSelect(canvas, codeInput, 'Tabel 2 (niet meer geldig)'); - await rsSelect(dataSourceInput, 'Manually fill in'); + await rsSelect(canvas, dataSourceInput, 'Manually fill in'); const labelInput = canvas.getByTestId('input-data.values[0].label'); await userEvent.type(labelInput, 'Foo'); diff --git a/src/registry/selectboxes/selectboxes-referentielijsten.stories.ts b/src/registry/selectboxes/selectboxes-referentielijsten.stories.ts index 293f2ce4..e6f9f95f 100644 --- a/src/registry/selectboxes/selectboxes-referentielijsten.stories.ts +++ b/src/registry/selectboxes/selectboxes-referentielijsten.stories.ts @@ -48,13 +48,13 @@ export const StoreValuesInComponent: Story = { await step('Fill in options', async () => { const dataSourceInput = canvas.getByLabelText('Data source'); - await rsSelect(dataSourceInput, 'Referentielijsten API'); + await rsSelect(canvas, dataSourceInput, 'Referentielijsten API'); const serviceInput = canvas.getByLabelText('Referentielijsten service'); - await rsSelect(serviceInput, 'Referentielijsten'); + await rsSelect(canvas, serviceInput, 'Referentielijsten'); const codeInput = canvas.getByLabelText('Referentielijsten table code'); - await rsSelect(codeInput, 'Tabel 2 (niet meer geldig)'); + await rsSelect(canvas, codeInput, 'Tabel 2 (niet meer geldig)'); await userEvent.click(canvas.getByRole('button', {name: 'Save'})); @@ -80,15 +80,15 @@ export const SwitchToVariableResetOptions: Story = { await step('Fill in options', async () => { const dataSourceInput = canvas.getByLabelText('Data source'); - await rsSelect(dataSourceInput, 'Referentielijsten API'); + await rsSelect(canvas, dataSourceInput, 'Referentielijsten API'); const serviceInput = canvas.getByLabelText('Referentielijsten service'); - await rsSelect(serviceInput, 'Referentielijsten'); + await rsSelect(canvas, serviceInput, 'Referentielijsten'); const codeInput = canvas.getByLabelText('Referentielijsten table code'); - await rsSelect(codeInput, 'Tabel 2 (niet meer geldig)'); + await rsSelect(canvas, codeInput, 'Tabel 2 (niet meer geldig)'); - await rsSelect(dataSourceInput, 'From variable'); + await rsSelect(canvas, dataSourceInput, 'From variable'); const itemsExpressionInput = canvas.getByTestId('jsonEdit'); await userEvent.clear(itemsExpressionInput); @@ -117,15 +117,15 @@ export const SwitchToManualResetOptions: Story = { await step('Fill in options', async () => { const dataSourceInput = canvas.getByLabelText('Data source'); - await rsSelect(dataSourceInput, 'Referentielijsten API'); + await rsSelect(canvas, dataSourceInput, 'Referentielijsten API'); const serviceInput = canvas.getByLabelText('Referentielijsten service'); - await rsSelect(serviceInput, 'Referentielijsten'); + await rsSelect(canvas, serviceInput, 'Referentielijsten'); const codeInput = canvas.getByLabelText('Referentielijsten table code'); - await rsSelect(codeInput, 'Tabel 2 (niet meer geldig)'); + await rsSelect(canvas, codeInput, 'Tabel 2 (niet meer geldig)'); - await rsSelect(dataSourceInput, 'Manually fill in'); + await rsSelect(canvas, dataSourceInput, 'Manually fill in'); const labelInput = canvas.getByTestId('input-values[0].label'); await userEvent.type(labelInput, 'Foo'); diff --git a/src/utils/storybookTestHelpers.d.ts b/src/utils/storybookTestHelpers.d.ts index 3ef4dbeb..09f1934b 100644 --- a/src/utils/storybookTestHelpers.d.ts +++ b/src/utils/storybookTestHelpers.d.ts @@ -1,34 +1,17 @@ declare module '@/utils/storybookTestHelpers' { - import {Screen} from '@testing-library/react'; + import {within} from '@storybook/test'; /** * Wrapper around selectEvent.select to ensure the portal option is used. * + * @param canvas - The canvas where the input is present. * @param input - The input element associated with the react-select component. * @param optionOrOptions - The option or options to select. * @returns A promise that resolves when the select event is triggered. */ - export function rsSelect(input: HTMLElement, optionOrOptions: string | string[]): Promise; - - /** - * From the input field (retrieved by accessible queries), find the react-select container. - * - * Usage: - * - * const dropdown = canvas.getByLabelText('My dropdown'); - * const container = getReactSelectContainer(dropdown); - * const options = within(container).queryByRole('option'); - * - * @param comboboxInput - The combobox input element. - * @returns The react-select container element or null if not found. - */ - export function getReactSelectContainer(comboboxInput: HTMLElement): HTMLElement | null; - - /** - * Get the (portaled) opened react-select menu. - * - * @param canvas - The canvas object from Storybook's testing-library. - * @returns A promise that resolves to the listbox element. - */ - export function findReactSelectMenu(canvas: Screen): Promise; + export function rsSelect( + canvas: ReturnType, + input: HTMLElement, + optionOrOptions: string | string[] + ): Promise; } diff --git a/src/utils/storybookTestHelpers.ts b/src/utils/storybookTestHelpers.ts index 2844db3f..cff5b95a 100644 --- a/src/utils/storybookTestHelpers.ts +++ b/src/utils/storybookTestHelpers.ts @@ -1,49 +1,19 @@ -import {ByRoleOptions, Screen} from '@testing-library/react'; -import selectEvent from 'react-select-event'; - -const SB_ROOT: HTMLElement | null = document.getElementById('storybook-root'); +import {userEvent, within} from '@storybook/test'; /** - * Wrapper around selectEvent.select to ensure the portal option is used. + * Wrapper to select an option in a react-select component * + * @param canvas - The canvas where the input is present. * @param input - The input element associated with the react-select component. * @param optionOrOptions - The option or options to select. */ -const rsSelect = async (input: HTMLElement, optionOrOptions: string | string[]): Promise => { - if (!SB_ROOT) { - throw new Error('storybook-root element not found in the DOM.'); - } - await selectEvent.select(input, optionOrOptions, {container: SB_ROOT}); -}; - -/** - * From the input field (retrieved by accessible queries), find the react-select container. - * - * Usage: - * - * const dropdown = canvas.getByLabelText('My dropdown'); - * const container = getReactSelectContainer(dropdown); - * const options = within(container).queryByRole('option'); - * - * @param comboboxInput - The combobox input element. - * @returns The react-select container element or null if not found. - */ -const getReactSelectContainer = (comboboxInput: HTMLElement): HTMLElement | null => { - return comboboxInput.closest('.admin-react-select'); -}; - -/** - * Get the (portaled) opened react-select menu. - * - * @param canvas - The canvas object from Storybook's testing-library. - * @param options - Optional options for querying the listbox. - * @returns A promise that resolves to the listbox element. - */ -const findReactSelectMenu = async ( - canvas: Screen, - options?: ByRoleOptions -): Promise => { - return await canvas.findByRole('listbox', options); +const rsSelect = async ( + canvas: ReturnType, + input: HTMLElement, + optionOrOptions: string | string[] +): Promise => { + await userEvent.click(input); + await userEvent.click(await canvas.findByText(optionOrOptions)); }; -export {rsSelect, getReactSelectContainer, findReactSelectMenu}; +export {rsSelect}; diff --git a/tsconfig.json b/tsconfig.json index 589fe44a..837fb56d 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -16,6 +16,7 @@ "noImplicitAny": true, "strictBindCallApply": true, "strictNullChecks": true, + "skipLibCheck": true, "allowSyntheticDefaultImports": true, "noErrorTruncation": true, "paths": {