From 2fb36d025507921d8d0f81508ab28b69d8249dcf Mon Sep 17 00:00:00 2001 From: kajambiya Date: Fri, 29 Sep 2023 13:06:17 +0300 Subject: [PATCH] Add unit tests and fix circular dependency issue --- .../inputs/select/ohri-dropdown.test.tsx | 2 +- .../ui-select-extended.test.tsx | 165 ++++++++++++++++++ .../ui-select-extended/ui-select-extended.tsx | 4 +- .../inbuilt-components/control-templates.ts | 15 ++ .../inbuilt-components/inbuiltControls.ts | 22 +-- .../template-component-map.ts | 8 + src/registry/registry.ts | 3 +- 7 files changed, 196 insertions(+), 23 deletions(-) create mode 100644 src/components/inputs/ui-select-extended/ui-select-extended.test.tsx create mode 100644 src/registry/inbuilt-components/control-templates.ts create mode 100644 src/registry/inbuilt-components/template-component-map.ts diff --git a/src/components/inputs/select/ohri-dropdown.test.tsx b/src/components/inputs/select/ohri-dropdown.test.tsx index 582fde893..f4ae331e9 100644 --- a/src/components/inputs/select/ohri-dropdown.test.tsx +++ b/src/components/inputs/select/ohri-dropdown.test.tsx @@ -63,7 +63,7 @@ const renderForm = intialValues => { fields: [question], isFieldInitializationComplete: true, isSubmitting: false, - formFieldHandlers: { 'obs': ObsSubmissionHandler } + formFieldHandlers: { obs: ObsSubmissionHandler }, }}> diff --git a/src/components/inputs/ui-select-extended/ui-select-extended.test.tsx b/src/components/inputs/ui-select-extended/ui-select-extended.test.tsx new file mode 100644 index 000000000..c44f1e07c --- /dev/null +++ b/src/components/inputs/ui-select-extended/ui-select-extended.test.tsx @@ -0,0 +1,165 @@ +import React from 'react'; +import { render, fireEvent, waitFor, act, screen } from '@testing-library/react'; +import UISelectExtended from './ui-select-extended'; +import { OHRIFormField } from '../../../api/types'; +import { EncounterContext, OHRIFormContext } from '../../../ohri-form-context'; +import { Form, Formik } from 'formik'; +import { ObsSubmissionHandler } from '../../../submission-handlers/base-handlers'; + +const question: OHRIFormField = { + label: 'Transfer Location', + type: 'obs', + questionOptions: { + rendering: 'ui-select-extended', + concept: '160540AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA', + datasource: { + name: 'location_datasource', + }, + }, + value: null, + id: 'patient_transfer_location', +}; + +const encounterContext: EncounterContext = { + patient: { + id: '833db896-c1f0-11eb-8529-0242ac130003', + }, + location: { + uuid: '41e6e516-c1f0-11eb-8529-0242ac130003', + }, + encounter: { + uuid: '873455da-3ec4-453c-b565-7c1fe35426be', + obs: [], + }, + sessionMode: 'enter', + encounterDate: new Date(2023, 8, 29), + setEncounterDate: value => {}, +}; + +const renderForm = intialValues => { + render( + + {props => ( +
+ + + +
+ )} +
, + ); +}; + +// Mock the data source fetch behavior +jest.mock('../../../registry/registry', () => ({ + getRegisteredDataSource: jest.fn().mockResolvedValue({ + fetchData: jest.fn().mockResolvedValue([ + { + uuid: 'aaa-1', + display: 'Kololo', + }, + { + uuid: 'aaa-2', + display: 'Naguru', + }, + { + uuid: 'aaa-3', + display: 'Muyenga', + }, + ]), + toUuidAndDisplay: data => data, + }), +})); + +describe('UISelectExtended Component', () => { + it('renders with items from the datasource', async () => { + await act(async () => { + await renderForm({}); + }); + + // setup + const uiSelectExtendedWidget = screen.getByLabelText('Transfer Location'); + + // assert initial values + await act(async () => { + expect(question.value).toBe(null); + }); + + //Click on the UISelectExtendedWidget to open the dropdown + fireEvent.click(uiSelectExtendedWidget); + + // Assert that all three items are displayed + expect(screen.getByText('Kololo')).toBeInTheDocument(); + expect(screen.getByText('Naguru')).toBeInTheDocument(); + expect(screen.getByText('Muyenga')).toBeInTheDocument(); + }); + + it('Selects a value from the list', async () => { + await act(async () => { + await renderForm({}); + }); + + // setup + const uiSelectExtendedWidget = screen.getByLabelText('Transfer Location'); + + //Click on the UISelectExtendedWidget to open the dropdown + fireEvent.click(uiSelectExtendedWidget); + + // Find the list item for 'Naguru' and click it to select + const naguruOption = screen.getByText('Naguru'); + fireEvent.click(naguruOption); + + // verify + await act(async () => { + expect(question.value).toEqual({ + person: '833db896-c1f0-11eb-8529-0242ac130003', + obsDatetime: new Date(2023, 8, 29), + concept: '160540AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA', + location: { uuid: '41e6e516-c1f0-11eb-8529-0242ac130003' }, + formFieldNamespace: 'ohri-forms', + formFieldPath: 'ohri-forms-patient_transfer_location', + order: null, + groupMembers: [], + voided: false, + value: 'aaa-2', + }); + }); + }); + + it('Filters items based on user input', async () => { + await act(async () => { + await renderForm({}); + }); + + // setup + const uiSelectExtendedWidget = screen.getByLabelText('Transfer Location'); + + //Click on the UISelectExtendedWidget to open the dropdown + fireEvent.click(uiSelectExtendedWidget); + + // Type 'Nag' in the input field to filter items + fireEvent.change(uiSelectExtendedWidget, { target: { value: 'Nag' } }); + + // Wait for the filtered items to appear in the dropdown + await waitFor(() => { + // Verify that 'Naguru' is in the filtered items + expect(screen.getByText('Naguru')).toBeInTheDocument(); + + // Verify that 'Kololo' and 'Muyenga' are not in the filtered items + expect(screen.queryByText('Kololo')).not.toBeInTheDocument(); + expect(screen.queryByText('Muyenga')).not.toBeInTheDocument(); + }); + }); +}); diff --git a/src/components/inputs/ui-select-extended/ui-select-extended.tsx b/src/components/inputs/ui-select-extended/ui-select-extended.tsx index fe0eb4916..c4b1abcda 100644 --- a/src/components/inputs/ui-select-extended/ui-select-extended.tsx +++ b/src/components/inputs/ui-select-extended/ui-select-extended.tsx @@ -12,7 +12,7 @@ import { PreviousValueReview } from '../../previous-value-review/previous-value- import debounce from 'lodash-es/debounce'; import { useTranslation } from 'react-i18next'; import { getRegisteredDataSource } from '../../../registry/registry'; -import { getControlTemplate } from '../../../registry/inbuilt-components/inbuiltControls'; +import { getControlTemplate } from '../../../registry/inbuilt-components/control-templates'; const UISelectExtended: React.FC = ({ question, handler, onChange }) => { const { t } = useTranslation(); @@ -123,8 +123,6 @@ const UISelectExtended: React.FC = ({ question, handler, onC id={question.id} titleText={question.label} items={items} - isLoading={isLoading} - loadingMessage="loading..." itemToString={item => item?.display} selectedItem={items.find(item => item.uuid == field.value)} shouldFilterItem={({ item, inputValue }) => { diff --git a/src/registry/inbuilt-components/control-templates.ts b/src/registry/inbuilt-components/control-templates.ts new file mode 100644 index 000000000..92cf96517 --- /dev/null +++ b/src/registry/inbuilt-components/control-templates.ts @@ -0,0 +1,15 @@ +export const controlTemplates = [ + { + name: 'drug', + datasource: { + name: 'drug_datasource', + config: { + class: '8d490dfc-c2cc-11de-8d13-0010c6dffd0f', + }, + }, + }, +]; + +export const getControlTemplate = (name: string) => { + return controlTemplates.find(template => template.name === name); +}; diff --git a/src/registry/inbuilt-components/inbuiltControls.ts b/src/registry/inbuilt-components/inbuiltControls.ts index 2ae36d429..dae9d7c84 100644 --- a/src/registry/inbuilt-components/inbuiltControls.ts +++ b/src/registry/inbuilt-components/inbuiltControls.ts @@ -1,5 +1,6 @@ import { OHRIFormFieldProps } from '../../api/types'; import OHRIExtensionParcel from '../../components/extension/ohri-extension-parcel.component'; +import UISelectExtended from '../../components/inputs/ui-select-extended/ui-select-extended'; import { OHRIObsGroup } from '../../components/group/ohri-obs-group.component'; import { OHRIContentSwitcher } from '../../components/inputs/content-switcher/ohri-content-switcher.component'; import OHRIDate from '../../components/inputs/date/ohri-date.component'; @@ -13,25 +14,14 @@ import OHRIDropdown from '../../components/inputs/select/ohri-dropdown.component import OHRITextArea from '../../components/inputs/text-area/ohri-text-area.component'; import OHRIText from '../../components/inputs/text/ohri-text.component'; import OHRIToggle from '../../components/inputs/toggle/ohri-toggle.component'; -import UISelectExtended from '../../components/inputs/ui-select-extended/ui-select-extended'; import { OHRIRepeat } from '../../components/repeat/ohri-repeat.component'; import { RegistryItem } from '../registry'; +import { controlTemplates } from './control-templates'; +import { templateToComponentMap } from './template-component-map'; /** * @internal */ -const controlTemplates = [ - { - name: 'drug', - baseControlComponent: UISelectExtended, - datasource: { - name: 'drug_datasource', - config: { - class: '8d490dfc-c2cc-11de-8d13-0010c6dffd0f', - }, - }, - }, -]; export const inbuiltControls: Array>> = [ { @@ -123,11 +113,7 @@ export const inbuiltControls: Array ({ name: `${template.name}Control`, - component: template.baseControlComponent, + component: templateToComponentMap.find(component => component.name === template.name).baseControlComponent, type: template.name.toLowerCase(), })), ]; - -export const getControlTemplate = (name: string) => { - return controlTemplates.find(template => template.name === name); -}; diff --git a/src/registry/inbuilt-components/template-component-map.ts b/src/registry/inbuilt-components/template-component-map.ts new file mode 100644 index 000000000..3441717de --- /dev/null +++ b/src/registry/inbuilt-components/template-component-map.ts @@ -0,0 +1,8 @@ +import UISelectExtended from '../../components/inputs/ui-select-extended/ui-select-extended'; + +export const templateToComponentMap = [ + { + name: 'drug', + baseControlComponent: UISelectExtended, + }, +]; diff --git a/src/registry/registry.ts b/src/registry/registry.ts index 141908119..a3c56d619 100644 --- a/src/registry/registry.ts +++ b/src/registry/registry.ts @@ -1,10 +1,11 @@ import { DataSource, FieldValidator, OHRIFormFieldProps, PostSubmissionAction, SubmissionHandler } from '../api/types'; import { getGlobalStore } from '@openmrs/esm-framework'; import { OHRIFormsStore } from '../constants'; -import { getControlTemplate, inbuiltControls } from './inbuilt-components/inbuiltControls'; +import { inbuiltControls } from './inbuilt-components/inbuiltControls'; import { inbuiltFieldSubmissionHandlers } from './inbuilt-components/inbuiltFieldSubmissionHandlers'; import { inbuiltValidators } from './inbuilt-components/inbuiltValidators'; import { inbuiltDataSources } from './inbuilt-components/inbuiltDataSources'; +import { getControlTemplate } from './inbuilt-components/control-templates'; /** * @internal