@olaboot/esm-patient-registration-app 9.2.0 → 10.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/1339.js +1 -0
- package/dist/1339.js.map +1 -0
- package/dist/1480.js +1 -0
- package/dist/1480.js.map +1 -0
- package/dist/1646.js +1 -0
- package/dist/1646.js.map +1 -0
- package/dist/1789.js +1 -0
- package/dist/1789.js.map +1 -0
- package/dist/1869.js +1 -0
- package/dist/1869.js.map +1 -0
- package/dist/1877.js +1 -0
- package/dist/1877.js.map +1 -0
- package/dist/2317.js +1 -0
- package/dist/2317.js.map +1 -0
- package/dist/2416.js +1 -0
- package/dist/2416.js.map +1 -0
- package/dist/2747.js +1 -0
- package/dist/2747.js.map +1 -0
- package/dist/282.js +1 -0
- package/dist/282.js.map +1 -0
- package/dist/2881.js +1 -0
- package/dist/2881.js.map +1 -0
- package/dist/3378.js +1 -0
- package/dist/3378.js.map +1 -0
- package/dist/3720.js +1 -0
- package/dist/3720.js.map +1 -0
- package/dist/3906.js +1 -0
- package/dist/3906.js.map +1 -0
- package/dist/3963.js +1 -0
- package/dist/3963.js.map +1 -0
- package/dist/3989.js +1 -0
- package/dist/3989.js.map +1 -0
- package/dist/4106.js +1 -0
- package/dist/4106.js.map +1 -0
- package/dist/4111.js +1 -0
- package/dist/4111.js.map +1 -0
- package/dist/434.js +1 -0
- package/dist/434.js.map +1 -0
- package/dist/4348.js +1 -0
- package/dist/4348.js.map +1 -0
- package/dist/4383.js +1 -0
- package/dist/4383.js.map +1 -0
- package/dist/4658.js +1 -0
- package/dist/4658.js.map +1 -0
- package/dist/466.js +1 -0
- package/dist/466.js.map +1 -0
- package/dist/4928.js +1 -0
- package/dist/4928.js.map +1 -0
- package/dist/5117.js +1 -0
- package/dist/5117.js.map +1 -0
- package/dist/5132.js +1 -0
- package/dist/5132.js.map +1 -0
- package/dist/5145.js +1 -0
- package/dist/5145.js.map +1 -0
- package/dist/5208.js +43 -0
- package/dist/5208.js.map +1 -0
- package/dist/527.js +1 -0
- package/dist/527.js.map +1 -0
- package/dist/5280.js +1 -0
- package/dist/5280.js.map +1 -0
- package/dist/5338.js +6 -0
- package/dist/5338.js.map +1 -0
- package/dist/5503.js +1 -0
- package/dist/5503.js.map +1 -0
- package/dist/555.js +1 -0
- package/dist/555.js.map +1 -0
- package/dist/556.js +1 -0
- package/dist/556.js.map +1 -0
- package/dist/5644.js +1 -0
- package/dist/5644.js.map +1 -0
- package/dist/5697.js +1 -0
- package/dist/{4024.js.map → 5697.js.map} +1 -1
- package/dist/5940.js +1 -0
- package/dist/5940.js.map +1 -0
- package/dist/6047.js +1 -0
- package/dist/6047.js.map +1 -0
- package/dist/6371.js +1 -0
- package/dist/6371.js.map +1 -0
- package/dist/6377.js +1 -0
- package/dist/6377.js.map +1 -0
- package/dist/6388.js +1 -0
- package/dist/6388.js.map +1 -0
- package/dist/6444.js +1 -0
- package/dist/6444.js.map +1 -0
- package/dist/6508.js +1 -0
- package/dist/6508.js.map +1 -0
- package/dist/6724.js +1 -0
- package/dist/6724.js.map +1 -0
- package/dist/689.js +1 -0
- package/dist/689.js.map +1 -0
- package/dist/6904.js +1 -0
- package/dist/6904.js.map +1 -0
- package/dist/7045.js +1 -0
- package/dist/7045.js.map +1 -0
- package/dist/7175.js +1 -0
- package/dist/7175.js.map +1 -0
- package/dist/7182.js +1 -0
- package/dist/7182.js.map +1 -0
- package/dist/7649.js +1 -0
- package/dist/7649.js.map +1 -0
- package/dist/7742.js +1 -0
- package/dist/7742.js.map +1 -0
- package/dist/7912.js +1 -0
- package/dist/7912.js.map +1 -0
- package/dist/8358.js +1 -0
- package/dist/8358.js.map +1 -0
- package/dist/8359.js +1 -0
- package/dist/8359.js.map +1 -0
- package/dist/8695.js +1 -0
- package/dist/8695.js.map +1 -0
- package/dist/903.js +1 -0
- package/dist/903.js.map +1 -0
- package/dist/9061.js +1 -0
- package/dist/9061.js.map +1 -0
- package/dist/9072.js +1 -0
- package/dist/9072.js.map +1 -0
- package/dist/9397.js +1 -0
- package/dist/9397.js.map +1 -0
- package/dist/9712.js +1 -0
- package/dist/9712.js.map +1 -0
- package/dist/9771.js +1 -0
- package/dist/9771.js.map +1 -0
- package/dist/9806.js +1 -0
- package/dist/9806.js.map +1 -0
- package/dist/9816.js +1 -0
- package/dist/9816.js.map +1 -0
- package/dist/main.js +7 -6
- package/dist/main.js.map +1 -1
- package/dist/openmrs-esm-patient-registration-app.js +6 -0
- package/dist/{olaboot-esm-patient-registration-app.js.buildmanifest.json → openmrs-esm-patient-registration-app.js.buildmanifest.json} +540 -455
- package/dist/openmrs-esm-patient-registration-app.js.map +1 -0
- package/dist/routes.json +1 -1
- package/package.json +8 -9
- package/src/add-patient-link.extension.tsx +3 -2
- package/src/add-patient-link.test.tsx +2 -1
- package/src/config-schema.ts +1 -1
- package/src/index.ts +2 -24
- package/src/nav-link.test.tsx +1 -0
- package/src/offline.resources.ts +97 -31
- package/src/patient-registration/before-save-prompt.test.tsx +199 -0
- package/src/patient-registration/field/__mocks__/field.resource.ts +8 -7
- package/src/patient-registration/field/address/address-field.component.tsx +10 -13
- package/src/patient-registration/field/address/address-hierarchy-levels.component.tsx +6 -1
- package/src/patient-registration/field/address/address-hierarchy.test.tsx +191 -198
- package/src/patient-registration/field/address/address-search.component.tsx +20 -8
- package/src/patient-registration/field/address/address-search.scss +19 -2
- package/src/patient-registration/field/address/address-search.test.tsx +249 -57
- package/src/patient-registration/field/address/custom-address-field.component.tsx +1 -1
- package/src/patient-registration/field/cause-of-death/cause-of-death.component.tsx +1 -1
- package/src/patient-registration/field/cause-of-death/cause-of-death.test.tsx +251 -0
- package/src/patient-registration/field/custom-field.component.tsx +1 -1
- package/src/patient-registration/field/date-and-time-of-death/date-and-time-of-death.component.tsx +1 -1
- package/src/patient-registration/field/date-and-time-of-death/date-and-time-of-death.test.tsx +144 -0
- package/src/patient-registration/field/dob/dob.component.tsx +2 -2
- package/src/patient-registration/field/dob/dob.test.tsx +370 -54
- package/src/patient-registration/field/field.component.tsx +1 -1
- package/src/patient-registration/field/field.resource.ts +2 -2
- package/src/patient-registration/field/field.test.tsx +25 -22
- package/src/patient-registration/field/gender/gender-field.test.tsx +240 -54
- package/src/patient-registration/field/id/id-field.component.tsx +15 -5
- package/src/patient-registration/field/id/id-field.test.tsx +103 -47
- package/src/patient-registration/field/id/identifier-selection-overlay.test.tsx +346 -0
- package/src/patient-registration/field/name/name-field.component.tsx +2 -2
- package/src/patient-registration/field/name/name-field.test.tsx +282 -0
- package/src/patient-registration/field/obs/obs-field.test.tsx +294 -118
- package/src/patient-registration/field/person-attributes/coded-person-attribute-field.test.tsx +172 -108
- package/src/patient-registration/field/person-attributes/location-person-attribute-field.component.tsx +3 -3
- package/src/patient-registration/field/person-attributes/location-person-attribute-field.resource.tsx +2 -5
- package/src/patient-registration/field/person-attributes/person-attribute-field.component.tsx +2 -2
- package/src/patient-registration/field/person-attributes/person-attribute-field.test.tsx +249 -131
- package/src/patient-registration/field/person-attributes/person-attributes.resource.ts +1 -1
- package/src/patient-registration/field/person-attributes/text-person-attribute-field.test.tsx +98 -70
- package/src/patient-registration/field/phone/phone-field.test.tsx +100 -0
- package/src/patient-registration/form-manager.test.ts +6 -5
- package/src/patient-registration/form-manager.ts +5 -2
- package/src/patient-registration/input/basic-input/input/input.component.tsx +3 -121
- package/src/patient-registration/input/basic-input/input/input.test.tsx +151 -51
- package/src/patient-registration/input/basic-input/select/select-input.test.tsx +113 -33
- package/src/patient-registration/input/combo-input/combo-input.component.tsx +60 -24
- package/src/patient-registration/input/custom-input/autosuggest/autosuggest.component.tsx +10 -101
- package/src/patient-registration/input/custom-input/autosuggest/autosuggest.test.tsx +144 -108
- package/src/patient-registration/input/custom-input/identifier/identifier-input.test.tsx +241 -177
- package/src/patient-registration/input/custom-input/identifier/utils.test.ts +47 -8
- package/src/patient-registration/input/dummy-data/dummy-data-input.component.tsx +12 -12
- package/src/patient-registration/input/dummy-data/dummy-data-input.test.tsx +52 -20
- package/src/patient-registration/input/input.scss +1 -2
- package/src/patient-registration/patient-registration-context.ts +5 -3
- package/src/patient-registration/patient-registration-hooks.ts +4 -12
- package/src/patient-registration/patient-registration-utils.test.ts +2 -1
- package/src/patient-registration/patient-registration-utils.ts +2 -98
- package/src/patient-registration/patient-registration.component.tsx +50 -46
- package/src/patient-registration/patient-registration.resource.test.tsx +4 -7
- package/src/patient-registration/patient-registration.resource.ts +1 -4
- package/src/patient-registration/patient-registration.scss +16 -3
- package/src/patient-registration/patient-registration.test.tsx +99 -65
- package/src/patient-registration/patient-registration.types.ts +17 -28
- package/src/patient-registration/section/death-info/death-info-section.test.tsx +130 -34
- package/src/patient-registration/section/demographics/demographics-section.test.tsx +122 -68
- package/src/patient-registration/section/patient-relationships/relationships-section.component.tsx +15 -15
- package/src/patient-registration/section/patient-relationships/relationships-section.test.tsx +278 -84
- package/src/patient-registration/section/section-wrapper.component.tsx +1 -1
- package/src/patient-registration/ui-components/overlay/overlay.test.tsx +104 -0
- package/src/patient-registration/validation/patient-registration-validation.test.ts +2 -1
- package/src/patient-registration/validation/patient-registration-validation.ts +9 -3
- package/src/root.component.tsx +2 -5
- package/src/widgets/cancel-patient-edit.test.tsx +48 -11
- package/src/widgets/delete-identifier-confirmation.test.tsx +77 -24
- package/src/widgets/edit-patient-details-button.component.tsx +14 -18
- package/src/widgets/edit-patient-details-button.scss +2 -2
- package/src/widgets/edit-patient-details-button.test.tsx +11 -13
- package/translations/am.json +9 -4
- package/translations/ar.json +9 -4
- package/translations/ar_SY.json +9 -4
- package/translations/bn.json +9 -4
- package/translations/cs.json +9 -4
- package/translations/de.json +120 -115
- package/translations/en.json +9 -4
- package/translations/en_US.json +9 -4
- package/translations/es.json +9 -4
- package/translations/es_MX.json +9 -4
- package/translations/fr.json +9 -4
- package/translations/he.json +9 -4
- package/translations/hi.json +9 -4
- package/translations/hi_IN.json +9 -4
- package/translations/id.json +9 -4
- package/translations/it.json +9 -4
- package/translations/ka.json +9 -4
- package/translations/km.json +9 -4
- package/translations/ku.json +9 -4
- package/translations/ky.json +9 -4
- package/translations/lg.json +9 -4
- package/translations/ne.json +9 -4
- package/translations/pl.json +9 -4
- package/translations/pt.json +9 -4
- package/translations/pt_BR.json +10 -5
- package/translations/qu.json +9 -4
- package/translations/ro_RO.json +9 -4
- package/translations/ru_RU.json +9 -4
- package/translations/si.json +9 -4
- package/translations/sq.json +9 -4
- package/translations/sw.json +9 -4
- package/translations/sw_KE.json +9 -4
- package/translations/tr.json +9 -4
- package/translations/tr_TR.json +9 -4
- package/translations/uk.json +9 -4
- package/translations/uz.json +9 -4
- package/translations/uz@Latn.json +9 -4
- package/translations/uz_UZ.json +9 -4
- package/translations/vi.json +9 -4
- package/translations/zh.json +50 -45
- package/translations/zh_CN.json +9 -4
- package/translations/zh_TW.json +9 -4
- package/vitest.config.ts +4 -0
- package/ADDRESS_CONFIGURATION.md +0 -152
- package/IDENTIFIER_CONFIGURATION.md +0 -142
- package/IMPLEMENTATION_SUMMARY.md +0 -111
- package/QUICK_START.md +0 -95
- package/address-required-fields-config.json +0 -26
- package/dist/126.js +0 -1
- package/dist/15.js +0 -1
- package/dist/1564.js +0 -1
- package/dist/1567.js +0 -1
- package/dist/1845.js +0 -1
- package/dist/1953.js +0 -1
- package/dist/200.js +0 -1
- package/dist/200.js.map +0 -1
- package/dist/215.js +0 -1
- package/dist/2178.js +0 -1
- package/dist/250.js +0 -1
- package/dist/250.js.map +0 -1
- package/dist/2523.js +0 -1
- package/dist/2523.js.map +0 -1
- package/dist/2566.js +0 -1
- package/dist/2586.js +0 -1
- package/dist/2586.js.map +0 -1
- package/dist/2716.js +0 -1
- package/dist/2716.js.map +0 -1
- package/dist/2759.js +0 -1
- package/dist/2821.js +0 -6
- package/dist/2821.js.map +0 -1
- package/dist/3089.js +0 -1
- package/dist/3089.js.map +0 -1
- package/dist/3230.js +0 -1
- package/dist/3441.js +0 -1
- package/dist/3565.js +0 -1
- package/dist/3571.js +0 -1
- package/dist/3571.js.map +0 -1
- package/dist/3746.js +0 -1
- package/dist/3925.js +0 -1
- package/dist/3946.js +0 -1
- package/dist/4024.js +0 -1
- package/dist/4744.js +0 -1
- package/dist/4744.js.map +0 -1
- package/dist/4809.js +0 -1
- package/dist/4894.js +0 -1
- package/dist/4970.js +0 -1
- package/dist/4970.js.map +0 -1
- package/dist/5130.js +0 -1
- package/dist/5187.js +0 -1
- package/dist/5491.js +0 -1
- package/dist/5491.js.map +0 -1
- package/dist/5595.js +0 -1
- package/dist/5961.js +0 -1
- package/dist/6133.js +0 -1
- package/dist/634.js +0 -1
- package/dist/634.js.map +0 -1
- package/dist/6456.js +0 -1
- package/dist/6466.js +0 -1
- package/dist/6613.js +0 -1
- package/dist/6783.js +0 -1
- package/dist/7073.js +0 -38
- package/dist/7073.js.map +0 -1
- package/dist/7154.js +0 -1
- package/dist/7154.js.map +0 -1
- package/dist/7348.js +0 -1
- package/dist/7439.js +0 -1
- package/dist/7439.js.map +0 -1
- package/dist/7543.js +0 -1
- package/dist/7607.js +0 -1
- package/dist/772.js +0 -1
- package/dist/7984.js +0 -1
- package/dist/7984.js.map +0 -1
- package/dist/8538.js +0 -1
- package/dist/8538.js.map +0 -1
- package/dist/8599.js +0 -1
- package/dist/8727.js +0 -1
- package/dist/8847.js +0 -1
- package/dist/9015.js +0 -1
- package/dist/906.js +0 -1
- package/dist/9065.js +0 -1
- package/dist/9182.js +0 -1
- package/dist/9339.js +0 -1
- package/dist/9453.js +0 -1
- package/dist/9833.js +0 -1
- package/dist/9833.js.map +0 -1
- package/dist/9856.js +0 -1
- package/dist/9856.js.map +0 -1
- package/dist/9920.js +0 -1
- package/dist/9938.js +0 -1
- package/dist/9943.js +0 -1
- package/dist/9943.js.map +0 -1
- package/dist/olaboot-esm-patient-registration-app.js +0 -5
- package/dist/olaboot-esm-patient-registration-app.js.map +0 -1
- package/example-config.json +0 -14
- package/jest.config.js +0 -3
- package/src/resource.ts +0 -12
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
import { vi, describe, it, expect, test, beforeEach, type Mock } from 'vitest';
|
|
2
3
|
import userEvent from '@testing-library/user-event';
|
|
3
|
-
import { screen } from '@testing-library/react';
|
|
4
|
-
import { Formik, Form
|
|
4
|
+
import { screen, waitFor, fireEvent } from '@testing-library/react';
|
|
5
|
+
import { Formik, Form } from 'formik';
|
|
5
6
|
import { renderWithContext } from 'tools';
|
|
6
7
|
import { type Resources } from '../../../offline.resources';
|
|
7
8
|
import { PatientRegistrationContextProvider } from '../../patient-registration-context';
|
|
@@ -10,27 +11,18 @@ import { useAddressHierarchy, useOrderedAddressHierarchyLevels } from './address
|
|
|
10
11
|
import { type RegistrationConfig, esmPatientRegistrationSchema } from '../../../config-schema';
|
|
11
12
|
import { mockedAddressTemplate, mockedAddressOptions, mockedOrderedFields } from '__mocks__';
|
|
12
13
|
import { ResourcesContextProvider } from '../../../resources-context';
|
|
14
|
+
import { initialFormValues } from '../../patient-registration.component';
|
|
15
|
+
import { type FormValues } from '../../patient-registration.types';
|
|
13
16
|
import AddressSearchComponent from './address-search.component';
|
|
14
17
|
|
|
15
|
-
const mockUseConfig =
|
|
16
|
-
const mockUseAddressHierarchy =
|
|
17
|
-
const mockUseOrderedAddressHierarchyLevels =
|
|
18
|
-
const mockUseFormikContext = useFormikContext as jest.Mock;
|
|
18
|
+
const mockUseConfig = vi.mocked(useConfig<RegistrationConfig>);
|
|
19
|
+
const mockUseAddressHierarchy = vi.mocked(useAddressHierarchy);
|
|
20
|
+
const mockUseOrderedAddressHierarchyLevels = vi.mocked(useOrderedAddressHierarchyLevels);
|
|
19
21
|
|
|
20
|
-
|
|
21
|
-
...(
|
|
22
|
-
useAddressHierarchy:
|
|
23
|
-
useOrderedAddressHierarchyLevels:
|
|
24
|
-
}));
|
|
25
|
-
|
|
26
|
-
jest.mock('../../patient-registration.resource', () => ({
|
|
27
|
-
...(jest.requireActual('../../../patient-registration.resource') as jest.Mock),
|
|
28
|
-
useAddressHierarchy: jest.fn(),
|
|
29
|
-
}));
|
|
30
|
-
|
|
31
|
-
jest.mock('formik', () => ({
|
|
32
|
-
...(jest.requireActual('formik') as jest.Mock),
|
|
33
|
-
useFormikContext: jest.fn(() => ({})),
|
|
22
|
+
vi.mock('./address-hierarchy.resource', async () => ({
|
|
23
|
+
...((await vi.importActual('./address-hierarchy.resource')) as object),
|
|
24
|
+
useAddressHierarchy: vi.fn(),
|
|
25
|
+
useOrderedAddressHierarchyLevels: vi.fn(),
|
|
34
26
|
}));
|
|
35
27
|
|
|
36
28
|
const allFields = mockedAddressTemplate.lines
|
|
@@ -44,23 +36,55 @@ const allFields = mockedAddressTemplate.lines
|
|
|
44
36
|
const orderMap = Object.fromEntries(mockedOrderedFields.map((field, indx) => [field, indx]));
|
|
45
37
|
allFields.sort((existingField1, existingField2) => orderMap[existingField1.name] - orderMap[existingField2.name]);
|
|
46
38
|
|
|
47
|
-
|
|
39
|
+
/**
|
|
40
|
+
* Helper to render AddressSearchComponent with Formik for state-dependent tests.
|
|
41
|
+
*/
|
|
42
|
+
async function renderAddressSearchWithFormik(
|
|
43
|
+
initialValues: Partial<FormValues> = {},
|
|
44
|
+
addressTemplate = mockedAddressTemplate,
|
|
45
|
+
) {
|
|
46
|
+
const defaultValues = {
|
|
47
|
+
address: {},
|
|
48
|
+
...initialValues,
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
let formValuesRef: FormValues = { ...initialFormValues, ...defaultValues } as FormValues;
|
|
48
52
|
const mockResourcesContextValue = { addressTemplate } as unknown as Resources;
|
|
49
53
|
|
|
50
|
-
await renderWithContext(
|
|
51
|
-
<Formik initialValues={
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
54
|
+
const utils = await renderWithContext(
|
|
55
|
+
<Formik initialValues={defaultValues} onSubmit={() => {}}>
|
|
56
|
+
{({ setFieldValue, values }) => {
|
|
57
|
+
formValuesRef = { ...initialFormValues, ...values } as FormValues;
|
|
58
|
+
return (
|
|
59
|
+
<Form>
|
|
60
|
+
<PatientRegistrationContextProvider
|
|
61
|
+
value={{
|
|
62
|
+
identifierTypes: [],
|
|
63
|
+
values: formValuesRef,
|
|
64
|
+
validationSchema: null,
|
|
65
|
+
inEditMode: false,
|
|
66
|
+
setFieldValue: setFieldValue as any,
|
|
67
|
+
setCapturePhotoProps: vi.fn(),
|
|
68
|
+
setFieldTouched: vi.fn().mockResolvedValue(undefined),
|
|
69
|
+
currentPhoto: '',
|
|
70
|
+
isOffline: false,
|
|
71
|
+
initialFormValues: formValuesRef,
|
|
72
|
+
}}>
|
|
73
|
+
<AddressSearchComponent addressLayout={allFields} />
|
|
74
|
+
</PatientRegistrationContextProvider>
|
|
75
|
+
</Form>
|
|
76
|
+
);
|
|
77
|
+
}}
|
|
57
78
|
</Formik>,
|
|
58
79
|
ResourcesContextProvider,
|
|
59
80
|
mockResourcesContextValue,
|
|
60
81
|
);
|
|
61
|
-
}
|
|
62
82
|
|
|
63
|
-
|
|
83
|
+
return {
|
|
84
|
+
...utils,
|
|
85
|
+
getFormValues: () => formValuesRef,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
64
88
|
|
|
65
89
|
describe('Testing address search bar', () => {
|
|
66
90
|
beforeEach(() => {
|
|
@@ -73,7 +97,6 @@ describe('Testing address search bar', () => {
|
|
|
73
97
|
useQuickSearch: true,
|
|
74
98
|
searchAddressByLevel: false,
|
|
75
99
|
},
|
|
76
|
-
requiredAddressFields: [],
|
|
77
100
|
},
|
|
78
101
|
} as RegistrationConfig['fieldConfigurations'],
|
|
79
102
|
});
|
|
@@ -82,60 +105,229 @@ describe('Testing address search bar', () => {
|
|
|
82
105
|
isLoadingFieldOrder: false,
|
|
83
106
|
errorFetchingFieldOrder: null,
|
|
84
107
|
});
|
|
85
|
-
mockUseFormikContext.mockReturnValue({
|
|
86
|
-
setFieldValue,
|
|
87
|
-
});
|
|
88
108
|
});
|
|
89
109
|
|
|
90
|
-
it('
|
|
110
|
+
it('renders the search bar', async () => {
|
|
91
111
|
mockUseAddressHierarchy.mockReturnValue({
|
|
92
112
|
addresses: [],
|
|
93
113
|
error: null,
|
|
94
114
|
isLoading: false,
|
|
95
115
|
});
|
|
96
116
|
|
|
97
|
-
|
|
117
|
+
await renderAddressSearchWithFormik();
|
|
98
118
|
|
|
99
|
-
const searchbox = screen.getByRole('searchbox');
|
|
119
|
+
const searchbox = screen.getByRole('searchbox', { name: /search address/i });
|
|
100
120
|
expect(searchbox).toBeInTheDocument();
|
|
101
121
|
|
|
102
122
|
const ul = screen.queryByRole('list');
|
|
103
123
|
expect(ul).not.toBeInTheDocument();
|
|
104
124
|
});
|
|
105
125
|
|
|
106
|
-
it(
|
|
126
|
+
it('displays search results when user types a search term', async () => {
|
|
107
127
|
const user = userEvent.setup();
|
|
128
|
+
mockUseAddressHierarchy.mockReturnValue({
|
|
129
|
+
addresses: mockedAddressOptions,
|
|
130
|
+
error: null,
|
|
131
|
+
isLoading: false,
|
|
132
|
+
});
|
|
108
133
|
|
|
134
|
+
await renderAddressSearchWithFormik();
|
|
135
|
+
|
|
136
|
+
const searchbox = screen.getByRole('searchbox', { name: /search address/i });
|
|
137
|
+
await user.type(searchbox, 'nea');
|
|
138
|
+
|
|
139
|
+
await waitFor(() => {
|
|
140
|
+
expect(screen.getByRole('list')).toBeInTheDocument();
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
await waitFor(() => {
|
|
144
|
+
expect(screen.getAllByRole('listitem').length).toBeGreaterThan(0);
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it('updates form values when user selects an address option', async () => {
|
|
149
|
+
const user = userEvent.setup();
|
|
109
150
|
mockUseAddressHierarchy.mockReturnValue({
|
|
110
151
|
addresses: mockedAddressOptions,
|
|
111
152
|
error: null,
|
|
112
153
|
isLoading: false,
|
|
113
154
|
});
|
|
114
155
|
|
|
115
|
-
|
|
156
|
+
const { getFormValues } = await renderAddressSearchWithFormik();
|
|
116
157
|
|
|
117
|
-
const
|
|
118
|
-
|
|
119
|
-
const options: Set<string> = new Set();
|
|
158
|
+
const searchbox = screen.getByRole('searchbox', { name: /search address/i });
|
|
159
|
+
await user.type(searchbox, 'nea');
|
|
120
160
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
if (val.toLowerCase().includes(searchString.toLowerCase())) {
|
|
125
|
-
options.add(values.slice(0, index + 1).join(separator));
|
|
126
|
-
}
|
|
127
|
-
});
|
|
161
|
+
// Wait for results to appear
|
|
162
|
+
await waitFor(() => {
|
|
163
|
+
expect(screen.getByRole('list')).toBeInTheDocument();
|
|
128
164
|
});
|
|
129
165
|
|
|
130
|
-
|
|
131
|
-
addressOptions.
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
166
|
+
// Find and click an address option
|
|
167
|
+
const addressOptions = screen.getAllByRole('listitem');
|
|
168
|
+
const firstOption = addressOptions[0];
|
|
169
|
+
const addressText = firstOption.textContent || '';
|
|
170
|
+
|
|
171
|
+
await user.click(firstOption);
|
|
172
|
+
|
|
173
|
+
// Verify form values were updated
|
|
174
|
+
const addressValues = addressText.split(' > ');
|
|
175
|
+
for (let index = 0; index < allFields.length; index++) {
|
|
176
|
+
const { name } = allFields[index];
|
|
177
|
+
await waitFor(() => {
|
|
178
|
+
const formValues = getFormValues();
|
|
179
|
+
expect(formValues.address[name]).toBe(addressValues[index] || '');
|
|
138
180
|
});
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
it('clears search results when user clicks outside the component', async () => {
|
|
185
|
+
const user = userEvent.setup();
|
|
186
|
+
mockUseAddressHierarchy.mockReturnValue({
|
|
187
|
+
addresses: mockedAddressOptions,
|
|
188
|
+
error: null,
|
|
189
|
+
isLoading: false,
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
await renderAddressSearchWithFormik();
|
|
193
|
+
|
|
194
|
+
const searchbox = screen.getByRole('searchbox', { name: /search address/i });
|
|
195
|
+
await user.type(searchbox, 'nea');
|
|
196
|
+
|
|
197
|
+
await waitFor(() => {
|
|
198
|
+
expect(screen.getByRole('list')).toBeInTheDocument();
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
// Mock empty addresses when searchString is cleared
|
|
202
|
+
mockUseAddressHierarchy.mockReturnValue({
|
|
203
|
+
addresses: [],
|
|
204
|
+
error: null,
|
|
205
|
+
isLoading: false,
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
// Click outside - component listens for mousedown events
|
|
209
|
+
fireEvent.mouseDown(document.body);
|
|
210
|
+
|
|
211
|
+
await waitFor(() => {
|
|
212
|
+
expect(screen.queryByRole('list')).not.toBeInTheDocument();
|
|
213
|
+
});
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
it('clears search input when an address is selected', async () => {
|
|
217
|
+
const user = userEvent.setup();
|
|
218
|
+
mockUseAddressHierarchy.mockReturnValue({
|
|
219
|
+
addresses: mockedAddressOptions,
|
|
220
|
+
error: null,
|
|
221
|
+
isLoading: false,
|
|
139
222
|
});
|
|
223
|
+
|
|
224
|
+
await renderAddressSearchWithFormik();
|
|
225
|
+
|
|
226
|
+
const searchbox = screen.getByRole('searchbox', { name: /search address/i }) as HTMLInputElement;
|
|
227
|
+
await user.type(searchbox, 'nea');
|
|
228
|
+
|
|
229
|
+
await waitFor(() => {
|
|
230
|
+
expect(screen.getByRole('list')).toBeInTheDocument();
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
const addressOptions = screen.getAllByRole('listitem');
|
|
234
|
+
await user.click(addressOptions[0]);
|
|
235
|
+
|
|
236
|
+
// Search input should be cleared
|
|
237
|
+
await waitFor(() => {
|
|
238
|
+
expect(searchbox.value).toBe('');
|
|
239
|
+
});
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
it('shows a loading message while search results are being fetched', async () => {
|
|
243
|
+
const user = userEvent.setup();
|
|
244
|
+
mockUseAddressHierarchy.mockReturnValue({
|
|
245
|
+
addresses: [],
|
|
246
|
+
error: null,
|
|
247
|
+
isLoading: true,
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
await renderAddressSearchWithFormik();
|
|
251
|
+
|
|
252
|
+
const searchbox = screen.getByRole('searchbox', { name: /search address/i });
|
|
253
|
+
await user.type(searchbox, 'nea');
|
|
254
|
+
|
|
255
|
+
expect(screen.getByText(/searching/i)).toBeInTheDocument();
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
it('shows an error message when the address search fails', async () => {
|
|
259
|
+
const user = userEvent.setup();
|
|
260
|
+
mockUseAddressHierarchy.mockReturnValue({
|
|
261
|
+
addresses: [],
|
|
262
|
+
error: new Error('Network error'),
|
|
263
|
+
isLoading: false,
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
await renderAddressSearchWithFormik();
|
|
267
|
+
|
|
268
|
+
const searchbox = screen.getByRole('searchbox', { name: /search address/i });
|
|
269
|
+
await user.type(searchbox, 'nea');
|
|
270
|
+
|
|
271
|
+
expect(screen.getByText(/error fetching address results/i)).toBeInTheDocument();
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
it('shows a no results message when the search returns no matches', async () => {
|
|
275
|
+
const user = userEvent.setup();
|
|
276
|
+
mockUseAddressHierarchy.mockReturnValue({
|
|
277
|
+
addresses: [],
|
|
278
|
+
error: null,
|
|
279
|
+
isLoading: false,
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
await renderAddressSearchWithFormik();
|
|
283
|
+
|
|
284
|
+
const searchbox = screen.getByRole('searchbox', { name: /search address/i });
|
|
285
|
+
await user.type(searchbox, 'nonexistent');
|
|
286
|
+
|
|
287
|
+
expect(screen.getByText(/no matching addresses found/i)).toBeInTheDocument();
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
it('does not submit the form when pressing Enter in the search field', async () => {
|
|
291
|
+
const user = userEvent.setup();
|
|
292
|
+
const onSubmit = vi.fn();
|
|
293
|
+
|
|
294
|
+
mockUseAddressHierarchy.mockReturnValue({
|
|
295
|
+
addresses: [],
|
|
296
|
+
error: null,
|
|
297
|
+
isLoading: false,
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
const defaultValues = { address: {} };
|
|
301
|
+
const formValuesRef = { ...initialFormValues, ...defaultValues } as FormValues;
|
|
302
|
+
const mockResourcesContextValue = { addressTemplate: mockedAddressTemplate } as unknown as Resources;
|
|
303
|
+
|
|
304
|
+
await renderWithContext(
|
|
305
|
+
<Formik initialValues={defaultValues} onSubmit={onSubmit}>
|
|
306
|
+
<Form>
|
|
307
|
+
<PatientRegistrationContextProvider
|
|
308
|
+
value={{
|
|
309
|
+
identifierTypes: [],
|
|
310
|
+
values: formValuesRef,
|
|
311
|
+
validationSchema: null,
|
|
312
|
+
inEditMode: false,
|
|
313
|
+
setFieldValue: vi.fn() as any,
|
|
314
|
+
setCapturePhotoProps: vi.fn(),
|
|
315
|
+
setFieldTouched: vi.fn().mockResolvedValue(undefined),
|
|
316
|
+
currentPhoto: '',
|
|
317
|
+
isOffline: false,
|
|
318
|
+
initialFormValues: formValuesRef,
|
|
319
|
+
}}>
|
|
320
|
+
<AddressSearchComponent addressLayout={allFields} />
|
|
321
|
+
</PatientRegistrationContextProvider>
|
|
322
|
+
</Form>
|
|
323
|
+
</Formik>,
|
|
324
|
+
ResourcesContextProvider,
|
|
325
|
+
mockResourcesContextValue,
|
|
326
|
+
);
|
|
327
|
+
|
|
328
|
+
const searchbox = screen.getByRole('searchbox', { name: /search address/i });
|
|
329
|
+
await user.type(searchbox, 'test{Enter}');
|
|
330
|
+
|
|
331
|
+
expect(onSubmit).not.toHaveBeenCalled();
|
|
140
332
|
});
|
|
141
333
|
});
|
|
@@ -3,8 +3,8 @@ import classNames from 'classnames';
|
|
|
3
3
|
import { Field } from 'formik';
|
|
4
4
|
import { useTranslation } from 'react-i18next';
|
|
5
5
|
import { Input } from '../../input/basic-input/input/input.component';
|
|
6
|
-
import styles from '../field.scss';
|
|
7
6
|
import { type FieldDefinition } from '../../../config-schema';
|
|
7
|
+
import styles from '../field.scss';
|
|
8
8
|
|
|
9
9
|
export interface AddressFieldProps {
|
|
10
10
|
fieldDefinition: FieldDefinition;
|
|
@@ -59,7 +59,7 @@ export const CauseOfDeathField: React.FC = () => {
|
|
|
59
59
|
id="deathCause"
|
|
60
60
|
invalid={errors.deathCause && touched.deathCause}
|
|
61
61
|
invalidText={errors.deathCause?.message}
|
|
62
|
-
labelText={t('causeOfDeathInputLabel', 'Cause of
|
|
62
|
+
labelText={t('causeOfDeathInputLabel', 'Cause of death')}
|
|
63
63
|
name="deathCause"
|
|
64
64
|
required={required}>
|
|
65
65
|
<SelectItem id="empty-default-option" value={null} text={t('selectAnOption', 'Select an option')} />
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { vi, describe, it, expect, beforeEach } from 'vitest';
|
|
3
|
+
import userEvent from '@testing-library/user-event';
|
|
4
|
+
import { Formik, Form } from 'formik';
|
|
5
|
+
import { render, screen, waitFor } from '@testing-library/react';
|
|
6
|
+
import { getDefaultsFromConfigSchema, useConfig } from '@openmrs/esm-framework';
|
|
7
|
+
import { type RegistrationConfig, esmPatientRegistrationSchema } from '../../../config-schema';
|
|
8
|
+
import { useConceptAnswers } from '../field.resource';
|
|
9
|
+
import { CauseOfDeathField } from './cause-of-death.component';
|
|
10
|
+
import { PatientRegistrationContextProvider } from '../../patient-registration-context';
|
|
11
|
+
import { initialFormValues } from '../../patient-registration.component';
|
|
12
|
+
import { type FormValues } from '../../patient-registration.types';
|
|
13
|
+
|
|
14
|
+
const mockUseConfig = vi.mocked(useConfig<RegistrationConfig>);
|
|
15
|
+
const mockUseConceptAnswers = vi.mocked(useConceptAnswers);
|
|
16
|
+
|
|
17
|
+
vi.mock('../field.resource', async () => ({
|
|
18
|
+
...((await vi.importActual('../field.resource')) as object),
|
|
19
|
+
useConceptAnswers: vi.fn(),
|
|
20
|
+
}));
|
|
21
|
+
|
|
22
|
+
const mockConceptAnswers = [
|
|
23
|
+
{ display: 'Cardiac Arrest', uuid: 'cardiac-uuid' },
|
|
24
|
+
{ display: 'Pneumonia', uuid: 'pneumonia-uuid' },
|
|
25
|
+
{ display: 'Other', uuid: 'other-uuid' },
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Helper to render CauseOfDeathField with Formik render props for state-dependent tests.
|
|
30
|
+
*/
|
|
31
|
+
const renderCauseOfDeathFieldWithFormik = (
|
|
32
|
+
initialValues: Partial<FormValues> = {},
|
|
33
|
+
options?: { enableReinitialize?: boolean },
|
|
34
|
+
) => {
|
|
35
|
+
const defaultValues = {
|
|
36
|
+
deathCause: '',
|
|
37
|
+
nonCodedCauseOfDeath: '',
|
|
38
|
+
...initialValues,
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
let formValuesRef: FormValues = { ...initialFormValues, ...defaultValues } as FormValues;
|
|
42
|
+
|
|
43
|
+
const utils = render(
|
|
44
|
+
<Formik initialValues={defaultValues} onSubmit={() => {}} enableReinitialize={options?.enableReinitialize}>
|
|
45
|
+
{({ setFieldValue, values, setFieldTouched }) => {
|
|
46
|
+
formValuesRef = { ...initialFormValues, ...values } as FormValues;
|
|
47
|
+
return (
|
|
48
|
+
<Form>
|
|
49
|
+
<PatientRegistrationContextProvider
|
|
50
|
+
value={{
|
|
51
|
+
identifierTypes: [],
|
|
52
|
+
values: formValuesRef,
|
|
53
|
+
validationSchema: null,
|
|
54
|
+
inEditMode: false,
|
|
55
|
+
setFieldValue: setFieldValue as any,
|
|
56
|
+
setCapturePhotoProps: vi.fn(),
|
|
57
|
+
setFieldTouched: setFieldTouched as any,
|
|
58
|
+
currentPhoto: '',
|
|
59
|
+
isOffline: false,
|
|
60
|
+
initialFormValues: formValuesRef,
|
|
61
|
+
}}>
|
|
62
|
+
<CauseOfDeathField />
|
|
63
|
+
</PatientRegistrationContextProvider>
|
|
64
|
+
</Form>
|
|
65
|
+
);
|
|
66
|
+
}}
|
|
67
|
+
</Formik>,
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
return {
|
|
71
|
+
...utils,
|
|
72
|
+
getFormValues: () => formValuesRef,
|
|
73
|
+
};
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
describe('CauseOfDeathField', () => {
|
|
77
|
+
beforeEach(() => {
|
|
78
|
+
mockUseConfig.mockReturnValue({
|
|
79
|
+
...getDefaultsFromConfigSchema(esmPatientRegistrationSchema),
|
|
80
|
+
fieldConfigurations: {
|
|
81
|
+
causeOfDeath: {
|
|
82
|
+
conceptUuid: 'cause-of-death-uuid',
|
|
83
|
+
required: false,
|
|
84
|
+
},
|
|
85
|
+
} as RegistrationConfig['fieldConfigurations'],
|
|
86
|
+
freeTextFieldConceptUuid: 'other-uuid',
|
|
87
|
+
} as RegistrationConfig);
|
|
88
|
+
mockUseConceptAnswers.mockReturnValue({
|
|
89
|
+
data: mockConceptAnswers,
|
|
90
|
+
isLoading: false,
|
|
91
|
+
error: null,
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it('renders the cause of death field with label', () => {
|
|
96
|
+
renderCauseOfDeathFieldWithFormik();
|
|
97
|
+
|
|
98
|
+
expect(screen.getByRole('heading', { name: /cause of death/i })).toBeInTheDocument();
|
|
99
|
+
expect(screen.getByRole('combobox', { name: /cause of death/i })).toBeInTheDocument();
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it('displays loading skeleton when concept answers are loading', () => {
|
|
103
|
+
mockUseConceptAnswers.mockReturnValue({
|
|
104
|
+
data: null,
|
|
105
|
+
isLoading: true,
|
|
106
|
+
error: null,
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
renderCauseOfDeathFieldWithFormik();
|
|
110
|
+
|
|
111
|
+
// SelectSkeleton renders as a skeleton element, check for the skeleton class
|
|
112
|
+
expect(screen.getByText(/cause of death/i)).toBeInTheDocument();
|
|
113
|
+
expect(screen.queryByRole('combobox')).not.toBeInTheDocument();
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it('displays error notification when concept UUID is not configured', () => {
|
|
117
|
+
mockUseConfig.mockReturnValue({
|
|
118
|
+
...getDefaultsFromConfigSchema(esmPatientRegistrationSchema),
|
|
119
|
+
fieldConfigurations: {
|
|
120
|
+
causeOfDeath: {
|
|
121
|
+
conceptUuid: null,
|
|
122
|
+
required: false,
|
|
123
|
+
},
|
|
124
|
+
} as RegistrationConfig['fieldConfigurations'],
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
renderCauseOfDeathFieldWithFormik();
|
|
128
|
+
|
|
129
|
+
expect(screen.getByText(/error fetching coded causes of death/i)).toBeInTheDocument();
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it('displays error notification when there is an error loading concept answers', () => {
|
|
133
|
+
mockUseConceptAnswers.mockReturnValue({
|
|
134
|
+
data: null,
|
|
135
|
+
isLoading: false,
|
|
136
|
+
error: new Error('Failed to load'),
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
renderCauseOfDeathFieldWithFormik();
|
|
140
|
+
|
|
141
|
+
expect(screen.getByText(/error fetching coded causes of death/i)).toBeInTheDocument();
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
describe('Cause of death selection', () => {
|
|
145
|
+
it('renders all available cause of death options', () => {
|
|
146
|
+
renderCauseOfDeathFieldWithFormik();
|
|
147
|
+
|
|
148
|
+
expect(screen.getByRole('option', { name: /cardiac arrest/i })).toBeInTheDocument();
|
|
149
|
+
expect(screen.getByRole('option', { name: /pneumonia/i })).toBeInTheDocument();
|
|
150
|
+
expect(screen.getByRole('option', { name: /other/i })).toBeInTheDocument();
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
it('updates form value when user selects a cause of death', async () => {
|
|
154
|
+
const user = userEvent.setup();
|
|
155
|
+
const { getFormValues } = renderCauseOfDeathFieldWithFormik();
|
|
156
|
+
|
|
157
|
+
const select = screen.getByRole('combobox', { name: /cause of death/i }) as HTMLSelectElement;
|
|
158
|
+
await user.selectOptions(select, 'cardiac-uuid');
|
|
159
|
+
|
|
160
|
+
await waitFor(() => {
|
|
161
|
+
expect(getFormValues().deathCause).toBe('cardiac-uuid');
|
|
162
|
+
});
|
|
163
|
+
expect(select.value).toBe('cardiac-uuid');
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
it('shows non-coded cause of death input when "Other" is selected', async () => {
|
|
167
|
+
const user = userEvent.setup();
|
|
168
|
+
const { getFormValues } = renderCauseOfDeathFieldWithFormik();
|
|
169
|
+
|
|
170
|
+
const select = screen.getByRole('combobox', { name: /cause of death/i }) as HTMLSelectElement;
|
|
171
|
+
await user.selectOptions(select, 'other-uuid');
|
|
172
|
+
|
|
173
|
+
await waitFor(() => {
|
|
174
|
+
expect(getFormValues().deathCause).toBe('other-uuid');
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
await waitFor(() => {
|
|
178
|
+
expect(screen.getByRole('textbox', { name: /non-coded cause of death/i })).toBeInTheDocument();
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
it('hides non-coded cause of death input when non-other option is selected', async () => {
|
|
183
|
+
const user = userEvent.setup();
|
|
184
|
+
const { getFormValues } = renderCauseOfDeathFieldWithFormik(
|
|
185
|
+
{ deathCause: 'other-uuid' },
|
|
186
|
+
{ enableReinitialize: true },
|
|
187
|
+
);
|
|
188
|
+
|
|
189
|
+
// Wait for non-coded input to appear (component checks deathCause.value)
|
|
190
|
+
await waitFor(() => {
|
|
191
|
+
expect(screen.getByRole('textbox', { name: /non-coded cause of death/i })).toBeInTheDocument();
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
// Select a different option
|
|
195
|
+
const select = screen.getByRole('combobox', { name: /cause of death/i }) as HTMLSelectElement;
|
|
196
|
+
await user.selectOptions(select, 'cardiac-uuid');
|
|
197
|
+
|
|
198
|
+
await waitFor(() => {
|
|
199
|
+
expect(getFormValues().deathCause).toBe('cardiac-uuid');
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
// Non-coded input should be hidden
|
|
203
|
+
await waitFor(() => {
|
|
204
|
+
expect(screen.queryByRole('textbox', { name: /non-coded cause of death/i })).not.toBeInTheDocument();
|
|
205
|
+
});
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
it('allows user to enter non-coded cause of death text', async () => {
|
|
209
|
+
const user = userEvent.setup();
|
|
210
|
+
const { getFormValues } = renderCauseOfDeathFieldWithFormik(
|
|
211
|
+
{ deathCause: 'other-uuid' },
|
|
212
|
+
{ enableReinitialize: true },
|
|
213
|
+
);
|
|
214
|
+
|
|
215
|
+
// Wait for non-coded input to appear
|
|
216
|
+
const textInput = await screen.findByRole('textbox', { name: /non-coded cause of death/i });
|
|
217
|
+
await user.type(textInput, 'Unknown cause');
|
|
218
|
+
|
|
219
|
+
await waitFor(() => {
|
|
220
|
+
expect(getFormValues().nonCodedCauseOfDeath).toBe('Unknown cause');
|
|
221
|
+
});
|
|
222
|
+
});
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
describe('Required field', () => {
|
|
226
|
+
it('renders as required when configured', () => {
|
|
227
|
+
mockUseConfig.mockReturnValue({
|
|
228
|
+
...getDefaultsFromConfigSchema(esmPatientRegistrationSchema),
|
|
229
|
+
fieldConfigurations: {
|
|
230
|
+
causeOfDeath: {
|
|
231
|
+
conceptUuid: 'cause-of-death-uuid',
|
|
232
|
+
required: true,
|
|
233
|
+
},
|
|
234
|
+
} as RegistrationConfig['fieldConfigurations'],
|
|
235
|
+
freeTextFieldConceptUuid: 'other-uuid',
|
|
236
|
+
} as RegistrationConfig);
|
|
237
|
+
|
|
238
|
+
renderCauseOfDeathFieldWithFormik();
|
|
239
|
+
|
|
240
|
+
const select = screen.getByRole('combobox', { name: /cause of death/i });
|
|
241
|
+
expect(select).toBeRequired();
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
it('renders as optional when not required', () => {
|
|
245
|
+
renderCauseOfDeathFieldWithFormik();
|
|
246
|
+
|
|
247
|
+
const select = screen.getByRole('combobox', { name: /cause of death/i });
|
|
248
|
+
expect(select).not.toBeRequired();
|
|
249
|
+
});
|
|
250
|
+
});
|
|
251
|
+
});
|
|
@@ -11,7 +11,7 @@ export interface CustomFieldProps {
|
|
|
11
11
|
|
|
12
12
|
export function CustomField({ name }: CustomFieldProps) {
|
|
13
13
|
const config = useConfig<RegistrationConfig>();
|
|
14
|
-
const fieldDefinition = config.fieldDefinitions.filter((def) => def.id
|
|
14
|
+
const fieldDefinition = config.fieldDefinitions.filter((def) => def.id === name)[0];
|
|
15
15
|
|
|
16
16
|
if (fieldDefinition.type === 'person attribute') {
|
|
17
17
|
return <PersonAttributeField fieldDefinition={fieldDefinition} />;
|
package/src/patient-registration/field/date-and-time-of-death/date-and-time-of-death.component.tsx
CHANGED
|
@@ -14,7 +14,7 @@ export const DateAndTimeOfDeathField: React.FC = () => {
|
|
|
14
14
|
|
|
15
15
|
return (
|
|
16
16
|
<div className={classNames(styles.dodField, styles.halfWidthInDesktopView)}>
|
|
17
|
-
<h4 className={styles.productiveHeading02Light}>{t('deathDateInputLabel', 'Date of
|
|
17
|
+
<h4 className={styles.productiveHeading02Light}>{t('deathDateInputLabel', 'Date of death')}</h4>
|
|
18
18
|
<span>
|
|
19
19
|
<DeathDateField />
|
|
20
20
|
<DeathTimeField />
|