From 86eb49b10f3b4bd592e258ad106ddec39879fe6a Mon Sep 17 00:00:00 2001 From: Sergei Maertens Date: Fri, 22 Nov 2024 13:56:28 +0100 Subject: [PATCH] :green_heart: [#4693] Fix interaction tests The tests broke because of react-select now *always* being rendered in a portal. Added a helper that encapsulates this logic so that we don't need to worry about this in our actual test code. --- package.json | 2 +- .../form_design/RegistrationFields.stories.js | 4 ++-- .../actions/dmn/DMNActionConfig.stories.js | 5 ++--- .../ObjectsApiOptionsFormFields.stories.js | 12 +++++------ .../zgw/ZGWOptionsFormFields.stories.js | 6 +++--- .../variables/VariablesEditor.stories.js | 1 - .../admin/forms/VariableMapping.stories.js | 10 +++++----- .../admin/forms/VariableSelection.stories.js | 6 ++++++ .../js/utils/storybookTestHelpers.js | 20 ++++++++++++++++++- 9 files changed, 44 insertions(+), 22 deletions(-) diff --git a/package.json b/package.json index 5f82ebe1da..d375b3872f 100644 --- a/package.json +++ b/package.json @@ -148,7 +148,7 @@ "trailingComma": "es5", "useTabs": false, "importOrder": [ - "^((api-mocks|components|data|formio|hooks|map|story-utils|types|utils)/(.*)|(api|api-mocks|cache|Context|errors|headers|i18n|sdk|sentry|types))$", + "^((api-mocks|components|data|formio|hooks|map|story-utils|types|utils)/(.*)|(api|api-mocks|cache|Context|errors|headers|i18n|sdk|sentry|story-utils|types))$", "^[./]" ], "importOrderSeparation": true, diff --git a/src/openforms/js/components/admin/form_design/RegistrationFields.stories.js b/src/openforms/js/components/admin/form_design/RegistrationFields.stories.js index 631595ccd9..a2ba06bcbc 100644 --- a/src/openforms/js/components/admin/form_design/RegistrationFields.stories.js +++ b/src/openforms/js/components/admin/form_design/RegistrationFields.stories.js @@ -1,5 +1,4 @@ import {expect, fn, screen, userEvent, waitFor, within} from '@storybook/test'; -import selectEvent from 'react-select-event'; import {mockProcessDefinitionsGet} from 'components/admin/form_design/registrations/camunda/mocks'; import { @@ -17,6 +16,7 @@ import { FormDecorator, ValidationErrorsDecorator, } from 'components/admin/form_design/story-decorators'; +import {rsSelect} from 'utils/storybookTestHelpers'; import RegistrationFields from './RegistrationFields'; @@ -729,7 +729,7 @@ export const ObjectsAPI = { await userEvent.click(within(fieldsetTitle).getByRole('link', {name: '(Tonen)'})); const catalogueSelect = modal.getByLabelText('Catalogus'); - await selectEvent.select(catalogueSelect, 'Catalogus 2'); + await rsSelect(catalogueSelect, 'Catalogus 2'); }); await step('Submit the form', async () => { diff --git a/src/openforms/js/components/admin/form_design/logic/actions/dmn/DMNActionConfig.stories.js b/src/openforms/js/components/admin/form_design/logic/actions/dmn/DMNActionConfig.stories.js index 2638f48e77..a94e86a518 100644 --- a/src/openforms/js/components/admin/form_design/logic/actions/dmn/DMNActionConfig.stories.js +++ b/src/openforms/js/components/admin/form_design/logic/actions/dmn/DMNActionConfig.stories.js @@ -1,5 +1,4 @@ import {expect, fireEvent, fn, userEvent, waitFor, within} from '@storybook/test'; -import selectEvent from 'react-select-event'; import { mockDMNDecisionDefinitionVersionsGet, @@ -8,7 +7,7 @@ import { } from 'components/admin/form_design/mocks'; import {FormDecorator} from 'components/admin/form_design/story-decorators'; import {serializeValue} from 'components/admin/forms/VariableMapping'; -import {getReactSelectContainer} from 'utils/storybookTestHelpers'; +import {getReactSelectContainer, rsSelect} from 'utils/storybookTestHelpers'; import DMNActionConfig from './DMNActionConfig'; @@ -232,7 +231,7 @@ export const Empty = { const [formVarsDropdowns, dmnVarsDropdown] = dropdowns; - await selectEvent.select(formVarsDropdowns, 'Name'); + await rsSelect(formVarsDropdowns, 'Name'); // this is super flaky for some reason on both Chromium and Firefox :/ await waitFor(async () => { await userEvent.selectOptions(dmnVarsDropdown, 'Camunda variable'); diff --git a/src/openforms/js/components/admin/form_design/registrations/objectsapi/ObjectsApiOptionsFormFields.stories.js b/src/openforms/js/components/admin/form_design/registrations/objectsapi/ObjectsApiOptionsFormFields.stories.js index fa0d755abc..ddee0bdd9d 100644 --- a/src/openforms/js/components/admin/form_design/registrations/objectsapi/ObjectsApiOptionsFormFields.stories.js +++ b/src/openforms/js/components/admin/form_design/registrations/objectsapi/ObjectsApiOptionsFormFields.stories.js @@ -1,11 +1,11 @@ import {expect, fn, userEvent, waitFor, within} from '@storybook/test'; import {Form, Formik} from 'formik'; -import selectEvent from 'react-select-event'; import { FeatureFlagsDecorator, ValidationErrorsDecorator, } from 'components/admin/form_design/story-decorators'; +import {rsSelect} from 'utils/storybookTestHelpers'; import ObjectsApiOptionsFormFields from './ObjectsApiOptionsFormFields'; import { @@ -92,7 +92,7 @@ export const SwitchToV2Empty = { }); const groupSelect = canvas.getByLabelText('API-groep'); - await selectEvent.select(groupSelect, 'Objects API group 1'); + await rsSelect(groupSelect, 'Objects API group 1'); const testForm = await canvas.findByTestId('test-form'); await waitFor(() => { @@ -280,7 +280,7 @@ export const APIFetchError = { await step('Retrieving object types', async () => { const groupSelect = canvas.getByLabelText('API-groep'); - await selectEvent.select(groupSelect, 'Objects API group 1'); + await rsSelect(groupSelect, 'Objects API group 1'); const errorMessage = await canvas.findByText( 'Er ging iets fout bij het ophalen van de objecttypes.' @@ -350,9 +350,9 @@ export const SelectDocumentType = { await userEvent.click(within(fieldsetTitle).getByRole('link', {name: '(Tonen)'})); const catalogueSelect = canvas.getByLabelText('Catalogus'); - await selectEvent.select(catalogueSelect, 'Catalogus 1'); + await rsSelect(catalogueSelect, 'Catalogus 1'); const pdfSelect = canvas.getByLabelText('Informatieobjecttype inzendings-PDF'); - await selectEvent.select(pdfSelect, 'Test PDF'); + await rsSelect(pdfSelect, 'Test PDF'); const testForm = await canvas.findByTestId('test-form'); await waitFor(() => { @@ -363,7 +363,7 @@ export const SelectDocumentType = { }); }); - await selectEvent.select(catalogueSelect, 'Catalogus 2'); + await rsSelect(catalogueSelect, 'Catalogus 2'); await waitFor(() => { expect(testForm).toHaveFormValues({ iotSubmissionReport: '', diff --git a/src/openforms/js/components/admin/form_design/registrations/zgw/ZGWOptionsFormFields.stories.js b/src/openforms/js/components/admin/form_design/registrations/zgw/ZGWOptionsFormFields.stories.js index c12994c9d2..3d6705ac98 100644 --- a/src/openforms/js/components/admin/form_design/registrations/zgw/ZGWOptionsFormFields.stories.js +++ b/src/openforms/js/components/admin/form_design/registrations/zgw/ZGWOptionsFormFields.stories.js @@ -1,12 +1,12 @@ import {fn, userEvent, within} from '@storybook/test'; import {Form, Formik} from 'formik'; -import selectEvent from 'react-select-event'; import { FeatureFlagsDecorator, FormDecorator, ValidationErrorsDecorator, } from 'components/admin/form_design/story-decorators'; +import {rsSelect} from 'utils/storybookTestHelpers'; import ZGWFormFields from './ZGWOptionsFormFields'; import {mockCaseTypesGet, mockCataloguesGet, mockProductsGet} from './mocks'; @@ -119,11 +119,11 @@ export const SelectCaseType = { const canvas = within(canvasElement); const catalogueSelect = canvas.getByLabelText('Catalogus'); - await selectEvent.select(catalogueSelect, 'Catalogus 1'); + await rsSelect(catalogueSelect, 'Catalogus 1'); const caseTypeSelect = canvas.getByLabelText('Zaaktype', { selector: '#id_caseTypeIdentification', }); - await selectEvent.select(caseTypeSelect, 'Request passport'); + await rsSelect(caseTypeSelect, 'Request passport'); }, }; diff --git a/src/openforms/js/components/admin/form_design/variables/VariablesEditor.stories.js b/src/openforms/js/components/admin/form_design/variables/VariablesEditor.stories.js index 014770575f..610d5f44b6 100644 --- a/src/openforms/js/components/admin/form_design/variables/VariablesEditor.stories.js +++ b/src/openforms/js/components/admin/form_design/variables/VariablesEditor.stories.js @@ -1,5 +1,4 @@ import {expect, fn, screen, userEvent, waitFor, within} from '@storybook/test'; -import selectEvent from 'react-select-event'; import { mockObjectsAPIPrefillPropertiesGet, diff --git a/src/openforms/js/components/admin/forms/VariableMapping.stories.js b/src/openforms/js/components/admin/forms/VariableMapping.stories.js index a999071807..b6800d5c49 100644 --- a/src/openforms/js/components/admin/forms/VariableMapping.stories.js +++ b/src/openforms/js/components/admin/forms/VariableMapping.stories.js @@ -1,9 +1,9 @@ -import {expect, fn, userEvent, waitFor, within} from '@storybook/test'; +import {expect, fn, userEvent, within} from '@storybook/test'; import selectEvent from 'react-select-event'; import {FormDecorator, FormikDecorator} from 'components/admin/form_design/story-decorators'; import {VARIABLE_SOURCES} from 'components/admin/form_design/variables/constants'; -import {getReactSelectContainer} from 'utils/storybookTestHelpers'; +import {findReactSelectMenu} from 'utils/storybookTestHelpers'; import VariableMapping, {serializeValue} from './VariableMapping'; @@ -149,9 +149,9 @@ export const SelectOptions = { const formVariableDropdown = canvas.getByLabelText('Formuliervariabele'); selectEvent.openMenu(formVariableDropdown); - const formVarOptions = await within( - getReactSelectContainer(formVariableDropdown) - ).findAllByRole('option'); + const formVarOptions = await within(await findReactSelectMenu(canvas)).findAllByRole( + 'option' + ); expect(formVarOptions).toHaveLength(2); expect(formVarOptions[0]).toHaveTextContent('key2'); diff --git a/src/openforms/js/components/admin/forms/VariableSelection.stories.js b/src/openforms/js/components/admin/forms/VariableSelection.stories.js index 0c9b6ccb94..fa8967b72f 100644 --- a/src/openforms/js/components/admin/forms/VariableSelection.stories.js +++ b/src/openforms/js/components/admin/forms/VariableSelection.stories.js @@ -1,6 +1,8 @@ import {useArgs} from '@storybook/preview-api'; +import {expect, within} from '@storybook/test'; import {FormDecorator} from 'components/admin/form_design/story-decorators'; +import {findReactSelectMenu} from 'utils/storybookTestHelpers'; import {VARIABLE_SOURCES} from '../form_design/variables/constants'; import VariableSelection from './VariableSelection'; @@ -120,4 +122,8 @@ export const menuOpen = { args: { menuIsOpen: true, }, + play: async ({canvasElement}) => { + const canvas = within(canvasElement); + expect(await findReactSelectMenu(canvas)).toBeVisible(); + }, }; diff --git a/src/openforms/js/utils/storybookTestHelpers.js b/src/openforms/js/utils/storybookTestHelpers.js index 09fb2a8849..dbc92fdf04 100644 --- a/src/openforms/js/utils/storybookTestHelpers.js +++ b/src/openforms/js/utils/storybookTestHelpers.js @@ -1,3 +1,14 @@ +import selectEvent from 'react-select-event'; + +const SB_ROOT = document.getElementById('storybook-root'); + +/** + * Wrapper around selectEvent.select to ensure the portal option is used. + */ +const rsSelect = async (input, optionOrOptions) => { + await selectEvent.select(input, optionOrOptions, {container: SB_ROOT}); +}; + /** * From the input field (retrieved by accessible queries), find the react-select container. * @@ -16,4 +27,11 @@ const getReactSelectContainer = comboboxInput => { return container; }; -export {getReactSelectContainer}; +/** + * Get the (portaled) opened react select menu. + */ +const findReactSelectMenu = async canvas => { + return await canvas.findByRole('listbox'); +}; + +export {rsSelect, getReactSelectContainer, findReactSelectMenu};