@kenyaemr/esm-patient-registration-app 4.5.4 → 4.5.5
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/117.js +2 -0
- package/dist/117.js.map +1 -0
- package/dist/130.js +1 -1
- package/dist/130.js.map +1 -1
- package/dist/208.js +1 -1
- package/dist/218.js +1 -0
- package/dist/218.js.map +1 -0
- package/dist/275.js +1 -0
- package/dist/275.js.map +1 -0
- package/dist/319.js +1 -1
- package/dist/{821.js → 348.js} +1 -1
- package/dist/{821.js.map → 348.js.map} +1 -1
- package/dist/574.js +1 -1
- package/dist/68.js +1 -1
- package/dist/68.js.map +1 -1
- package/dist/693.js +1 -0
- package/dist/693.js.map +1 -0
- package/dist/757.js +1 -1
- package/dist/788.js +1 -1
- package/dist/807.js +1 -1
- package/dist/833.js +1 -1
- package/dist/kenyaemr-esm-patient-registration-app.js +1 -1
- package/dist/kenyaemr-esm-patient-registration-app.js.buildmanifest.json +147 -122
- package/dist/kenyaemr-esm-patient-registration-app.js.map +1 -1
- package/dist/main.js +1 -1
- package/dist/main.js.map +1 -1
- package/dist/routes.json +1 -1
- package/jest.config.js +3 -0
- package/package.json +5 -2
- package/src/index.ts +9 -2
- package/src/offline.resources.ts +8 -4
- package/src/offline.ts +1 -1
- package/src/patient-registration/field/__mocks__/field.resource.ts +1 -1
- package/src/patient-registration/field/address/address-field.component.tsx +25 -70
- package/src/patient-registration/field/address/address-hierarchy-levels.component.tsx +11 -9
- package/src/patient-registration/field/address/address-hierarchy.resource.tsx +57 -3
- package/src/patient-registration/field/address/address-search.component.tsx +1 -1
- package/src/patient-registration/field/address/tests/address-hierarchy.test.tsx +137 -63
- package/src/patient-registration/field/address/tests/address-search-component.test.tsx +128 -0
- package/src/patient-registration/field/address/tests/mocks.ts +93 -99
- package/src/patient-registration/field/dob/dob.component.tsx +34 -32
- package/src/patient-registration/field/field.resource.ts +1 -1
- package/src/patient-registration/field/id/id-field.component.tsx +1 -1
- package/src/patient-registration/field/id/identifier-selection-overlay.tsx +1 -1
- package/src/patient-registration/field/name/name-field.component.tsx +0 -1
- package/src/patient-registration/field/obs/obs-field.component.tsx +14 -13
- package/src/patient-registration/field/person-attributes/coded-attributes.component.tsx +1 -1
- package/src/patient-registration/field/person-attributes/coded-person-attribute-field.component.tsx +1 -1
- package/src/patient-registration/field/person-attributes/coded-person-attribute-field.test.tsx +103 -0
- package/src/patient-registration/field/person-attributes/person-attribute-field.test.tsx +187 -0
- package/src/patient-registration/field/person-attributes/person-attributes.resource.tsx +1 -1
- package/src/patient-registration/field/person-attributes/text-person-attribute-field.component.tsx +3 -3
- package/src/patient-registration/field/person-attributes/text-person-attribute-field.test.tsx +88 -0
- package/src/patient-registration/form-manager.test.ts +1 -1
- package/src/patient-registration/form-manager.ts +1 -1
- package/src/patient-registration/input/basic-input/input/input.test.tsx +0 -135
- package/src/patient-registration/input/basic-input/select/select-input.test.tsx +8 -4
- package/src/patient-registration/input/combo-input/combo-input.component.tsx +8 -6
- package/src/patient-registration/input/custom-input/identifier/identifier-input.component.tsx +1 -1
- package/src/patient-registration/input/custom-input/identifier/utils.test.ts +81 -0
- package/src/patient-registration/input/custom-input/identifier/utils.ts +1 -1
- package/src/patient-registration/input/dummy-data/dummy-data-input.component.tsx +1 -1
- package/src/patient-registration/patient-registration-context.ts +1 -1
- package/src/patient-registration/patient-registration-hooks.ts +1 -1
- package/src/patient-registration/patient-registration-utils.ts +1 -1
- package/src/patient-registration/patient-registration.component.tsx +1 -12
- package/src/patient-registration/patient-registration.resource.tsx +1 -72
- package/src/patient-registration/patient-registration.test.tsx +250 -247
- package/src/patient-registration/{patient-registration-types.tsx → patient-registration.types.tsx} +45 -0
- package/src/patient-registration/section/patient-relationships/relationships-section.component.tsx +83 -79
- package/src/patient-registration/section/patient-relationships/relationships-section.test.tsx +88 -0
- package/src/patient-registration/section/patient-relationships/relationships.resource.tsx +1 -1
- package/src/patient-registration/validation/patient-registration-validation.tsx +1 -1
- package/src/patient-verification/patient-verification-hook.tsx +12 -1
- package/src/patient-verification/patient-verification-utils.ts +1 -1
- package/src/patient-verification/patient-verification.component.tsx +1 -1
- package/src/patient-verification/verification-modal/confirm-prompt.component.tsx +11 -0
- package/src/root.component.tsx +1 -1
- package/src/routes.json +62 -51
- package/src/widgets/display-photo.test.tsx +37 -0
- package/src/widgets/edit-patient-details-button.test.tsx +36 -0
- package/translations/am.json +0 -7
- package/translations/en.json +2 -5
- package/translations/es.json +0 -7
- package/translations/fr.json +0 -7
- package/translations/he.json +0 -7
- package/translations/km.json +0 -7
- package/__mocks__/react-i18next.js +0 -49
- package/dist/196.js +0 -1
- package/dist/196.js.map +0 -1
- package/dist/59.js +0 -1
- package/dist/59.js.map +0 -1
- package/dist/9.js +0 -2
- package/dist/9.js.map +0 -1
- /package/dist/{9.js.LICENSE.txt → 117.js.LICENSE.txt} +0 -0
|
@@ -6,7 +6,7 @@ import { useTranslation } from 'react-i18next';
|
|
|
6
6
|
import { Formik, Form, FormikHelpers } from 'formik';
|
|
7
7
|
import { createErrorHandler, showToast, useConfig, interpolateUrl, usePatient } from '@openmrs/esm-framework';
|
|
8
8
|
import { validationSchema as initialSchema } from './validation/patient-registration-validation';
|
|
9
|
-
import { FormValues, CapturePhotoProps, PatientIdentifierValue } from './patient-registration
|
|
9
|
+
import { FormValues, CapturePhotoProps, PatientIdentifierValue } from './patient-registration.types';
|
|
10
10
|
import { PatientRegistrationContext } from './patient-registration-context';
|
|
11
11
|
import { SavePatientForm, SavePatientTransactionManager } from './form-manager';
|
|
12
12
|
import { usePatientPhoto } from './patient-registration.resource';
|
|
@@ -75,17 +75,6 @@ export const PatientRegistration: React.FC<PatientRegistrationProps> = ({ savePa
|
|
|
75
75
|
.filter((s) => s);
|
|
76
76
|
}, [config.sections, config.sectionDefinitions]);
|
|
77
77
|
|
|
78
|
-
useEffect(() => {
|
|
79
|
-
if (addressTemplate) {
|
|
80
|
-
const addressTemplateXml = addressTemplate?.results[0].value;
|
|
81
|
-
if (!addressTemplateXml) {
|
|
82
|
-
return;
|
|
83
|
-
}
|
|
84
|
-
const { addressValidationSchema } = parseAddressTemplateXml(addressTemplateXml);
|
|
85
|
-
setValidationSchema((validationSchema) => validationSchema.concat(addressValidationSchema));
|
|
86
|
-
}
|
|
87
|
-
}, [inEditMode, addressTemplate, initialAddressFieldValues]);
|
|
88
|
-
|
|
89
78
|
const onFormSubmit = async (values: FormValues, helpers: FormikHelpers<FormValues>) => {
|
|
90
79
|
const abortController = new AbortController();
|
|
91
80
|
helpers.setSubmitting(true);
|
|
@@ -2,7 +2,7 @@ import { useMemo } from 'react';
|
|
|
2
2
|
import useSWR from 'swr';
|
|
3
3
|
import useSWRImmutable from 'swr/immutable';
|
|
4
4
|
import { FetchResponse, openmrsFetch, useConfig } from '@openmrs/esm-framework';
|
|
5
|
-
import { Patient, Relationship, PatientIdentifier, Encounter } from './patient-registration
|
|
5
|
+
import { Patient, Relationship, PatientIdentifier, Encounter } from './patient-registration.types';
|
|
6
6
|
|
|
7
7
|
export const uuidIdentifier = '05a29f94-c0ed-11e2-94be-8c13b969e334';
|
|
8
8
|
export const uuidTelephoneNumber = '14d4f066-15f5-102d-96e4-000c29c2a5d7';
|
|
@@ -223,74 +223,3 @@ export async function deletePatientIdentifier(patientUuid: string, patientIdenti
|
|
|
223
223
|
signal: abortController.signal,
|
|
224
224
|
});
|
|
225
225
|
}
|
|
226
|
-
|
|
227
|
-
export function useAddressHierarchy(
|
|
228
|
-
searchString,
|
|
229
|
-
separator,
|
|
230
|
-
): {
|
|
231
|
-
addresses: Array<string>;
|
|
232
|
-
isLoading: boolean;
|
|
233
|
-
error: Error;
|
|
234
|
-
} {
|
|
235
|
-
const { data, error, isLoading } = useSWRImmutable<
|
|
236
|
-
FetchResponse<
|
|
237
|
-
Array<{
|
|
238
|
-
address: string;
|
|
239
|
-
}>
|
|
240
|
-
>,
|
|
241
|
-
Error
|
|
242
|
-
>(
|
|
243
|
-
searchString
|
|
244
|
-
? `/module/addresshierarchy/ajax/getPossibleFullAddresses.form?separator=${separator}&searchString=${searchString}`
|
|
245
|
-
: null,
|
|
246
|
-
openmrsFetch,
|
|
247
|
-
);
|
|
248
|
-
|
|
249
|
-
const results = useMemo(
|
|
250
|
-
() => ({
|
|
251
|
-
addresses: data?.data?.map((address) => address.address) ?? [],
|
|
252
|
-
error,
|
|
253
|
-
isLoading,
|
|
254
|
-
}),
|
|
255
|
-
[data?.data, error, isLoading],
|
|
256
|
-
);
|
|
257
|
-
return results;
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
export function useAdressHierarchyWithParentSearch(
|
|
261
|
-
addressField,
|
|
262
|
-
parentid,
|
|
263
|
-
query,
|
|
264
|
-
): {
|
|
265
|
-
error: Error;
|
|
266
|
-
isLoading: boolean;
|
|
267
|
-
addresses: Array<{
|
|
268
|
-
uuid: string;
|
|
269
|
-
name: string;
|
|
270
|
-
}>;
|
|
271
|
-
} {
|
|
272
|
-
const { data, error, isLoading } = useSWRImmutable<
|
|
273
|
-
FetchResponse<
|
|
274
|
-
Array<{
|
|
275
|
-
uuid: string;
|
|
276
|
-
name: string;
|
|
277
|
-
}>
|
|
278
|
-
>
|
|
279
|
-
>(
|
|
280
|
-
query
|
|
281
|
-
? `/module/addresshierarchy/ajax/getPossibleAddressHierarchyEntriesWithParents.form?addressField=${addressField}&limit=20&searchString=${query}&parentUuid=${parentid}`
|
|
282
|
-
: null,
|
|
283
|
-
openmrsFetch,
|
|
284
|
-
);
|
|
285
|
-
|
|
286
|
-
const results = useMemo(
|
|
287
|
-
() => ({
|
|
288
|
-
error: error,
|
|
289
|
-
isLoading,
|
|
290
|
-
addresses: data?.data ?? [],
|
|
291
|
-
}),
|
|
292
|
-
[data?.data, error, isLoading],
|
|
293
|
-
);
|
|
294
|
-
|
|
295
|
-
return results;
|
|
296
|
-
}
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { BrowserRouter as Router } from 'react-router-dom';
|
|
3
|
-
import { render, screen,
|
|
2
|
+
import { BrowserRouter as Router, useParams } from 'react-router-dom';
|
|
3
|
+
import { render, screen, waitFor, within } from '@testing-library/react';
|
|
4
4
|
import userEvent from '@testing-library/user-event';
|
|
5
5
|
import { showToast, useConfig, usePatient } from '@openmrs/esm-framework';
|
|
6
|
-
import FormManager from './form-manager';
|
|
7
|
-
import { mockPatient } from '../../../../__mocks__/patient.mock';
|
|
6
|
+
import { FormManager } from './form-manager';
|
|
8
7
|
import { saveEncounter, savePatient } from './patient-registration.resource';
|
|
9
8
|
import { Encounter } from './patient-registration-types';
|
|
10
9
|
import { Resources, ResourcesContext } from '../offline.resources';
|
|
11
10
|
import { PatientRegistration } from './patient-registration.component';
|
|
12
11
|
import { RegistrationConfig } from '../config-schema';
|
|
12
|
+
import { mockedAddressTemplate } from './field/address/tests/mocks';
|
|
13
|
+
import { mockPatient } from '../../../../tools/test-helpers';
|
|
13
14
|
|
|
14
15
|
const mockedUseConfig = useConfig as jest.Mock;
|
|
15
16
|
const mockedUsePatient = usePatient as jest.Mock;
|
|
@@ -35,6 +36,7 @@ jest.mock('react-router-dom', () => ({
|
|
|
35
36
|
pathname: 'openmrs/spa/patient-registration',
|
|
36
37
|
}),
|
|
37
38
|
useHistory: () => [],
|
|
39
|
+
useParams: jest.fn().mockReturnValue({ patientUuid: undefined }),
|
|
38
40
|
}));
|
|
39
41
|
|
|
40
42
|
jest.mock('./patient-registration.resource', () => {
|
|
@@ -56,17 +58,8 @@ jest.mock('@openmrs/esm-framework', () => {
|
|
|
56
58
|
};
|
|
57
59
|
});
|
|
58
60
|
|
|
59
|
-
const predefinedAddressTemplate = {
|
|
60
|
-
results: [
|
|
61
|
-
{
|
|
62
|
-
value:
|
|
63
|
-
'<org.openmrs.layout.address.AddressTemplate>\r\n <nameMappings class="properties">\r\n <property name="postalCode" value="Location.postalCode"/>\r\n <property name="address2" value="Location.address2"/>\r\n <property name="address1" value="Location.address1"/>\r\n <property name="country" value="Location.country"/>\r\n <property name="stateProvince" value="Location.stateProvince"/>\r\n <property name="cityVillage" value="Location.cityVillage"/>\r\n </nameMappings>\r\n <sizeMappings class="properties">\r\n <property name="postalCode" value="4"/>\r\n <property name="address1" value="40"/>\r\n <property name="address2" value="40"/>\r\n <property name="country" value="10"/>\r\n <property name="stateProvince" value="10"/>\r\n <property name="cityVillage" value="10"/>\r\n <asset name="cityVillage" value="10"/>\r\n </sizeMappings>\r\n <lineByLineFormat>\r\n <string>address1 address2</string>\r\n <string>cityVillage stateProvince postalCode</string>\r\n <string>country</string>\r\n </lineByLineFormat>\r\n <elementDefaults class="properties">\r\n <property name="country" value=""/>\r\n </elementDefaults>\r\n <elementRegex class="properties">\r\n <property name="address1" value="[a-zA-Z]+$"/>\r\n </elementRegex>\r\n <elementRegexFormats class="properties">\r\n <property name="address1" value="Countries can only be letters"/>\r\n </elementRegexFormats>\r\n </org.openmrs.layout.address.AddressTemplate>',
|
|
64
|
-
},
|
|
65
|
-
],
|
|
66
|
-
};
|
|
67
|
-
|
|
68
61
|
const mockResourcesContextValue = {
|
|
69
|
-
addressTemplate:
|
|
62
|
+
addressTemplate: mockedAddressTemplate,
|
|
70
63
|
currentSession: {
|
|
71
64
|
authenticated: true,
|
|
72
65
|
sessionId: 'JSESSION',
|
|
@@ -87,9 +80,11 @@ let mockOpenmrsConfig: RegistrationConfig = {
|
|
|
87
80
|
fieldConfigurations: {
|
|
88
81
|
name: {
|
|
89
82
|
displayMiddleName: true,
|
|
90
|
-
|
|
83
|
+
allowUnidentifiedPatients: true,
|
|
91
84
|
defaultUnknownGivenName: 'UNKNOWN',
|
|
92
85
|
defaultUnknownFamilyName: 'UNKNOWN',
|
|
86
|
+
displayReverseFieldOrder: false,
|
|
87
|
+
displayCapturePhoto: true,
|
|
93
88
|
},
|
|
94
89
|
gender: [
|
|
95
90
|
{
|
|
@@ -173,264 +168,272 @@ const fillRequiredFields = async () => {
|
|
|
173
168
|
await user.type(familyNameInput, 'Gaihre');
|
|
174
169
|
await user.clear(dateOfBirthInput);
|
|
175
170
|
await user.type(dateOfBirthInput, '02/08/1993');
|
|
176
|
-
|
|
177
|
-
fireEvent.click(genderInput);
|
|
171
|
+
user.click(genderInput);
|
|
178
172
|
};
|
|
179
173
|
|
|
180
|
-
describe('patient registration', () => {
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
174
|
+
describe('patient registration component', () => {
|
|
175
|
+
describe('when registering a new patient', () => {
|
|
176
|
+
beforeEach(() => {
|
|
177
|
+
mockedUseConfig.mockReturnValue(mockOpenmrsConfig);
|
|
178
|
+
mockedSavePatient.mockReturnValue({ data: { uuid: 'new-pt-uuid' }, ok: true });
|
|
179
|
+
mockedSaveEncounter.mockClear();
|
|
180
|
+
mockedShowToast.mockClear();
|
|
181
|
+
jest.clearAllMocks();
|
|
182
|
+
});
|
|
187
183
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
184
|
+
it('renders without crashing', () => {
|
|
185
|
+
render(
|
|
186
|
+
<ResourcesContext.Provider value={mockResourcesContextValue}>
|
|
187
|
+
<Router>
|
|
188
|
+
<PatientRegistration isOffline={false} savePatientForm={jest.fn()} />
|
|
189
|
+
</Router>
|
|
190
|
+
,
|
|
191
|
+
</ResourcesContext.Provider>,
|
|
192
|
+
);
|
|
193
|
+
});
|
|
198
194
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
195
|
+
it('has the expected sections', async () => {
|
|
196
|
+
render(
|
|
197
|
+
<ResourcesContext.Provider value={mockResourcesContextValue}>
|
|
198
|
+
<Router>
|
|
199
|
+
<PatientRegistration isOffline={false} savePatientForm={jest.fn()} />
|
|
200
|
+
</Router>
|
|
201
|
+
</ResourcesContext.Provider>,
|
|
202
|
+
);
|
|
203
|
+
await waitFor(() => expect(screen.getByLabelText(/Demographics Section/)).not.toBeNull());
|
|
204
|
+
expect(screen.getByLabelText(/Contact Info Section/)).not.toBeNull();
|
|
205
|
+
});
|
|
210
206
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
);
|
|
221
|
-
|
|
222
|
-
await fillRequiredFields();
|
|
223
|
-
await user.click(await screen.findByText('Register Patient'));
|
|
224
|
-
await waitFor(() => {
|
|
225
|
-
expect(mockedSavePatient).toHaveBeenCalledWith(
|
|
226
|
-
expect.anything(),
|
|
227
|
-
expect.objectContaining({
|
|
228
|
-
identifiers: [], //TODO when the identifer story is finished: { identifier: '', identifierType: '05a29f94-c0ed-11e2-94be-8c13b969e334', location: '' }
|
|
229
|
-
// identifiers: [{ identifier: '', identifierType: '05a29f94-c0ed-11e2-94be-8c13b969e334', location: '' }],
|
|
230
|
-
person: {
|
|
231
|
-
addresses: [{}],
|
|
232
|
-
attributes: [],
|
|
233
|
-
birthdate: '1993-8-2',
|
|
234
|
-
birthdateEstimated: false,
|
|
235
|
-
gender: 'M',
|
|
236
|
-
names: [{ givenName: 'Paul', middleName: '', familyName: 'Gaihre', preferred: true, uuid: undefined }],
|
|
237
|
-
dead: false,
|
|
238
|
-
uuid: expect.anything(),
|
|
239
|
-
},
|
|
240
|
-
uuid: expect.anything(),
|
|
241
|
-
}),
|
|
242
|
-
undefined,
|
|
207
|
+
it('saves the patient without extra info', async () => {
|
|
208
|
+
const user = userEvent.setup();
|
|
209
|
+
|
|
210
|
+
render(
|
|
211
|
+
<ResourcesContext.Provider value={mockResourcesContextValue}>
|
|
212
|
+
<Router>
|
|
213
|
+
<PatientRegistration isOffline={false} savePatientForm={FormManager.savePatientFormOnline} />
|
|
214
|
+
</Router>
|
|
215
|
+
</ResourcesContext.Provider>,
|
|
243
216
|
);
|
|
217
|
+
|
|
218
|
+
await fillRequiredFields();
|
|
219
|
+
await user.click(await screen.findByText('Register Patient'));
|
|
220
|
+
await waitFor(() => {
|
|
221
|
+
expect(mockedSavePatient).toHaveBeenCalledWith(
|
|
222
|
+
expect.objectContaining({
|
|
223
|
+
identifiers: [], //TODO when the identifer story is finished: { identifier: '', identifierType: '05a29f94-c0ed-11e2-94be-8c13b969e334', location: '' },
|
|
224
|
+
person: {
|
|
225
|
+
addresses: expect.arrayContaining([expect.any(Object)]),
|
|
226
|
+
attributes: [],
|
|
227
|
+
birthdate: '1993-8-2',
|
|
228
|
+
birthdateEstimated: false,
|
|
229
|
+
gender: 'M',
|
|
230
|
+
names: [{ givenName: 'Paul', middleName: '', familyName: 'Gaihre', preferred: true, uuid: undefined }],
|
|
231
|
+
dead: false,
|
|
232
|
+
uuid: expect.anything(),
|
|
233
|
+
},
|
|
234
|
+
uuid: expect.anything(),
|
|
235
|
+
}),
|
|
236
|
+
undefined,
|
|
237
|
+
);
|
|
238
|
+
});
|
|
244
239
|
});
|
|
245
|
-
});
|
|
246
240
|
|
|
247
|
-
|
|
248
|
-
|
|
241
|
+
it('should not save the patient if validation fails', async () => {
|
|
242
|
+
const user = userEvent.setup();
|
|
243
|
+
|
|
244
|
+
const mockedSavePatientForm = jest.fn();
|
|
245
|
+
render(
|
|
246
|
+
<ResourcesContext.Provider value={mockResourcesContextValue}>
|
|
247
|
+
<Router>
|
|
248
|
+
<PatientRegistration isOffline={false} savePatientForm={mockedSavePatientForm} />
|
|
249
|
+
</Router>
|
|
250
|
+
</ResourcesContext.Provider>,
|
|
251
|
+
);
|
|
249
252
|
|
|
250
|
-
|
|
251
|
-
render(
|
|
252
|
-
<ResourcesContext.Provider value={mockResourcesContextValue}>
|
|
253
|
-
<Router>
|
|
254
|
-
<PatientRegistration isOffline={false} savePatientForm={mockedSavePatientForm} />
|
|
255
|
-
</Router>
|
|
256
|
-
</ResourcesContext.Provider>,
|
|
257
|
-
);
|
|
253
|
+
const givenNameInput = (await screen.findByLabelText('First Name')) as HTMLInputElement;
|
|
258
254
|
|
|
259
|
-
|
|
255
|
+
await user.type(givenNameInput, '5');
|
|
256
|
+
await user.click(screen.getByText('Register Patient'));
|
|
260
257
|
|
|
261
|
-
|
|
262
|
-
|
|
258
|
+
expect(mockedSavePatientForm).not.toHaveBeenCalled();
|
|
259
|
+
});
|
|
263
260
|
|
|
264
|
-
|
|
265
|
-
|
|
261
|
+
it('renders and saves registration obs', async () => {
|
|
262
|
+
const user = userEvent.setup();
|
|
266
263
|
|
|
267
|
-
|
|
268
|
-
|
|
264
|
+
mockedSaveEncounter.mockResolvedValue({});
|
|
265
|
+
mockedUseConfig.mockReturnValue(configWithObs);
|
|
269
266
|
|
|
270
|
-
|
|
267
|
+
render(
|
|
268
|
+
<ResourcesContext.Provider value={mockResourcesContextValue}>
|
|
269
|
+
<Router>
|
|
270
|
+
<PatientRegistration isOffline={false} savePatientForm={FormManager.savePatientFormOnline} />
|
|
271
|
+
</Router>
|
|
272
|
+
</ResourcesContext.Provider>,
|
|
273
|
+
);
|
|
271
274
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
275
|
+
await fillRequiredFields();
|
|
276
|
+
const customSection = screen.getByLabelText('Custom Section');
|
|
277
|
+
const weight = within(customSection).getByLabelText('Weight (kg) (optional)');
|
|
278
|
+
await user.type(weight, '50');
|
|
279
|
+
const complaint = within(customSection).getByLabelText('Chief Complaint (optional)');
|
|
280
|
+
await user.type(complaint, 'sad');
|
|
281
|
+
const nationality = within(customSection).getByLabelText('Nationality');
|
|
282
|
+
await user.selectOptions(nationality, 'USA');
|
|
283
|
+
|
|
284
|
+
await user.click(screen.getByText('Register Patient'));
|
|
285
|
+
|
|
286
|
+
await waitFor(() => expect(mockedSavePatient).toHaveBeenCalled());
|
|
287
|
+
await waitFor(() =>
|
|
288
|
+
expect(mockedSaveEncounter).toHaveBeenCalledWith(
|
|
289
|
+
expect.objectContaining<Partial<Encounter>>({
|
|
290
|
+
encounterType: 'reg-enc-uuid',
|
|
291
|
+
patient: 'new-pt-uuid',
|
|
292
|
+
obs: [
|
|
293
|
+
{ concept: 'weight-uuid', value: 50 },
|
|
294
|
+
{ concept: 'chief-complaint-uuid', value: 'sad' },
|
|
295
|
+
{ concept: 'nationality-uuid', value: 'usa' },
|
|
296
|
+
],
|
|
297
|
+
}),
|
|
298
|
+
),
|
|
299
|
+
);
|
|
277
300
|
});
|
|
278
301
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
<Router>
|
|
282
|
-
<PatientRegistration isOffline={false} savePatientForm={FormManager.savePatientFormOnline} />
|
|
283
|
-
</Router>
|
|
284
|
-
</ResourcesContext.Provider>,
|
|
285
|
-
);
|
|
286
|
-
|
|
287
|
-
const givenNameInput = screen.getByLabelText(/First Name/) as HTMLInputElement;
|
|
288
|
-
const familyNameInput = screen.getByLabelText(/Family Name/) as HTMLInputElement;
|
|
289
|
-
const middleNameInput = screen.getByLabelText(/Middle Name/) as HTMLInputElement;
|
|
290
|
-
const dateOfBirthInput = screen.getByLabelText('Date of Birth') as HTMLInputElement;
|
|
291
|
-
const address1 = screen.getByLabelText('Location.address1') as HTMLInputElement;
|
|
292
|
-
|
|
293
|
-
// assert initial values
|
|
294
|
-
expect(givenNameInput.value).toBe('John');
|
|
295
|
-
expect(familyNameInput.value).toBe('Wilson');
|
|
296
|
-
expect(middleNameInput.value).toBeFalsy();
|
|
297
|
-
expect(dateOfBirthInput.value).toBe('04/04/1972');
|
|
298
|
-
|
|
299
|
-
// do some edits
|
|
300
|
-
await user.clear(givenNameInput);
|
|
301
|
-
await user.clear(middleNameInput);
|
|
302
|
-
await user.clear(familyNameInput);
|
|
303
|
-
await user.type(givenNameInput, 'Eric');
|
|
304
|
-
await user.type(middleNameInput, 'Johnson');
|
|
305
|
-
await user.type(familyNameInput, 'Smith');
|
|
306
|
-
await user.type(address1, 'Bom Jesus Street');
|
|
307
|
-
await user.click(screen.getByText('Update Patient'));
|
|
308
|
-
|
|
309
|
-
expect(mockedSavePatient).toHaveBeenCalledWith(
|
|
310
|
-
expect.anything(),
|
|
311
|
-
{
|
|
312
|
-
uuid: '8673ee4f-e2ab-4077-ba55-4980f408773e',
|
|
313
|
-
identifiers: [
|
|
314
|
-
{
|
|
315
|
-
uuid: '1f0ad7a1-430f-4397-b571-59ea654a52db',
|
|
316
|
-
identifier: '100GEJ',
|
|
317
|
-
identifierType: 'e5af9a9c-ff9d-486d-900c-5fbf66a5ba3c',
|
|
318
|
-
preferred: true,
|
|
319
|
-
},
|
|
320
|
-
{
|
|
321
|
-
uuid: '1f0ad7a1-430f-4397-b571-59ea654a52db',
|
|
322
|
-
identifier: '100732HE',
|
|
323
|
-
identifierType: '3ff0063c-dd45-4d98-8af4-0c094f26166c',
|
|
324
|
-
preferred: false,
|
|
325
|
-
},
|
|
326
|
-
],
|
|
327
|
-
person: {
|
|
328
|
-
addresses: [
|
|
329
|
-
{
|
|
330
|
-
address1: 'Bom Jesus Street',
|
|
331
|
-
address2: '',
|
|
332
|
-
cityVillage: 'City0351',
|
|
333
|
-
country: 'Country0351',
|
|
334
|
-
postalCode: '60351',
|
|
335
|
-
stateProvince: 'State0351tested',
|
|
336
|
-
},
|
|
337
|
-
],
|
|
338
|
-
attributes: [],
|
|
339
|
-
birthdate: new Date('1972-04-04'),
|
|
340
|
-
birthdateEstimated: false,
|
|
341
|
-
gender: 'M',
|
|
342
|
-
names: [
|
|
343
|
-
{
|
|
344
|
-
uuid: 'efdb246f-4142-4c12-a27a-9be60b9592e9',
|
|
345
|
-
givenName: 'Eric',
|
|
346
|
-
middleName: 'Johnson',
|
|
347
|
-
familyName: 'Smith',
|
|
348
|
-
preferred: true,
|
|
349
|
-
},
|
|
350
|
-
],
|
|
351
|
-
dead: false,
|
|
352
|
-
uuid: '8673ee4f-e2ab-4077-ba55-4980f408773e',
|
|
353
|
-
},
|
|
354
|
-
},
|
|
355
|
-
'8673ee4f-e2ab-4077-ba55-4980f408773e',
|
|
356
|
-
);
|
|
357
|
-
});
|
|
302
|
+
it('retries saving registration obs after a failed attempt', async () => {
|
|
303
|
+
const user = userEvent.setup();
|
|
358
304
|
|
|
359
|
-
|
|
360
|
-
const user = userEvent.setup();
|
|
361
|
-
|
|
362
|
-
mockedSaveEncounter.mockResolvedValue({});
|
|
363
|
-
mockedUseConfig.mockReturnValue(configWithObs);
|
|
364
|
-
|
|
365
|
-
render(
|
|
366
|
-
<ResourcesContext.Provider value={mockResourcesContextValue}>
|
|
367
|
-
<Router>
|
|
368
|
-
<PatientRegistration isOffline={false} savePatientForm={FormManager.savePatientFormOnline} />
|
|
369
|
-
</Router>
|
|
370
|
-
</ResourcesContext.Provider>,
|
|
371
|
-
);
|
|
372
|
-
|
|
373
|
-
await fillRequiredFields();
|
|
374
|
-
const customSection = screen.getByLabelText('Custom Section');
|
|
375
|
-
const weight = within(customSection).getByLabelText('Weight (kg)');
|
|
376
|
-
await user.type(weight, '50');
|
|
377
|
-
const complaint = within(customSection).getByLabelText('Chief Complaint');
|
|
378
|
-
await user.type(complaint, 'sad');
|
|
379
|
-
const nationality = within(customSection).getByLabelText('Nationality');
|
|
380
|
-
await user.selectOptions(nationality, 'USA');
|
|
381
|
-
|
|
382
|
-
await user.click(screen.getByText('Register Patient'));
|
|
383
|
-
|
|
384
|
-
await waitFor(() => expect(mockedSavePatient).toHaveBeenCalled());
|
|
385
|
-
await waitFor(() =>
|
|
386
|
-
expect(mockedSaveEncounter).toHaveBeenCalledWith(
|
|
387
|
-
expect.anything(),
|
|
388
|
-
expect.objectContaining<Partial<Encounter>>({
|
|
389
|
-
encounterType: 'reg-enc-uuid',
|
|
390
|
-
patient: 'new-pt-uuid',
|
|
391
|
-
obs: [
|
|
392
|
-
{ concept: 'weight-uuid', value: 50 },
|
|
393
|
-
{ concept: 'chief-complaint-uuid', value: 'sad' },
|
|
394
|
-
{ concept: 'nationality-uuid', value: 'usa' },
|
|
395
|
-
],
|
|
396
|
-
}),
|
|
397
|
-
),
|
|
398
|
-
);
|
|
399
|
-
});
|
|
305
|
+
mockedUseConfig.mockReturnValue(configWithObs);
|
|
400
306
|
|
|
401
|
-
|
|
402
|
-
|
|
307
|
+
render(
|
|
308
|
+
<ResourcesContext.Provider value={mockResourcesContextValue}>
|
|
309
|
+
<Router>
|
|
310
|
+
<PatientRegistration isOffline={false} savePatientForm={FormManager.savePatientFormOnline} />
|
|
311
|
+
</Router>
|
|
312
|
+
</ResourcesContext.Provider>,
|
|
313
|
+
);
|
|
403
314
|
|
|
404
|
-
|
|
315
|
+
await fillRequiredFields();
|
|
316
|
+
const customSection = screen.getByLabelText('Custom Section');
|
|
317
|
+
const weight = within(customSection).getByLabelText('Weight (kg) (optional)');
|
|
318
|
+
await user.type(weight, '-999');
|
|
405
319
|
|
|
406
|
-
|
|
407
|
-
<ResourcesContext.Provider value={mockResourcesContextValue}>
|
|
408
|
-
<Router>
|
|
409
|
-
<PatientRegistration isOffline={false} savePatientForm={FormManager.savePatientFormOnline} />
|
|
410
|
-
</Router>
|
|
411
|
-
</ResourcesContext.Provider>,
|
|
412
|
-
);
|
|
320
|
+
mockedSaveEncounter.mockRejectedValue({ status: 400, responseBody: { error: { message: 'an error message' } } });
|
|
413
321
|
|
|
414
|
-
|
|
415
|
-
const customSection = screen.getByLabelText('Custom Section');
|
|
416
|
-
const weight = within(customSection).getByLabelText('Weight (kg)');
|
|
417
|
-
await user.type(weight, '-999');
|
|
322
|
+
await user.click(screen.getByText('Register Patient'));
|
|
418
323
|
|
|
419
|
-
|
|
324
|
+
await waitFor(() => expect(mockedSavePatient).toHaveBeenCalledTimes(1));
|
|
325
|
+
await waitFor(() => expect(mockedSaveEncounter).toHaveBeenCalledTimes(1));
|
|
326
|
+
await waitFor(() =>
|
|
327
|
+
expect(mockedShowToast).toHaveBeenCalledWith(expect.objectContaining({ description: 'an error message' })),
|
|
328
|
+
);
|
|
420
329
|
|
|
421
|
-
|
|
330
|
+
mockedSaveEncounter.mockResolvedValue({});
|
|
422
331
|
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
expect(mockedShowToast).toHaveBeenCalledWith(expect.objectContaining({
|
|
427
|
-
);
|
|
332
|
+
await user.click(screen.getByText('Register Patient'));
|
|
333
|
+
await waitFor(() => expect(mockedSavePatient).toHaveBeenCalledTimes(2));
|
|
334
|
+
await waitFor(() => expect(mockedSaveEncounter).toHaveBeenCalledTimes(2));
|
|
335
|
+
await waitFor(() => expect(mockedShowToast).toHaveBeenCalledWith(expect.objectContaining({ kind: 'success' })));
|
|
336
|
+
});
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
describe('when updating an existing patient details', () => {
|
|
340
|
+
beforeEach(() => {
|
|
341
|
+
mockedUseConfig.mockReturnValue(mockOpenmrsConfig);
|
|
342
|
+
mockedSavePatient.mockReturnValue({ data: { uuid: 'new-pt-uuid' }, ok: true });
|
|
343
|
+
mockedSaveEncounter.mockClear();
|
|
344
|
+
mockedShowToast.mockClear();
|
|
345
|
+
jest.clearAllMocks();
|
|
346
|
+
});
|
|
428
347
|
|
|
429
|
-
|
|
348
|
+
it('edits patient demographics', async () => {
|
|
349
|
+
const user = userEvent.setup();
|
|
430
350
|
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
351
|
+
mockedSavePatient.mockResolvedValue({});
|
|
352
|
+
|
|
353
|
+
const mockedUseParams = useParams as jest.Mock;
|
|
354
|
+
|
|
355
|
+
mockedUseParams.mockReturnValue({ patientUuid: mockPatient.id });
|
|
356
|
+
|
|
357
|
+
mockedUsePatient.mockReturnValue({
|
|
358
|
+
isLoading: false,
|
|
359
|
+
patient: mockPatient,
|
|
360
|
+
patientUuid: mockPatient.id,
|
|
361
|
+
error: null,
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
render(
|
|
365
|
+
<ResourcesContext.Provider value={mockResourcesContextValue}>
|
|
366
|
+
<Router>
|
|
367
|
+
<PatientRegistration isOffline={false} savePatientForm={mockedSavePatient} />
|
|
368
|
+
</Router>
|
|
369
|
+
</ResourcesContext.Provider>,
|
|
370
|
+
);
|
|
371
|
+
|
|
372
|
+
const givenNameInput: HTMLInputElement = screen.getByLabelText(/First Name/);
|
|
373
|
+
const familyNameInput: HTMLInputElement = screen.getByLabelText(/Family Name/);
|
|
374
|
+
const middleNameInput: HTMLInputElement = screen.getByLabelText(/Middle Name/);
|
|
375
|
+
const dateOfBirthInput: HTMLInputElement = screen.getByLabelText('Date of Birth');
|
|
376
|
+
const genderInput: HTMLInputElement = screen.getByLabelText(/Male/);
|
|
377
|
+
|
|
378
|
+
// assert initial values
|
|
379
|
+
expect(givenNameInput.value).toBe('John');
|
|
380
|
+
expect(familyNameInput.value).toBe('Wilson');
|
|
381
|
+
expect(middleNameInput.value).toBeFalsy();
|
|
382
|
+
expect(dateOfBirthInput.value).toBe('4/4/1972');
|
|
383
|
+
expect(genderInput.value).toBe('Male');
|
|
384
|
+
|
|
385
|
+
// do some edits
|
|
386
|
+
await user.clear(givenNameInput);
|
|
387
|
+
await user.clear(middleNameInput);
|
|
388
|
+
await user.clear(familyNameInput);
|
|
389
|
+
await user.type(givenNameInput, 'Eric');
|
|
390
|
+
await user.type(middleNameInput, 'Johnson');
|
|
391
|
+
await user.type(familyNameInput, 'Smith');
|
|
392
|
+
await user.click(screen.getByText('Update Patient'));
|
|
393
|
+
|
|
394
|
+
await waitFor(() =>
|
|
395
|
+
expect(mockedSavePatient).toHaveBeenCalledWith(
|
|
396
|
+
false,
|
|
397
|
+
{
|
|
398
|
+
'0': {
|
|
399
|
+
oldIdentificationNumber: '100732HE',
|
|
400
|
+
},
|
|
401
|
+
'1': {
|
|
402
|
+
openMrsId: '100GEJ',
|
|
403
|
+
},
|
|
404
|
+
addNameInLocalLanguage: undefined,
|
|
405
|
+
additionalFamilyName: '',
|
|
406
|
+
additionalGivenName: '',
|
|
407
|
+
additionalMiddleName: '',
|
|
408
|
+
address: {},
|
|
409
|
+
birthdate: new Date('1972-04-04T00:00:00.000Z'),
|
|
410
|
+
birthdateEstimated: false,
|
|
411
|
+
deathCause: '',
|
|
412
|
+
deathDate: '',
|
|
413
|
+
familyName: 'Smith',
|
|
414
|
+
gender: 'Male',
|
|
415
|
+
givenName: 'Eric',
|
|
416
|
+
identifiers: {},
|
|
417
|
+
isDead: false,
|
|
418
|
+
middleName: 'Johnson',
|
|
419
|
+
monthsEstimated: 0,
|
|
420
|
+
patientUuid: '8673ee4f-e2ab-4077-ba55-4980f408773e',
|
|
421
|
+
relationships: [],
|
|
422
|
+
telephoneNumber: '',
|
|
423
|
+
unidentifiedPatient: undefined,
|
|
424
|
+
yearsEstimated: 0,
|
|
425
|
+
},
|
|
426
|
+
expect.anything(),
|
|
427
|
+
expect.anything(),
|
|
428
|
+
null,
|
|
429
|
+
undefined,
|
|
430
|
+
expect.anything(),
|
|
431
|
+
expect.anything(),
|
|
432
|
+
expect.anything(),
|
|
433
|
+
{ patientSaved: false },
|
|
434
|
+
expect.anything(),
|
|
435
|
+
),
|
|
436
|
+
);
|
|
437
|
+
});
|
|
435
438
|
});
|
|
436
439
|
});
|