@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
|
@@ -0,0 +1,144 @@
|
|
|
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, fireEvent } from '@testing-library/react';
|
|
6
|
+
import { getDefaultsFromConfigSchema, useConfig } from '@openmrs/esm-framework';
|
|
7
|
+
import { type RegistrationConfig, esmPatientRegistrationSchema } from '../../../config-schema';
|
|
8
|
+
import { PatientRegistrationContextProvider } from '../../patient-registration-context';
|
|
9
|
+
import { initialFormValues } from '../../patient-registration.component';
|
|
10
|
+
import { DateAndTimeOfDeathField } from './date-and-time-of-death.component';
|
|
11
|
+
import { type FormValues } from '../../patient-registration.types';
|
|
12
|
+
|
|
13
|
+
const mockUseConfig = vi.mocked(useConfig<RegistrationConfig>);
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Helper to render DateAndTimeOfDeathField with Formik render props for state-dependent tests.
|
|
17
|
+
*/
|
|
18
|
+
const renderDateAndTimeOfDeathFieldWithFormik = (
|
|
19
|
+
initialValues: Partial<FormValues> = {},
|
|
20
|
+
options?: { enableReinitialize?: boolean },
|
|
21
|
+
) => {
|
|
22
|
+
const defaultValues = {
|
|
23
|
+
deathDate: '',
|
|
24
|
+
deathTime: '',
|
|
25
|
+
deathTimeFormat: 'AM' as const,
|
|
26
|
+
isDead: false,
|
|
27
|
+
...initialValues,
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
let formValuesRef: FormValues = { ...initialFormValues, ...defaultValues } as FormValues;
|
|
31
|
+
|
|
32
|
+
const utils = render(
|
|
33
|
+
<Formik initialValues={defaultValues} onSubmit={() => {}} enableReinitialize={options?.enableReinitialize}>
|
|
34
|
+
{({ setFieldValue, values, setFieldTouched }) => {
|
|
35
|
+
formValuesRef = { ...initialFormValues, ...values } as FormValues;
|
|
36
|
+
return (
|
|
37
|
+
<Form>
|
|
38
|
+
<PatientRegistrationContextProvider
|
|
39
|
+
value={{
|
|
40
|
+
identifierTypes: [],
|
|
41
|
+
values: formValuesRef,
|
|
42
|
+
validationSchema: null,
|
|
43
|
+
inEditMode: false,
|
|
44
|
+
setFieldValue: setFieldValue as any,
|
|
45
|
+
setCapturePhotoProps: vi.fn(),
|
|
46
|
+
setFieldTouched: setFieldTouched as any,
|
|
47
|
+
currentPhoto: '',
|
|
48
|
+
isOffline: false,
|
|
49
|
+
initialFormValues: formValuesRef,
|
|
50
|
+
}}>
|
|
51
|
+
<DateAndTimeOfDeathField />
|
|
52
|
+
</PatientRegistrationContextProvider>
|
|
53
|
+
</Form>
|
|
54
|
+
);
|
|
55
|
+
}}
|
|
56
|
+
</Formik>,
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
return {
|
|
60
|
+
...utils,
|
|
61
|
+
getFormValues: () => formValuesRef,
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
describe('DateAndTimeOfDeathField', () => {
|
|
66
|
+
beforeEach(() => {
|
|
67
|
+
mockUseConfig.mockReturnValue({
|
|
68
|
+
...getDefaultsFromConfigSchema(esmPatientRegistrationSchema),
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it('renders the date and time of death field with label', () => {
|
|
73
|
+
renderDateAndTimeOfDeathFieldWithFormik();
|
|
74
|
+
|
|
75
|
+
expect(screen.getByRole('heading', { name: /date of death/i })).toBeInTheDocument();
|
|
76
|
+
expect(screen.getByLabelText(/date of death/i)).toBeInTheDocument();
|
|
77
|
+
expect(screen.getByLabelText(/time of death/i)).toBeInTheDocument();
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
describe('Date of death', () => {
|
|
81
|
+
it('sets death date when user enters a date', async () => {
|
|
82
|
+
const { getFormValues } = renderDateAndTimeOfDeathFieldWithFormik({ isDead: true });
|
|
83
|
+
|
|
84
|
+
const dateInput = screen.getByLabelText(/date of death/i) as HTMLInputElement;
|
|
85
|
+
const deathDateString = '2020-01-15';
|
|
86
|
+
|
|
87
|
+
fireEvent.change(dateInput, { target: { value: deathDateString } });
|
|
88
|
+
fireEvent.blur(dateInput);
|
|
89
|
+
|
|
90
|
+
await waitFor(() => {
|
|
91
|
+
expect(getFormValues().deathDate).toBeTruthy();
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it('renders date picker when isDead is true', () => {
|
|
96
|
+
renderDateAndTimeOfDeathFieldWithFormik({ isDead: true });
|
|
97
|
+
|
|
98
|
+
// Verify date picker is rendered (OpenmrsDatePicker uses isRequired prop, not HTML required attribute)
|
|
99
|
+
const dateInput = screen.getByLabelText(/date of death/i);
|
|
100
|
+
expect(dateInput).toBeInTheDocument();
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it('renders date picker when isDead is false', () => {
|
|
104
|
+
renderDateAndTimeOfDeathFieldWithFormik({ isDead: false });
|
|
105
|
+
|
|
106
|
+
const dateInput = screen.getByLabelText(/date of death/i);
|
|
107
|
+
expect(dateInput).toBeInTheDocument();
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
describe('Time of death', () => {
|
|
112
|
+
it('allows user to enter time of death', async () => {
|
|
113
|
+
const user = userEvent.setup();
|
|
114
|
+
const { getFormValues } = renderDateAndTimeOfDeathFieldWithFormik();
|
|
115
|
+
|
|
116
|
+
const timeInput = screen.getByLabelText(/time of death/i) as HTMLInputElement;
|
|
117
|
+
await user.type(timeInput, '10:30');
|
|
118
|
+
|
|
119
|
+
await waitFor(() => {
|
|
120
|
+
expect(getFormValues().deathTime).toBe('10:30');
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it('allows user to select AM/PM format', async () => {
|
|
125
|
+
const user = userEvent.setup();
|
|
126
|
+
const { getFormValues } = renderDateAndTimeOfDeathFieldWithFormik();
|
|
127
|
+
|
|
128
|
+
// TimePickerSelect uses aria-label, find by that
|
|
129
|
+
const formatSelect = screen.getByLabelText(/time format/i) as HTMLSelectElement;
|
|
130
|
+
await user.selectOptions(formatSelect, 'PM');
|
|
131
|
+
|
|
132
|
+
await waitFor(() => {
|
|
133
|
+
expect(getFormValues().deathTimeFormat).toBe('PM');
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it('displays the initial time format value correctly', () => {
|
|
138
|
+
renderDateAndTimeOfDeathFieldWithFormik({ deathTimeFormat: 'PM' });
|
|
139
|
+
|
|
140
|
+
const formatSelect = screen.getByLabelText(/time format/i) as HTMLSelectElement;
|
|
141
|
+
expect(formatSelect.value).toBe('PM');
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
});
|
|
@@ -96,8 +96,8 @@ export const DobField: React.FC = () => {
|
|
|
96
96
|
<span className={styles.label01}>{t('dobToggleLabelText', 'Date of birth known?')}</span>
|
|
97
97
|
</div>
|
|
98
98
|
<ContentSwitcher size="md" onChange={onToggle} selectedIndex={dobUnknown ? 1 : 0}>
|
|
99
|
-
<Switch name="known"
|
|
100
|
-
<Switch name="unknown"
|
|
99
|
+
<Switch name="known">{t('yes', 'Yes')}</Switch>
|
|
100
|
+
<Switch name="unknown">{t('no', 'No')}</Switch>
|
|
101
101
|
</ContentSwitcher>
|
|
102
102
|
</div>
|
|
103
103
|
)}
|
|
@@ -1,14 +1,102 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
import { vi, describe, it, expect, test, beforeEach } from 'vitest';
|
|
2
3
|
import { Formik, Form } from 'formik';
|
|
3
|
-
import { render, screen } from '@testing-library/react';
|
|
4
|
+
import { render, screen, waitFor, fireEvent } from '@testing-library/react';
|
|
4
5
|
import userEvent from '@testing-library/user-event';
|
|
5
6
|
import { getDefaultsFromConfigSchema, useConfig } from '@openmrs/esm-framework';
|
|
6
7
|
import { type RegistrationConfig, esmPatientRegistrationSchema } from '../../../config-schema';
|
|
7
8
|
import { PatientRegistrationContextProvider } from '../../patient-registration-context';
|
|
8
9
|
import { initialFormValues } from '../../patient-registration.component';
|
|
9
10
|
import { DobField } from './dob.component';
|
|
11
|
+
import { type FormValues } from '../../patient-registration.types';
|
|
10
12
|
|
|
11
|
-
const mockUseConfig =
|
|
13
|
+
const mockUseConfig = vi.mocked(useConfig<RegistrationConfig>);
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Helper to render DobField with Formik render props for state-dependent tests.
|
|
17
|
+
* Returns the render result and a ref to access form values.
|
|
18
|
+
*/
|
|
19
|
+
const renderDobFieldWithFormik = (
|
|
20
|
+
initialValues: Partial<FormValues> = {},
|
|
21
|
+
options?: { enableReinitialize?: boolean },
|
|
22
|
+
) => {
|
|
23
|
+
const defaultValues = {
|
|
24
|
+
birthdate: '',
|
|
25
|
+
birthdateEstimated: false,
|
|
26
|
+
yearsEstimated: 0,
|
|
27
|
+
monthsEstimated: 0,
|
|
28
|
+
...initialValues,
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
let formValuesRef: FormValues = { ...initialFormValues, ...defaultValues } as FormValues;
|
|
32
|
+
|
|
33
|
+
const utils = render(
|
|
34
|
+
<Formik initialValues={defaultValues} onSubmit={() => {}} enableReinitialize={options?.enableReinitialize}>
|
|
35
|
+
{({ setFieldValue, values, setFieldTouched }) => {
|
|
36
|
+
formValuesRef = { ...initialFormValues, ...values } as FormValues;
|
|
37
|
+
return (
|
|
38
|
+
<Form>
|
|
39
|
+
<PatientRegistrationContextProvider
|
|
40
|
+
value={{
|
|
41
|
+
identifierTypes: [],
|
|
42
|
+
values: formValuesRef,
|
|
43
|
+
validationSchema: null,
|
|
44
|
+
inEditMode: false,
|
|
45
|
+
setFieldValue: setFieldValue as any,
|
|
46
|
+
setCapturePhotoProps: vi.fn(),
|
|
47
|
+
setFieldTouched: setFieldTouched as any,
|
|
48
|
+
currentPhoto: '',
|
|
49
|
+
isOffline: false,
|
|
50
|
+
initialFormValues: formValuesRef,
|
|
51
|
+
}}>
|
|
52
|
+
<DobField />
|
|
53
|
+
</PatientRegistrationContextProvider>
|
|
54
|
+
</Form>
|
|
55
|
+
);
|
|
56
|
+
}}
|
|
57
|
+
</Formik>,
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
return {
|
|
61
|
+
...utils,
|
|
62
|
+
getFormValues: () => formValuesRef,
|
|
63
|
+
};
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Helper to render DobField with mocked Formik functions (for simple rendering tests).
|
|
68
|
+
*/
|
|
69
|
+
const renderDobField = (initialValues: Partial<FormValues> = {}) => {
|
|
70
|
+
const defaultValues = {
|
|
71
|
+
birthdate: '',
|
|
72
|
+
birthdateEstimated: false,
|
|
73
|
+
yearsEstimated: 0,
|
|
74
|
+
monthsEstimated: 0,
|
|
75
|
+
...initialValues,
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
return render(
|
|
79
|
+
<Formik initialValues={defaultValues} onSubmit={() => {}}>
|
|
80
|
+
<Form>
|
|
81
|
+
<PatientRegistrationContextProvider
|
|
82
|
+
value={{
|
|
83
|
+
identifierTypes: [],
|
|
84
|
+
values: { ...initialFormValues, ...defaultValues } as FormValues,
|
|
85
|
+
validationSchema: null,
|
|
86
|
+
inEditMode: false,
|
|
87
|
+
setFieldValue: vi.fn().mockResolvedValue(undefined),
|
|
88
|
+
setCapturePhotoProps: vi.fn(),
|
|
89
|
+
setFieldTouched: vi.fn().mockResolvedValue(undefined),
|
|
90
|
+
currentPhoto: '',
|
|
91
|
+
isOffline: false,
|
|
92
|
+
initialFormValues: { ...initialFormValues, ...defaultValues } as FormValues,
|
|
93
|
+
}}>
|
|
94
|
+
<DobField />
|
|
95
|
+
</PatientRegistrationContextProvider>
|
|
96
|
+
</Form>
|
|
97
|
+
</Formik>,
|
|
98
|
+
);
|
|
99
|
+
};
|
|
12
100
|
|
|
13
101
|
describe('Dob', () => {
|
|
14
102
|
beforeEach(() => {
|
|
@@ -24,27 +112,7 @@ describe('Dob', () => {
|
|
|
24
112
|
});
|
|
25
113
|
|
|
26
114
|
it('renders the fields in the birth section of the registration form', async () => {
|
|
27
|
-
|
|
28
|
-
<Formik initialValues={{ birthdate: '' }} onSubmit={() => {}}>
|
|
29
|
-
<Form>
|
|
30
|
-
<PatientRegistrationContextProvider
|
|
31
|
-
value={{
|
|
32
|
-
identifierTypes: [],
|
|
33
|
-
values: initialFormValues,
|
|
34
|
-
validationSchema: null,
|
|
35
|
-
inEditMode: false,
|
|
36
|
-
setFieldValue: () => {},
|
|
37
|
-
setCapturePhotoProps: (value) => {},
|
|
38
|
-
setFieldTouched: () => {},
|
|
39
|
-
currentPhoto: '',
|
|
40
|
-
isOffline: false,
|
|
41
|
-
initialFormValues: initialFormValues,
|
|
42
|
-
}}>
|
|
43
|
-
<DobField />
|
|
44
|
-
</PatientRegistrationContextProvider>
|
|
45
|
-
</Form>
|
|
46
|
-
</Formik>,
|
|
47
|
-
);
|
|
115
|
+
renderDobField({ birthdate: '' });
|
|
48
116
|
|
|
49
117
|
expect(screen.getByRole('heading', { name: /birth/i })).toBeInTheDocument();
|
|
50
118
|
expect(screen.getByText(/date of birth known?/i)).toBeInTheDocument();
|
|
@@ -55,36 +123,284 @@ describe('Dob', () => {
|
|
|
55
123
|
expect(screen.getByLabelText(/date of birth/i)).toBeInTheDocument();
|
|
56
124
|
});
|
|
57
125
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
126
|
+
describe('Toggle functionality', () => {
|
|
127
|
+
it('shows estimated age inputs when user selects "unknown"', async () => {
|
|
128
|
+
const user = userEvent.setup();
|
|
129
|
+
renderDobFieldWithFormik({ birthdate: '', birthdateEstimated: false, yearsEstimated: 0, monthsEstimated: 0 });
|
|
130
|
+
|
|
131
|
+
await user.click(screen.getByRole('tab', { name: /no/i }));
|
|
132
|
+
|
|
133
|
+
// Wait for UI to update - estimated inputs should appear after state update
|
|
134
|
+
await waitFor(
|
|
135
|
+
() => {
|
|
136
|
+
expect(screen.getByLabelText(/estimated age in years/i)).toBeInTheDocument();
|
|
137
|
+
},
|
|
138
|
+
{ timeout: 2000 },
|
|
139
|
+
);
|
|
140
|
+
expect(screen.getByLabelText(/estimated age in months/i)).toBeInTheDocument();
|
|
141
|
+
expect(screen.queryByLabelText(/date of birth/i)).not.toBeInTheDocument();
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
it('shows date picker when user selects "known"', async () => {
|
|
145
|
+
const user = userEvent.setup();
|
|
146
|
+
renderDobFieldWithFormik({ birthdate: '', birthdateEstimated: true, yearsEstimated: 0, monthsEstimated: 0 });
|
|
147
|
+
|
|
148
|
+
// First verify we're in unknown mode
|
|
149
|
+
expect(screen.getByLabelText(/estimated age in years/i)).toBeInTheDocument();
|
|
150
|
+
|
|
151
|
+
// Switch back to known mode
|
|
152
|
+
await user.click(screen.getByRole('tab', { name: /yes/i }));
|
|
153
|
+
|
|
154
|
+
// Wait for the UI to update - date picker should appear after state update
|
|
155
|
+
await waitFor(
|
|
156
|
+
() => {
|
|
157
|
+
expect(screen.getByLabelText(/date of birth/i)).toBeInTheDocument();
|
|
158
|
+
},
|
|
159
|
+
{ timeout: 2000 },
|
|
160
|
+
);
|
|
161
|
+
expect(screen.queryByLabelText(/estimated age in years/i)).not.toBeInTheDocument();
|
|
162
|
+
expect(screen.queryByLabelText(/estimated age in months/i)).not.toBeInTheDocument();
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
describe('Estimated age input validation', () => {
|
|
167
|
+
it('accepts valid years (0-139)', async () => {
|
|
168
|
+
const user = userEvent.setup();
|
|
169
|
+
renderDobField({ birthdateEstimated: true });
|
|
170
|
+
|
|
171
|
+
const yearsInput = screen.getByLabelText(/estimated age in years/i) as HTMLInputElement;
|
|
172
|
+
await user.clear(yearsInput);
|
|
173
|
+
await user.type(yearsInput, '25');
|
|
174
|
+
|
|
175
|
+
expect(yearsInput.value).toBe('25');
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
it('accepts boundary value 0 for years', async () => {
|
|
179
|
+
const user = userEvent.setup();
|
|
180
|
+
const { getFormValues } = renderDobFieldWithFormik({ birthdateEstimated: true, yearsEstimated: 25 });
|
|
181
|
+
|
|
182
|
+
const yearsInput = screen.getByLabelText(/estimated age in years/i) as HTMLInputElement;
|
|
183
|
+
await user.clear(yearsInput);
|
|
184
|
+
await user.type(yearsInput, '0');
|
|
185
|
+
|
|
186
|
+
await waitFor(() => {
|
|
187
|
+
expect(yearsInput.value).toBe('0');
|
|
188
|
+
});
|
|
189
|
+
expect(getFormValues().yearsEstimated).toBe(0);
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
it('accepts boundary value 139 for years', async () => {
|
|
193
|
+
const user = userEvent.setup();
|
|
194
|
+
const { getFormValues } = renderDobFieldWithFormik({ birthdateEstimated: true });
|
|
195
|
+
|
|
196
|
+
const yearsInput = screen.getByLabelText(/estimated age in years/i) as HTMLInputElement;
|
|
197
|
+
await user.clear(yearsInput);
|
|
198
|
+
await user.type(yearsInput, '139');
|
|
199
|
+
|
|
200
|
+
await waitFor(() => {
|
|
201
|
+
expect(yearsInput.value).toBe('139');
|
|
202
|
+
});
|
|
203
|
+
expect(getFormValues().yearsEstimated).toBe(139);
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
it('does not update birthdate when years >= 140', async () => {
|
|
207
|
+
const user = userEvent.setup();
|
|
208
|
+
const { getFormValues } = renderDobFieldWithFormik({ birthdateEstimated: true, yearsEstimated: 25 });
|
|
209
|
+
|
|
210
|
+
const yearsInput = screen.getByLabelText(/estimated age in years/i) as HTMLInputElement;
|
|
211
|
+
const initialBirthdate = getFormValues().birthdate;
|
|
212
|
+
await user.clear(yearsInput);
|
|
213
|
+
await user.type(yearsInput, '150');
|
|
214
|
+
|
|
215
|
+
// Component logic only calls setFieldValue for birthdate if years < 140
|
|
216
|
+
// The input value can be 150, but birthdate should not be recalculated
|
|
217
|
+
await waitFor(() => {
|
|
218
|
+
expect(yearsInput.value).toBe('150');
|
|
219
|
+
});
|
|
220
|
+
// Verify birthdate was not recalculated (it should remain unchanged or be cleared)
|
|
221
|
+
const finalBirthdate = getFormValues().birthdate;
|
|
222
|
+
// If birthdate was cleared, it should be empty string, not a Date
|
|
223
|
+
// If it's a Date, it should be the same as initial (or approximately, accounting for time)
|
|
224
|
+
if (initialBirthdate instanceof Date && finalBirthdate instanceof Date) {
|
|
225
|
+
// Birthdate should not have changed significantly (component doesn't recalculate for invalid years)
|
|
226
|
+
const timeDiff = Math.abs(finalBirthdate.getTime() - initialBirthdate.getTime());
|
|
227
|
+
expect(timeDiff).toBeLessThan(1000); // Less than 1 second difference
|
|
228
|
+
}
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
it('does not accept negative values for years', async () => {
|
|
232
|
+
const user = userEvent.setup();
|
|
233
|
+
const { getFormValues } = renderDobFieldWithFormik({ birthdateEstimated: true, yearsEstimated: 25 });
|
|
234
|
+
|
|
235
|
+
const yearsInput = screen.getByLabelText(/estimated age in years/i) as HTMLInputElement;
|
|
236
|
+
const initialBirthdate = getFormValues().birthdate;
|
|
237
|
+
await user.clear(yearsInput);
|
|
238
|
+
await user.type(yearsInput, '-5');
|
|
239
|
+
|
|
240
|
+
// Component logic only calls setFieldValue for birthdate if years >= 0
|
|
241
|
+
// The input value can be -5, but birthdate should not be recalculated
|
|
242
|
+
await waitFor(() => {
|
|
243
|
+
expect(yearsInput.value).toBe('-5');
|
|
244
|
+
});
|
|
245
|
+
// Verify birthdate was not recalculated (it should remain unchanged)
|
|
246
|
+
const finalBirthdate = getFormValues().birthdate;
|
|
247
|
+
if (initialBirthdate instanceof Date && finalBirthdate instanceof Date) {
|
|
248
|
+
// Birthdate should not have changed (component doesn't recalculate for negative years)
|
|
249
|
+
const timeDiff = Math.abs(finalBirthdate.getTime() - initialBirthdate.getTime());
|
|
250
|
+
expect(timeDiff).toBeLessThan(1000); // Less than 1 second difference
|
|
251
|
+
}
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
it('does not accept negative values for months', async () => {
|
|
255
|
+
const user = userEvent.setup();
|
|
256
|
+
const { getFormValues } = renderDobFieldWithFormik({ birthdateEstimated: true, monthsEstimated: 6 });
|
|
257
|
+
|
|
258
|
+
const monthsInput = screen.getByLabelText(/estimated age in months/i) as HTMLInputElement;
|
|
259
|
+
await user.clear(monthsInput);
|
|
260
|
+
await user.type(monthsInput, '-3');
|
|
261
|
+
|
|
262
|
+
// Component logic accepts any number for months (including negative in input)
|
|
263
|
+
// but the calculation may not work correctly with negative
|
|
264
|
+
await waitFor(() => {
|
|
265
|
+
expect(monthsInput.value).toBe('-3');
|
|
266
|
+
});
|
|
267
|
+
// Verify the component handles it (may or may not update form value)
|
|
268
|
+
const formValues = getFormValues();
|
|
269
|
+
expect(typeof formValues.monthsEstimated).toBe('number');
|
|
270
|
+
});
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
describe('Birthdate calculation', () => {
|
|
274
|
+
it('calculates birthdate when user enters estimated years', async () => {
|
|
275
|
+
const user = userEvent.setup();
|
|
276
|
+
const { getFormValues } = renderDobFieldWithFormik(
|
|
277
|
+
{ birthdateEstimated: true, yearsEstimated: 0, monthsEstimated: 0, birthdate: '' },
|
|
278
|
+
{ enableReinitialize: true },
|
|
279
|
+
);
|
|
280
|
+
|
|
281
|
+
const yearsInput = screen.getByLabelText(/estimated age in years/i) as HTMLInputElement;
|
|
282
|
+
|
|
283
|
+
// Clear and type a valid year value
|
|
284
|
+
await user.clear(yearsInput);
|
|
285
|
+
await user.type(yearsInput, '25');
|
|
286
|
+
|
|
287
|
+
// Verify the input accepts the value (observable behavior)
|
|
288
|
+
expect(yearsInput.value).toBe('25');
|
|
289
|
+
|
|
290
|
+
// Wait for form state to update - the birthdate should be calculated
|
|
291
|
+
await waitFor(
|
|
292
|
+
() => {
|
|
293
|
+
const formValues = getFormValues();
|
|
294
|
+
// Wait for either birthdate to be a Date or yearsEstimated to be updated
|
|
295
|
+
expect(formValues.birthdate instanceof Date || formValues.yearsEstimated === 25).toBe(true);
|
|
296
|
+
},
|
|
297
|
+
{ timeout: 1000 },
|
|
298
|
+
);
|
|
299
|
+
|
|
300
|
+
// Verify birthdate was calculated (observable through form values)
|
|
301
|
+
const formValues = getFormValues();
|
|
302
|
+
// The birthdate should be approximately 25 years ago
|
|
303
|
+
if (formValues.birthdate instanceof Date) {
|
|
304
|
+
const yearsDiff = new Date().getFullYear() - formValues.birthdate.getFullYear();
|
|
305
|
+
expect(yearsDiff).toBeGreaterThanOrEqual(24);
|
|
306
|
+
expect(yearsDiff).toBeLessThanOrEqual(26);
|
|
307
|
+
} else {
|
|
308
|
+
// If not a Date yet, at least verify yearsEstimated was updated
|
|
309
|
+
expect(formValues.yearsEstimated).toBe(25);
|
|
310
|
+
}
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
it('calculates birthdate when user enters estimated months', async () => {
|
|
314
|
+
const user = userEvent.setup();
|
|
315
|
+
const { getFormValues } = renderDobFieldWithFormik(
|
|
316
|
+
{ birthdateEstimated: true, yearsEstimated: 25, monthsEstimated: 0, birthdate: '' },
|
|
317
|
+
{ enableReinitialize: true },
|
|
318
|
+
);
|
|
319
|
+
|
|
320
|
+
const monthsInput = screen.getByLabelText(/estimated age in months/i) as HTMLInputElement;
|
|
321
|
+
|
|
322
|
+
// Clear and type a valid month value
|
|
323
|
+
await user.clear(monthsInput);
|
|
324
|
+
await user.type(monthsInput, '6');
|
|
325
|
+
|
|
326
|
+
// Verify the input accepts the value (observable behavior)
|
|
327
|
+
expect(monthsInput.value).toBe('6');
|
|
328
|
+
|
|
329
|
+
// Wait for form state to update - the birthdate should be recalculated with months
|
|
330
|
+
await waitFor(
|
|
331
|
+
() => {
|
|
332
|
+
const formValues = getFormValues();
|
|
333
|
+
// Wait for either birthdate to be a Date or monthsEstimated to be updated
|
|
334
|
+
expect(formValues.birthdate instanceof Date || formValues.monthsEstimated === 6).toBe(true);
|
|
335
|
+
},
|
|
336
|
+
{ timeout: 1000 },
|
|
337
|
+
);
|
|
338
|
+
|
|
339
|
+
// Verify birthdate was recalculated with months included
|
|
340
|
+
const formValues = getFormValues();
|
|
341
|
+
if (formValues.birthdate instanceof Date) {
|
|
342
|
+
const yearsDiff = new Date().getFullYear() - formValues.birthdate.getFullYear();
|
|
343
|
+
// Should be approximately 25 years and 6 months ago
|
|
344
|
+
expect(yearsDiff).toBeGreaterThanOrEqual(24);
|
|
345
|
+
expect(yearsDiff).toBeLessThanOrEqual(26);
|
|
346
|
+
} else {
|
|
347
|
+
// If not a Date yet, at least verify monthsEstimated was updated
|
|
348
|
+
expect(formValues.monthsEstimated).toBe(6);
|
|
349
|
+
}
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
it('normalizes months > 12 into years on blur', async () => {
|
|
353
|
+
const user = userEvent.setup();
|
|
354
|
+
const { getFormValues } = renderDobFieldWithFormik(
|
|
355
|
+
{ birthdateEstimated: true, yearsEstimated: 25, monthsEstimated: 0, birthdate: '' },
|
|
356
|
+
{ enableReinitialize: true },
|
|
357
|
+
);
|
|
358
|
+
|
|
359
|
+
const monthsInput = screen.getByLabelText(/estimated age in months/i) as HTMLInputElement;
|
|
360
|
+
|
|
361
|
+
// Enter 18 months (should normalize to 1 year 6 months)
|
|
362
|
+
await user.clear(monthsInput);
|
|
363
|
+
await user.type(monthsInput, '18');
|
|
364
|
+
|
|
365
|
+
// Trigger blur to activate updateBirthdate normalization
|
|
366
|
+
await user.tab();
|
|
367
|
+
|
|
368
|
+
// Wait for normalization to occur - wait for years to update
|
|
369
|
+
await waitFor(
|
|
370
|
+
() => {
|
|
371
|
+
expect(getFormValues().yearsEstimated).toBe(26);
|
|
372
|
+
},
|
|
373
|
+
{ timeout: 1000 },
|
|
374
|
+
);
|
|
375
|
+
|
|
376
|
+
// Verify months were normalized: 18 months = 1 year 6 months
|
|
377
|
+
expect(getFormValues().monthsEstimated).toBe(6);
|
|
378
|
+
});
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
describe('Date picker interaction', () => {
|
|
382
|
+
it('sets birthdate when user enters a date', async () => {
|
|
383
|
+
const { getFormValues } = renderDobFieldWithFormik(
|
|
384
|
+
{ birthdate: '', birthdateEstimated: false },
|
|
385
|
+
{ enableReinitialize: true },
|
|
386
|
+
);
|
|
387
|
+
|
|
388
|
+
const dateOfBirthInput = screen.getByLabelText(/date of birth/i) as HTMLInputElement;
|
|
389
|
+
const birthDateString = '1993-08-02';
|
|
390
|
+
|
|
391
|
+
// Use fireEvent.change like in patient-registration.test.tsx
|
|
392
|
+
fireEvent.change(dateOfBirthInput, { target: { value: birthDateString } });
|
|
393
|
+
fireEvent.blur(dateOfBirthInput);
|
|
394
|
+
|
|
395
|
+
// Wait for form state to update
|
|
396
|
+
await waitFor(
|
|
397
|
+
() => {
|
|
398
|
+
// Verify birthdate was set (observable through form values)
|
|
399
|
+
// The value might be a Date object or string depending on how OpenmrsDatePicker handles it
|
|
400
|
+
expect(getFormValues().birthdate).toBeTruthy();
|
|
401
|
+
},
|
|
402
|
+
{ timeout: 1000 },
|
|
403
|
+
);
|
|
404
|
+
});
|
|
89
405
|
});
|
|
90
406
|
});
|
|
@@ -19,7 +19,7 @@ export function Field({ name }: FieldProps) {
|
|
|
19
19
|
const config = useConfig<RegistrationConfig>();
|
|
20
20
|
if (
|
|
21
21
|
!(builtInFields as ReadonlyArray<string>).includes(name) &&
|
|
22
|
-
!config.fieldDefinitions.some((def) => def.id
|
|
22
|
+
!config.fieldDefinitions.some((def) => def.id === name)
|
|
23
23
|
) {
|
|
24
24
|
reportError(
|
|
25
25
|
`Invalid field name '${name}'. Valid options are '${config.fieldDefinitions
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useMemo } from 'react';
|
|
2
2
|
import useSWRImmutable from 'swr/immutable';
|
|
3
|
+
import { type FetchResponse, openmrsFetch, restBaseUrl, showSnackbar } from '@openmrs/esm-framework';
|
|
3
4
|
import { type ConceptAnswers, type ConceptResponse } from '../patient-registration.types';
|
|
4
|
-
import { useMemo } from 'react';
|
|
5
5
|
|
|
6
6
|
export function useConcept(conceptUuid: string): { data: ConceptResponse; isLoading: boolean } {
|
|
7
7
|
const shouldFetch = typeof conceptUuid === 'string' && conceptUuid !== '';
|