@openmrs/esm-patient-programs-app 3.2.1-pre.89 → 4.0.1-pre.221
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/.turbo/turbo-build.log +25 -273
- package/dist/109.js +1 -0
- package/dist/13.js +1 -0
- package/dist/145.js +1 -0
- package/dist/154.js +2 -0
- package/dist/154.js.LICENSE.txt +53 -0
- package/dist/206.js +1 -2
- package/dist/238.js +2 -0
- package/dist/{707.js.LICENSE.txt → 238.js.LICENSE.txt} +0 -0
- package/dist/340.js +1 -0
- package/dist/435.js +1 -0
- package/dist/461.js +1 -0
- package/dist/574.js +1 -1
- package/dist/709.js +1 -0
- package/dist/784.js +1 -2
- package/dist/784.js.LICENSE.txt +2 -7
- package/dist/858.js +1 -2
- package/dist/858.js.LICENSE.txt +2 -0
- package/dist/879.js +1 -2
- package/dist/main.js +1 -0
- package/dist/openmrs-esm-patient-programs-app.js +1 -1
- package/dist/openmrs-esm-patient-programs-app.js.buildmanifest.json +150 -259
- package/dist/openmrs-esm-patient-programs-app.old +1 -2
- package/package.json +7 -11
- package/src/config-schema.ts +12 -0
- package/src/dashboard.meta.tsx +1 -1
- package/src/index.ts +3 -2
- package/src/programs/program-action-button/program-action-button.component.tsx +47 -0
- package/src/programs/programs-detailed-summary.component.tsx +68 -37
- package/src/programs/programs-detailed-summary.scss +1 -4
- package/src/programs/programs-detailed-summary.test.tsx +26 -7
- package/src/programs/programs-form.component.tsx +102 -46
- package/src/programs/programs-form.scss +1 -9
- package/src/programs/programs-form.test.tsx +113 -110
- package/src/programs/programs-overview.component.tsx +59 -45
- package/src/programs/programs-overview.scss +1 -3
- package/src/programs/programs-overview.test.tsx +6 -7
- package/src/programs/programs.resource.tsx +63 -8
- package/src/types/index.ts +16 -2
- package/translations/en.json +8 -2
- package/dist/163.js +0 -3
- package/dist/163.js.LICENSE.txt +0 -20
- package/dist/163.js.map +0 -1
- package/dist/186.js +0 -3
- package/dist/186.js.LICENSE.txt +0 -23
- package/dist/186.js.map +0 -1
- package/dist/206.js.map +0 -1
- package/dist/252.js +0 -3
- package/dist/252.js.LICENSE.txt +0 -23
- package/dist/252.js.map +0 -1
- package/dist/344.js +0 -2
- package/dist/344.js.map +0 -1
- package/dist/357.js +0 -2
- package/dist/357.js.map +0 -1
- package/dist/373.js +0 -2
- package/dist/373.js.map +0 -1
- package/dist/402.js +0 -2
- package/dist/402.js.map +0 -1
- package/dist/511.js +0 -2
- package/dist/511.js.map +0 -1
- package/dist/593.js +0 -2
- package/dist/593.js.map +0 -1
- package/dist/635.js +0 -3
- package/dist/635.js.LICENSE.txt +0 -16
- package/dist/635.js.map +0 -1
- package/dist/701.js +0 -2
- package/dist/701.js.map +0 -1
- package/dist/707.js +0 -3
- package/dist/707.js.map +0 -1
- package/dist/76.js +0 -2
- package/dist/76.js.map +0 -1
- package/dist/784.js.map +0 -1
- package/dist/858.js.map +0 -1
- package/dist/879.js.map +0 -1
- package/dist/932.js +0 -2
- package/dist/932.js.map +0 -1
- package/dist/openmrs-esm-patient-programs-app.js.map +0 -1
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import React, { SyntheticEvent } from 'react';
|
|
2
|
+
import { useTranslation } from 'react-i18next';
|
|
2
3
|
import dayjs from 'dayjs';
|
|
3
4
|
import filter from 'lodash-es/filter';
|
|
4
5
|
import includes from 'lodash-es/includes';
|
|
5
6
|
import map from 'lodash-es/map';
|
|
6
7
|
import { useSWRConfig } from 'swr';
|
|
7
|
-
import { useTranslation } from 'react-i18next';
|
|
8
8
|
import {
|
|
9
9
|
createErrorHandler,
|
|
10
10
|
showNotification,
|
|
@@ -12,27 +12,34 @@ import {
|
|
|
12
12
|
useSession,
|
|
13
13
|
useLocations,
|
|
14
14
|
useLayoutType,
|
|
15
|
+
parseDate,
|
|
15
16
|
} from '@openmrs/esm-framework';
|
|
16
17
|
import {
|
|
17
18
|
Button,
|
|
19
|
+
ButtonSet,
|
|
18
20
|
DatePicker,
|
|
19
21
|
DatePickerInput,
|
|
20
|
-
Select,
|
|
21
|
-
SelectItem,
|
|
22
22
|
Form,
|
|
23
23
|
FormGroup,
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
Select,
|
|
25
|
+
SelectItem,
|
|
26
|
+
Stack,
|
|
27
|
+
} from '@carbon/react';
|
|
26
28
|
import {
|
|
27
29
|
createProgramEnrollment,
|
|
28
30
|
useAvailablePrograms,
|
|
29
31
|
useEnrollments,
|
|
30
32
|
customRepresentation,
|
|
33
|
+
updateProgramEnrollment,
|
|
31
34
|
} from './programs.resource';
|
|
32
35
|
import { DefaultWorkspaceProps } from '@openmrs/esm-patient-common-lib';
|
|
33
36
|
import styles from './programs-form.scss';
|
|
34
37
|
|
|
35
|
-
|
|
38
|
+
interface ProgramsFormProps extends DefaultWorkspaceProps {
|
|
39
|
+
programEnrollmentId?: string;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const ProgramsForm: React.FC<ProgramsFormProps> = ({ closeWorkspace, patientUuid, programEnrollmentId }) => {
|
|
36
43
|
const { t } = useTranslation();
|
|
37
44
|
const isTablet = useLayoutType() === 'tablet';
|
|
38
45
|
const session = useSession();
|
|
@@ -41,16 +48,25 @@ const ProgramsForm: React.FC<DefaultWorkspaceProps> = ({ closeWorkspace, patient
|
|
|
41
48
|
|
|
42
49
|
const { data: availablePrograms } = useAvailablePrograms();
|
|
43
50
|
const { data: enrollments } = useEnrollments(patientUuid);
|
|
51
|
+
const currentEnrollment = programEnrollmentId && enrollments.filter((e) => e.uuid == programEnrollmentId)[0];
|
|
52
|
+
const currentProgram = currentEnrollment
|
|
53
|
+
? {
|
|
54
|
+
display: currentEnrollment.program.name,
|
|
55
|
+
...currentEnrollment.program,
|
|
56
|
+
}
|
|
57
|
+
: null;
|
|
44
58
|
|
|
45
|
-
const eligiblePrograms =
|
|
46
|
-
|
|
47
|
-
(program) => !includes(map(enrollments, 'program.uuid'), program.uuid)
|
|
59
|
+
const eligiblePrograms = currentProgram
|
|
60
|
+
? [currentProgram]
|
|
61
|
+
: filter(availablePrograms, (program) => !includes(map(enrollments, 'program.uuid'), program.uuid));
|
|
62
|
+
const [completionDate, setCompletionDate] = React.useState<Date>(
|
|
63
|
+
currentEnrollment?.dateCompleted ? parseDate(currentEnrollment.dateCompleted) : null,
|
|
48
64
|
);
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
const [selectedProgram, setSelectedProgram] = React.useState<string>('');
|
|
53
|
-
const [userLocation, setUserLocation] = React.useState('');
|
|
65
|
+
const [enrollmentDate, setEnrollmentDate] = React.useState<Date>(
|
|
66
|
+
currentEnrollment?.dateEnrolled ? parseDate(currentEnrollment.dateEnrolled) : new Date(),
|
|
67
|
+
);
|
|
68
|
+
const [selectedProgram, setSelectedProgram] = React.useState<string>(currentEnrollment?.program.uuid ?? '');
|
|
69
|
+
const [userLocation, setUserLocation] = React.useState<string>(currentEnrollment?.location.uuid ?? '');
|
|
54
70
|
|
|
55
71
|
if (!userLocation && session?.sessionLocation?.uuid) {
|
|
56
72
|
setUserLocation(session?.sessionLocation?.uuid);
|
|
@@ -71,43 +87,83 @@ const ProgramsForm: React.FC<DefaultWorkspaceProps> = ({ closeWorkspace, patient
|
|
|
71
87
|
};
|
|
72
88
|
|
|
73
89
|
const abortController = new AbortController();
|
|
74
|
-
const sub =
|
|
75
|
-
(
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
90
|
+
const sub = currentEnrollment
|
|
91
|
+
? updateProgramEnrollment(currentEnrollment.uuid, payload, abortController).subscribe(
|
|
92
|
+
(response) => {
|
|
93
|
+
if (response.status === 200) {
|
|
94
|
+
closeWorkspace();
|
|
95
|
+
|
|
96
|
+
showToast({
|
|
97
|
+
critical: true,
|
|
98
|
+
kind: 'success',
|
|
99
|
+
description: t(
|
|
100
|
+
'enrollmentUpdatesNowVisible',
|
|
101
|
+
'Changes to the program are now visible in the Programs table',
|
|
102
|
+
),
|
|
103
|
+
title: t('enrollmentUpdated', 'Program enrollment updated'),
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
mutate(`/ws/rest/v1/programenrollment?patient=${patientUuid}&v=${customRepresentation}`);
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
(err) => {
|
|
110
|
+
createErrorHandler();
|
|
111
|
+
|
|
112
|
+
showNotification({
|
|
113
|
+
title: t('programEnrollmentSaveError', 'Error saving program enrollment'),
|
|
114
|
+
kind: 'error',
|
|
115
|
+
critical: true,
|
|
116
|
+
description: err?.message,
|
|
117
|
+
});
|
|
118
|
+
},
|
|
119
|
+
)
|
|
120
|
+
: createProgramEnrollment(payload, abortController).subscribe(
|
|
121
|
+
(response) => {
|
|
122
|
+
if (response.status === 201) {
|
|
123
|
+
closeWorkspace();
|
|
124
|
+
|
|
125
|
+
showToast({
|
|
126
|
+
critical: true,
|
|
127
|
+
kind: 'success',
|
|
128
|
+
description: t('enrollmentNowVisible', 'It is now visible in the Programs table'),
|
|
129
|
+
title: t('enrollmentSaved', 'Program enrollment saved'),
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
mutate(`/ws/rest/v1/programenrollment?patient=${patientUuid}&v=${customRepresentation}`);
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
(err) => {
|
|
136
|
+
createErrorHandler();
|
|
137
|
+
|
|
138
|
+
showNotification({
|
|
139
|
+
title: t('programEnrollmentSaveError', 'Error saving program enrollment'),
|
|
140
|
+
kind: 'error',
|
|
141
|
+
critical: true,
|
|
142
|
+
description: err?.message,
|
|
143
|
+
});
|
|
144
|
+
},
|
|
145
|
+
);
|
|
100
146
|
return () => {
|
|
101
147
|
sub.unsubscribe();
|
|
102
148
|
};
|
|
103
149
|
},
|
|
104
|
-
[
|
|
150
|
+
[
|
|
151
|
+
closeWorkspace,
|
|
152
|
+
completionDate,
|
|
153
|
+
enrollmentDate,
|
|
154
|
+
mutate,
|
|
155
|
+
patientUuid,
|
|
156
|
+
selectedProgram,
|
|
157
|
+
t,
|
|
158
|
+
userLocation,
|
|
159
|
+
currentEnrollment,
|
|
160
|
+
],
|
|
105
161
|
);
|
|
106
162
|
|
|
107
163
|
return (
|
|
108
164
|
<Form className={styles.form} onSubmit={handleSubmit}>
|
|
109
|
-
<
|
|
110
|
-
<FormGroup style={{
|
|
165
|
+
<Stack className={styles.formContainer} gap={7}>
|
|
166
|
+
<FormGroup style={{ maxWidth: '50%' }} legendText={t('programName', 'Program name')}>
|
|
111
167
|
<div className={styles.selectContainer}>
|
|
112
168
|
<Select
|
|
113
169
|
id="program"
|
|
@@ -126,7 +182,7 @@ const ProgramsForm: React.FC<DefaultWorkspaceProps> = ({ closeWorkspace, patient
|
|
|
126
182
|
</Select>
|
|
127
183
|
</div>
|
|
128
184
|
</FormGroup>
|
|
129
|
-
<FormGroup legendText={t('dateEnrolled', 'Date enrolled')}>
|
|
185
|
+
<FormGroup style={{ maxWidth: '50%' }} legendText={t('dateEnrolled', 'Date enrolled')}>
|
|
130
186
|
<DatePicker
|
|
131
187
|
id="enrollmentDate"
|
|
132
188
|
datePickerType="single"
|
|
@@ -140,7 +196,7 @@ const ProgramsForm: React.FC<DefaultWorkspaceProps> = ({ closeWorkspace, patient
|
|
|
140
196
|
<DatePickerInput id="enrollmentDateInput" labelText="" />
|
|
141
197
|
</DatePicker>
|
|
142
198
|
</FormGroup>
|
|
143
|
-
<FormGroup legendText={t('dateCompleted', 'Date completed')}>
|
|
199
|
+
<FormGroup style={{ width: '50%' }} legendText={t('dateCompleted', 'Date completed')}>
|
|
144
200
|
<DatePicker
|
|
145
201
|
id="completionDate"
|
|
146
202
|
datePickerType="single"
|
|
@@ -173,7 +229,7 @@ const ProgramsForm: React.FC<DefaultWorkspaceProps> = ({ closeWorkspace, patient
|
|
|
173
229
|
))}
|
|
174
230
|
</Select>
|
|
175
231
|
</FormGroup>
|
|
176
|
-
</
|
|
232
|
+
</Stack>
|
|
177
233
|
<ButtonSet className={isTablet ? styles.tablet : styles.desktop}>
|
|
178
234
|
<Button className={styles.button} kind="secondary" onClick={() => closeWorkspace()}>
|
|
179
235
|
{t('cancel', 'Cancel')}
|
|
@@ -1,11 +1,4 @@
|
|
|
1
|
-
@import
|
|
2
|
-
@import "~carbon-components/src/globals/scss/vars";
|
|
3
|
-
@import "~carbon-components/src/globals/scss/mixins";
|
|
4
|
-
|
|
5
|
-
.selectContainer {
|
|
6
|
-
display: flex;
|
|
7
|
-
align-items: center;
|
|
8
|
-
}
|
|
1
|
+
@import '~@openmrs/esm-styleguide/src/vars';
|
|
9
2
|
|
|
10
3
|
.loading {
|
|
11
4
|
margin-left: 1rem;
|
|
@@ -13,7 +6,6 @@
|
|
|
13
6
|
min-height: 2.5rem;
|
|
14
7
|
}
|
|
15
8
|
|
|
16
|
-
|
|
17
9
|
.button {
|
|
18
10
|
height: 4rem;
|
|
19
11
|
display: flex;
|
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { throwError } from 'rxjs';
|
|
3
3
|
import { of } from 'rxjs/internal/observable/of';
|
|
4
|
-
import { render, screen, waitFor } from '@testing-library/react';
|
|
4
|
+
import { render, screen, waitFor, within } from '@testing-library/react';
|
|
5
5
|
import userEvent from '@testing-library/user-event';
|
|
6
|
-
import { createErrorHandler, openmrsFetch, showNotification, showToast
|
|
6
|
+
import { createErrorHandler, openmrsFetch, showNotification, showToast } from '@openmrs/esm-framework';
|
|
7
7
|
import { mockPatient } from '../../../../__mocks__/patient.mock';
|
|
8
8
|
import {
|
|
9
9
|
mockCareProgramsResponse,
|
|
10
10
|
mockEnrolledProgramsResponse,
|
|
11
11
|
mockLocationsResponse,
|
|
12
12
|
} from '../../../../__mocks__/programs.mock';
|
|
13
|
-
import { createProgramEnrollment } from './programs.resource';
|
|
13
|
+
import { createProgramEnrollment, updateProgramEnrollment } from './programs.resource';
|
|
14
14
|
import ProgramsForm from './programs-form.component';
|
|
15
15
|
|
|
16
|
+
jest.setTimeout(20000);
|
|
17
|
+
|
|
16
18
|
const testProps = {
|
|
17
19
|
closeWorkspace: jest.fn(),
|
|
18
20
|
patientUuid: mockPatient.id,
|
|
@@ -21,10 +23,10 @@ const testProps = {
|
|
|
21
23
|
|
|
22
24
|
const mockCreateErrorHandler = createErrorHandler as jest.Mock;
|
|
23
25
|
const mockCreateProgramEnrollment = createProgramEnrollment as jest.Mock;
|
|
26
|
+
const mockUpdateProgramEnrollment = updateProgramEnrollment as jest.Mock;
|
|
24
27
|
const mockOpenmrsFetch = openmrsFetch as jest.Mock;
|
|
25
28
|
const mockShowNotification = showNotification as jest.Mock;
|
|
26
29
|
const mockShowToast = showToast as jest.Mock;
|
|
27
|
-
const mockUseLayoutType = useLayoutType as jest.Mock;
|
|
28
30
|
|
|
29
31
|
jest.mock('@openmrs/esm-framework', () => {
|
|
30
32
|
const originalModule = jest.requireActual('@openmrs/esm-framework');
|
|
@@ -44,142 +46,143 @@ jest.mock('./programs.resource', () => {
|
|
|
44
46
|
return {
|
|
45
47
|
...originalModule,
|
|
46
48
|
createProgramEnrollment: jest.fn(),
|
|
49
|
+
updateProgramEnrollment: jest.fn(),
|
|
47
50
|
};
|
|
48
51
|
});
|
|
49
52
|
|
|
50
|
-
describe('ProgramsForm
|
|
51
|
-
|
|
53
|
+
describe('ProgramsForm', () => {
|
|
54
|
+
it('renders a success toast notification upon successfully recording a program enrollment', async () => {
|
|
55
|
+
const user = userEvent.setup();
|
|
56
|
+
|
|
57
|
+
const inpatientWardUuid = 'b1a8b05e-3542-4037-bbd3-998ee9c40574';
|
|
58
|
+
const oncologyScreeningProgramUuid = '11b129ca-a5e7-4025-84bf-b92a173e20de';
|
|
59
|
+
|
|
52
60
|
mockOpenmrsFetch.mockReturnValueOnce({ data: { results: mockCareProgramsResponse } });
|
|
53
61
|
mockOpenmrsFetch.mockReturnValueOnce({ data: { results: mockEnrolledProgramsResponse } });
|
|
54
|
-
|
|
62
|
+
mockCreateProgramEnrollment.mockReturnValueOnce(of({ status: 201, statusText: 'Created' }));
|
|
55
63
|
|
|
56
|
-
it('renders the programs form with all the relevant fields and values', async () => {
|
|
57
64
|
renderProgramsForm();
|
|
58
65
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
66
|
+
const enrollButton = screen.getByRole('button', { name: /save and close/i });
|
|
67
|
+
const enrollmentDateInput = screen.getAllByRole('textbox', { name: '' })[0];
|
|
68
|
+
const selectLocationInput = screen.getAllByRole('combobox', { name: '' })[1];
|
|
69
|
+
const selectProgramInput = screen.getAllByRole('combobox', { name: '' })[0];
|
|
70
|
+
|
|
71
|
+
await waitFor(() => user.type(enrollmentDateInput, '2020-05-05'));
|
|
72
|
+
await waitFor(() => user.selectOptions(selectProgramInput, [oncologyScreeningProgramUuid]));
|
|
73
|
+
await waitFor(() => user.selectOptions(selectLocationInput, [inpatientWardUuid]));
|
|
74
|
+
|
|
67
75
|
expect(screen.getByRole('option', { name: /Inpatient Ward/i })).toBeInTheDocument();
|
|
68
|
-
expect(screen.getByRole('option', { name: /Isolation Ward/i })).toBeInTheDocument();
|
|
69
|
-
expect(screen.getByRole('option', { name: /Laboratory/i })).toBeInTheDocument();
|
|
70
76
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
expect(
|
|
74
|
-
expect(
|
|
75
|
-
|
|
77
|
+
await waitFor(() => user.click(enrollButton));
|
|
78
|
+
|
|
79
|
+
expect(mockCreateProgramEnrollment).toHaveBeenCalledTimes(1);
|
|
80
|
+
expect(mockCreateProgramEnrollment).toHaveBeenCalledWith(
|
|
81
|
+
expect.objectContaining({
|
|
82
|
+
dateCompleted: null,
|
|
83
|
+
location: inpatientWardUuid,
|
|
84
|
+
patient: mockPatient.id,
|
|
85
|
+
program: oncologyScreeningProgramUuid,
|
|
86
|
+
}),
|
|
87
|
+
new AbortController(),
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
expect(mockShowToast).toHaveBeenCalledTimes(1);
|
|
91
|
+
expect(mockShowToast).toHaveBeenCalledWith({
|
|
92
|
+
critical: true,
|
|
93
|
+
description: 'It is now visible in the Programs table',
|
|
94
|
+
kind: 'success',
|
|
95
|
+
title: 'Program enrollment saved',
|
|
96
|
+
});
|
|
76
97
|
});
|
|
77
98
|
|
|
78
|
-
it('
|
|
79
|
-
|
|
99
|
+
it('updates a program enrollment', async () => {
|
|
100
|
+
const user = userEvent.setup();
|
|
80
101
|
|
|
81
|
-
|
|
82
|
-
userEvent.click(cancelButton);
|
|
102
|
+
renderProgramsForm(mockEnrolledProgramsResponse[0].uuid);
|
|
83
103
|
|
|
84
|
-
|
|
85
|
-
|
|
104
|
+
const enrollButton = screen.getByRole('button', { name: /save and close/i });
|
|
105
|
+
const dateCompletedGroup = screen.getByRole('group', { name: /Date completed/i });
|
|
106
|
+
const dateCompletedInput = within(dateCompletedGroup).getByRole('textbox');
|
|
86
107
|
|
|
87
|
-
|
|
88
|
-
mockUseLayoutType.mockReturnValueOnce('tablet').mockReturnValueOnce('tablet');
|
|
108
|
+
mockUpdateProgramEnrollment.mockReturnValueOnce(of({ status: 200, statusText: 'OK' }));
|
|
89
109
|
|
|
90
|
-
|
|
110
|
+
await waitFor(() => user.type(dateCompletedInput, '05/05/2020'));
|
|
91
111
|
|
|
92
|
-
expect(
|
|
93
|
-
|
|
112
|
+
expect(dateCompletedInput).toHaveValue('05/05/2020');
|
|
113
|
+
|
|
114
|
+
await waitFor(() => user.tab());
|
|
115
|
+
|
|
116
|
+
expect(enrollButton).not.toBeDisabled();
|
|
117
|
+
|
|
118
|
+
await waitFor(() => user.click(enrollButton));
|
|
119
|
+
|
|
120
|
+
expect(mockUpdateProgramEnrollment).toHaveBeenCalledTimes(1);
|
|
121
|
+
expect(mockUpdateProgramEnrollment).toHaveBeenCalledWith(
|
|
122
|
+
mockEnrolledProgramsResponse[0].uuid,
|
|
123
|
+
expect.objectContaining({
|
|
124
|
+
dateEnrolled: '2020-01-16T00:00:00+00:00',
|
|
125
|
+
dateCompleted: '2020-05-05T00:00:00+00:00',
|
|
126
|
+
location: mockEnrolledProgramsResponse[0].location.uuid,
|
|
127
|
+
patient: mockPatient.id,
|
|
128
|
+
program: mockEnrolledProgramsResponse[0].program.uuid,
|
|
129
|
+
}),
|
|
130
|
+
new AbortController(),
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
expect(mockShowToast).toHaveBeenCalledWith(
|
|
134
|
+
expect.objectContaining({
|
|
135
|
+
critical: true,
|
|
136
|
+
description: 'Changes to the program are now visible in the Programs table',
|
|
137
|
+
kind: 'success',
|
|
138
|
+
title: 'Program enrollment updated',
|
|
139
|
+
}),
|
|
140
|
+
);
|
|
94
141
|
});
|
|
95
142
|
|
|
96
|
-
|
|
143
|
+
it('renders an error notification if there was a problem recording a program enrollment', async () => {
|
|
144
|
+
const user = userEvent.setup();
|
|
145
|
+
|
|
97
146
|
const inpatientWardUuid = 'b1a8b05e-3542-4037-bbd3-998ee9c40574';
|
|
98
147
|
const oncologyScreeningProgramUuid = '11b129ca-a5e7-4025-84bf-b92a173e20de';
|
|
99
|
-
let cancelButton: HTMLElement;
|
|
100
|
-
let enrollButton: HTMLElement;
|
|
101
|
-
let enrollmentDateInput: HTMLElement;
|
|
102
|
-
let selectLocationInput: HTMLElement;
|
|
103
|
-
let selectProgramInput: HTMLElement;
|
|
104
|
-
|
|
105
|
-
beforeEach(() => {
|
|
106
|
-
renderProgramsForm();
|
|
107
|
-
|
|
108
|
-
cancelButton = screen.getByRole('button', { name: /cancel/i });
|
|
109
|
-
enrollButton = screen.getByRole('button', { name: /save and close/i });
|
|
110
|
-
enrollmentDateInput = screen.getAllByRole('textbox', { name: '' })[0];
|
|
111
|
-
selectLocationInput = screen.getAllByRole('combobox', { name: '' })[1];
|
|
112
|
-
selectProgramInput = screen.getAllByRole('combobox', { name: '' })[0];
|
|
113
|
-
});
|
|
114
148
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
expect(screen.getByDisplayValue('Oncology Screening and Diagnosis')).toBeInTheDocument();
|
|
123
|
-
expect(screen.getByDisplayValue('Inpatient Ward')).toBeInTheDocument();
|
|
124
|
-
expect(enrollButton).not.toBeDisabled();
|
|
125
|
-
|
|
126
|
-
await waitFor(() => userEvent.click(enrollButton));
|
|
127
|
-
|
|
128
|
-
expect(mockCreateProgramEnrollment).toHaveBeenCalledTimes(1);
|
|
129
|
-
expect(mockCreateProgramEnrollment).toHaveBeenCalledWith(
|
|
130
|
-
expect.objectContaining({
|
|
131
|
-
dateCompleted: null,
|
|
132
|
-
location: inpatientWardUuid,
|
|
133
|
-
patient: mockPatient.id,
|
|
134
|
-
program: oncologyScreeningProgramUuid,
|
|
135
|
-
}),
|
|
136
|
-
new AbortController(),
|
|
137
|
-
);
|
|
138
|
-
|
|
139
|
-
expect(mockShowToast).toHaveBeenCalledTimes(1);
|
|
140
|
-
expect(mockShowToast).toHaveBeenCalledWith(
|
|
141
|
-
expect.objectContaining({
|
|
142
|
-
critical: true,
|
|
143
|
-
description: 'It is now visible on the Programs page',
|
|
144
|
-
kind: 'success',
|
|
145
|
-
title: 'Program enrollment saved',
|
|
146
|
-
}),
|
|
147
|
-
);
|
|
148
|
-
});
|
|
149
|
+
const error = {
|
|
150
|
+
message: 'Internal Server Error',
|
|
151
|
+
response: {
|
|
152
|
+
status: 500,
|
|
153
|
+
statusText: 'Internal Server Error',
|
|
154
|
+
},
|
|
155
|
+
};
|
|
149
156
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
response: {
|
|
154
|
-
status: 500,
|
|
155
|
-
statusText: 'Internal Server Error',
|
|
156
|
-
},
|
|
157
|
-
};
|
|
157
|
+
mockOpenmrsFetch.mockReturnValueOnce({ data: { results: mockCareProgramsResponse } });
|
|
158
|
+
mockOpenmrsFetch.mockReturnValueOnce({ data: { results: mockEnrolledProgramsResponse } });
|
|
159
|
+
mockCreateProgramEnrollment.mockReturnValueOnce(throwError(error));
|
|
158
160
|
|
|
159
|
-
|
|
161
|
+
renderProgramsForm();
|
|
160
162
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
163
|
+
const enrollButton = screen.getByRole('button', { name: /save and close/i });
|
|
164
|
+
const enrollmentDateInput = screen.getAllByRole('textbox', { name: '' })[0];
|
|
165
|
+
const selectLocationInput = screen.getAllByRole('combobox', { name: '' })[1];
|
|
166
|
+
const selectProgramInput = screen.getAllByRole('combobox', { name: '' })[0];
|
|
164
167
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
expect(enrollButton).not.toBeDisabled();
|
|
168
|
+
await waitFor(() => user.type(enrollmentDateInput, '2020-05-05'));
|
|
169
|
+
await waitFor(() => user.selectOptions(selectProgramInput, [oncologyScreeningProgramUuid]));
|
|
170
|
+
await waitFor(() => user.selectOptions(selectLocationInput, [inpatientWardUuid]));
|
|
169
171
|
|
|
170
|
-
|
|
172
|
+
expect(enrollButton).not.toBeDisabled();
|
|
171
173
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
174
|
+
await waitFor(() => user.click(enrollButton));
|
|
175
|
+
|
|
176
|
+
expect(mockCreateErrorHandler).toHaveBeenCalledTimes(1);
|
|
177
|
+
expect(mockShowNotification).toHaveBeenCalledWith({
|
|
178
|
+
critical: true,
|
|
179
|
+
description: 'Internal Server Error',
|
|
180
|
+
kind: 'error',
|
|
181
|
+
title: 'Error saving program enrollment',
|
|
179
182
|
});
|
|
180
183
|
});
|
|
181
184
|
});
|
|
182
185
|
|
|
183
|
-
function renderProgramsForm() {
|
|
184
|
-
render(<ProgramsForm {...testProps} />);
|
|
186
|
+
function renderProgramsForm(programEnrollmentUuidToEdit?: string) {
|
|
187
|
+
render(<ProgramsForm {...testProps} programEnrollmentId={programEnrollmentUuidToEdit} />);
|
|
185
188
|
}
|