@openmrs/esm-fast-data-entry-app 1.4.2-pre.704 → 1.4.2-pre.706

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.
@@ -0,0 +1,142 @@
1
+ import { navigate } from '@openmrs/esm-framework';
2
+ import { initialWorkflowState } from './FormWorkflowContext';
3
+ import reducer, { fdeWorkflowStorageName, fdeWorkflowStorageVersion } from './FormWorkflowReducer';
4
+
5
+ const mockNavigate = jest.mocked(navigate);
6
+
7
+ const buildState = (formStateOverrides = {}) => ({
8
+ ...initialWorkflowState,
9
+ activeFormUuid: 'triage-form',
10
+ userUuid: 'user-1',
11
+ forms: {
12
+ 'triage-form': {
13
+ workflowState: 'NEW_PATIENT',
14
+ activePatientUuid: null,
15
+ activeEncounterUuid: null,
16
+ patientUuids: [],
17
+ encounters: {},
18
+ ...formStateOverrides,
19
+ },
20
+ },
21
+ });
22
+
23
+ describe('FormWorkflowReducer', () => {
24
+ beforeEach(() => {
25
+ localStorage.clear();
26
+ });
27
+
28
+ it('initializes a fresh workflow state when there is no saved session', () => {
29
+ const state = reducer(initialWorkflowState, {
30
+ type: 'INITIALIZE_WORKFLOW_STATE',
31
+ activeFormUuid: 'triage-form',
32
+ userUuid: 'user-1',
33
+ });
34
+
35
+ expect(state.activeFormUuid).toBe('triage-form');
36
+ expect(state.forms['triage-form']).toMatchObject({
37
+ workflowState: 'NEW_PATIENT',
38
+ activePatientUuid: null,
39
+ activeEncounterUuid: null,
40
+ patientUuids: [],
41
+ encounters: {},
42
+ });
43
+
44
+ expect(JSON.parse(localStorage.getItem(`${fdeWorkflowStorageName}:user-1`))).toMatchObject({
45
+ _storageVersion: fdeWorkflowStorageVersion,
46
+ activeFormUuid: 'triage-form',
47
+ });
48
+ });
49
+
50
+ it('restores a saved workflow and applies a patient from the URL when provided', () => {
51
+ localStorage.setItem(
52
+ `${fdeWorkflowStorageName}:user-1`,
53
+ JSON.stringify({
54
+ _storageVersion: fdeWorkflowStorageVersion,
55
+ activeFormUuid: 'triage-form',
56
+ userUuid: 'user-1',
57
+ forms: {
58
+ 'triage-form': {
59
+ workflowState: 'REVIEW',
60
+ activePatientUuid: null,
61
+ activeEncounterUuid: null,
62
+ patientUuids: ['patient-a'],
63
+ encounters: {},
64
+ },
65
+ },
66
+ }),
67
+ );
68
+
69
+ const state = reducer(initialWorkflowState, {
70
+ type: 'INITIALIZE_WORKFLOW_STATE',
71
+ activeFormUuid: 'triage-form',
72
+ newPatientUuid: 'patient-b',
73
+ userUuid: 'user-1',
74
+ });
75
+
76
+ expect(state.forms['triage-form']).toMatchObject({
77
+ workflowState: 'EDIT_FORM',
78
+ activePatientUuid: 'patient-b',
79
+ });
80
+ expect(state.forms['triage-form'].patientUuids).toEqual(['patient-a', 'patient-b']);
81
+ });
82
+
83
+ it('dispatches the submit event and moves the workflow into SUBMIT_FOR_NEXT', () => {
84
+ const dispatchEventSpy = jest.spyOn(window, 'dispatchEvent');
85
+ const state = buildState({
86
+ workflowState: 'EDIT_FORM',
87
+ activePatientUuid: 'patient-a',
88
+ });
89
+
90
+ const nextState = reducer(state, {
91
+ type: 'SUBMIT_FOR_NEXT',
92
+ });
93
+
94
+ expect(nextState.forms['triage-form'].workflowState).toBe('SUBMIT_FOR_NEXT');
95
+ expect(dispatchEventSpy).toHaveBeenCalledTimes(1);
96
+
97
+ const event = dispatchEventSpy.mock.calls[0][0] as CustomEvent;
98
+ expect(event.type).toBe('ampath-form-action');
99
+ expect(event.detail).toEqual({
100
+ formUuid: 'triage-form',
101
+ patientUuid: 'patient-a',
102
+ action: 'onSubmit',
103
+ });
104
+ });
105
+
106
+ it('stores the encounter and returns to NEW_PATIENT after saving for next', () => {
107
+ const state = buildState({
108
+ workflowState: 'SUBMIT_FOR_NEXT',
109
+ activePatientUuid: 'patient-a',
110
+ });
111
+
112
+ const nextState = reducer(state, {
113
+ type: 'SAVE_ENCOUNTER',
114
+ encounterUuid: 'encounter-1',
115
+ });
116
+
117
+ expect(nextState.forms['triage-form']).toMatchObject({
118
+ workflowState: 'NEW_PATIENT',
119
+ activePatientUuid: null,
120
+ activeEncounterUuid: null,
121
+ encounters: {
122
+ 'patient-a': 'encounter-1',
123
+ },
124
+ });
125
+ });
126
+
127
+ it('destroys the active form session and navigates back to the forms page after complete', () => {
128
+ const state = buildState({
129
+ workflowState: 'SUBMIT_FOR_COMPLETE',
130
+ activePatientUuid: 'patient-a',
131
+ });
132
+
133
+ const nextState = reducer(state, {
134
+ type: 'SAVE_ENCOUNTER',
135
+ encounterUuid: 'encounter-1',
136
+ });
137
+
138
+ expect(nextState.activeFormUuid).toBeNull();
139
+ expect(nextState.forms).toEqual({});
140
+ expect(mockNavigate).toHaveBeenCalledWith({ to: '${openmrsSpaBase}/forms' });
141
+ });
142
+ });
@@ -0,0 +1,302 @@
1
+ import { navigate } from '@openmrs/esm-framework';
2
+ import { initialWorkflowState } from './GroupFormWorkflowContext';
3
+ import reducer, { fdeGroupWorkflowStorageName, fdeGroupWorkflowStorageVersion } from './GroupFormWorkflowReducer';
4
+
5
+ jest.mock('uuid', () => ({
6
+ v4: jest.fn(() => 'generated-session-uuid'),
7
+ }));
8
+
9
+ const mockNavigate = jest.mocked(navigate);
10
+
11
+ const buildState = (formStateOverrides = {}, rootStateOverrides = {}) => ({
12
+ ...initialWorkflowState,
13
+ activeFormUuid: 'group-form',
14
+ userUuid: 'user-1',
15
+ forms: {
16
+ 'group-form': {
17
+ workflowState: 'NEW_GROUP_SESSION',
18
+ groupUuid: null,
19
+ groupName: null,
20
+ groupMembers: [],
21
+ activePatientUuid: null,
22
+ activeEncounterUuid: null,
23
+ activeVisitUuid: null,
24
+ activeSessionUuid: null,
25
+ patientUuids: [],
26
+ encounters: {},
27
+ visits: {},
28
+ ...formStateOverrides,
29
+ },
30
+ },
31
+ ...rootStateOverrides,
32
+ });
33
+
34
+ describe('GroupFormWorkflowReducer', () => {
35
+ beforeEach(() => {
36
+ localStorage.clear();
37
+ });
38
+
39
+ it('initializes a fresh group workflow state when there is no saved session', () => {
40
+ const state = reducer(initialWorkflowState, {
41
+ type: 'INITIALIZE_WORKFLOW_STATE',
42
+ activeFormUuid: 'group-form',
43
+ userUuid: 'user-1',
44
+ });
45
+
46
+ expect(state.activeFormUuid).toBe('group-form');
47
+ expect(state.forms['group-form']).toMatchObject({
48
+ workflowState: 'NEW_GROUP_SESSION',
49
+ groupUuid: null,
50
+ patientUuids: [],
51
+ encounters: {},
52
+ visits: {},
53
+ });
54
+
55
+ expect(JSON.parse(localStorage.getItem(`${fdeGroupWorkflowStorageName}:user-1`))).toMatchObject({
56
+ _storageVersion: fdeGroupWorkflowStorageVersion,
57
+ activeFormUuid: 'group-form',
58
+ });
59
+ });
60
+
61
+ it('restores a saved workflow and derives the current patient and visit state', () => {
62
+ localStorage.setItem(
63
+ `${fdeGroupWorkflowStorageName}:user-1`,
64
+ JSON.stringify({
65
+ _storageVersion: fdeGroupWorkflowStorageVersion,
66
+ activeFormUuid: 'group-form',
67
+ userUuid: 'user-1',
68
+ forms: {
69
+ 'group-form': {
70
+ workflowState: 'EDIT_FORM',
71
+ patientUuids: ['patient-a', 'patient-b'],
72
+ encounters: {
73
+ 'patient-a': 'encounter-a',
74
+ },
75
+ visits: {
76
+ 'patient-a': 'visit-a',
77
+ },
78
+ },
79
+ },
80
+ }),
81
+ );
82
+
83
+ const state = reducer(initialWorkflowState, {
84
+ type: 'INITIALIZE_WORKFLOW_STATE',
85
+ activeFormUuid: 'group-form',
86
+ userUuid: 'user-1',
87
+ });
88
+
89
+ expect(state.forms['group-form']).toMatchObject({
90
+ workflowState: 'EDIT_FORM',
91
+ activePatientUuid: 'patient-a',
92
+ activeEncounterUuid: 'encounter-a',
93
+ activeVisitUuid: 'visit-a',
94
+ activeSessionUuid: 'generated-session-uuid',
95
+ });
96
+ });
97
+
98
+ it('stores the selected group and clears the active patient state', () => {
99
+ const state = buildState({
100
+ activePatientUuid: 'patient-z',
101
+ activeEncounterUuid: 'encounter-z',
102
+ activeVisitUuid: 'visit-z',
103
+ activeSessionUuid: 'session-z',
104
+ });
105
+
106
+ const nextState = reducer(state, {
107
+ type: 'SET_GROUP',
108
+ group: {
109
+ uuid: 'cohort-1',
110
+ name: 'Nutrition Cohort',
111
+ cohortMembers: [{ patient: { uuid: 'patient-a' } }, { patient: { uuid: 'patient-b' } }],
112
+ },
113
+ });
114
+
115
+ expect(nextState.forms['group-form']).toMatchObject({
116
+ groupUuid: 'cohort-1',
117
+ groupName: 'Nutrition Cohort',
118
+ groupMembers: ['patient-a', 'patient-b'],
119
+ patientUuids: ['patient-a', 'patient-b'],
120
+ activePatientUuid: null,
121
+ activeEncounterUuid: null,
122
+ activeVisitUuid: null,
123
+ activeSessionUuid: null,
124
+ });
125
+ });
126
+
127
+ it('sets session metadata and moves to the first patient in edit mode', () => {
128
+ const state = buildState({
129
+ patientUuids: ['patient-a', 'patient-b'],
130
+ encounters: {
131
+ 'patient-a': 'encounter-a',
132
+ },
133
+ visits: {
134
+ 'patient-a': 'visit-a',
135
+ },
136
+ });
137
+
138
+ const nextState = reducer(state, {
139
+ type: 'SET_SESSION_META',
140
+ meta: {
141
+ sessionName: 'April Session',
142
+ practitionerName: 'Alice',
143
+ sessionDate: '2026-04-15',
144
+ sessionNotes: 'Notes',
145
+ },
146
+ });
147
+
148
+ expect(nextState.forms['group-form']).toMatchObject({
149
+ sessionMeta: {
150
+ sessionName: 'April Session',
151
+ practitionerName: 'Alice',
152
+ sessionDate: '2026-04-15',
153
+ sessionNotes: 'Notes',
154
+ },
155
+ activePatientUuid: 'patient-a',
156
+ activeEncounterUuid: 'encounter-a',
157
+ activeVisitUuid: 'visit-a',
158
+ activeSessionUuid: 'generated-session-uuid',
159
+ workflowState: 'EDIT_FORM',
160
+ });
161
+ });
162
+
163
+ it('adds and removes patient UUIDs without duplicating entries', () => {
164
+ const state = buildState({
165
+ patientUuids: ['patient-a'],
166
+ });
167
+
168
+ const unchangedState = reducer(state, {
169
+ type: 'ADD_PATIENT_UUID',
170
+ patientUuid: 'patient-a',
171
+ });
172
+ expect(unchangedState).toBe(state);
173
+
174
+ const addedState = reducer(state, {
175
+ type: 'ADD_PATIENT_UUID',
176
+ patientUuid: 'patient-b',
177
+ });
178
+ expect(addedState.forms['group-form'].patientUuids).toEqual(['patient-a', 'patient-b']);
179
+
180
+ const removedState = reducer(addedState, {
181
+ type: 'REMOVE_PATIENT_UUID',
182
+ patientUuid: 'patient-a',
183
+ });
184
+ expect(removedState.forms['group-form'].patientUuids).toEqual(['patient-b']);
185
+ });
186
+
187
+ it('dispatches validate events and stores the visit UUID for the active patient', () => {
188
+ const dispatchEventSpy = jest.spyOn(window, 'dispatchEvent');
189
+ const state = buildState({
190
+ workflowState: 'EDIT_FORM',
191
+ activePatientUuid: 'patient-a',
192
+ });
193
+
194
+ const validatingState = reducer(state, {
195
+ type: 'VALIDATE_FOR_NEXT',
196
+ });
197
+
198
+ expect(validatingState.forms['group-form'].workflowState).toBe('VALIDATE_FOR_NEXT');
199
+ const event = dispatchEventSpy.mock.calls[0][0] as CustomEvent;
200
+ expect(event.detail).toEqual({
201
+ formUuid: 'group-form',
202
+ patientUuid: 'patient-a',
203
+ action: 'validateForm',
204
+ });
205
+
206
+ const visitState = reducer(state, {
207
+ type: 'UPDATE_VISIT_UUID',
208
+ visitUuid: 'visit-a',
209
+ });
210
+
211
+ expect(visitState.forms['group-form']).toMatchObject({
212
+ activeVisitUuid: 'visit-a',
213
+ visits: {
214
+ 'patient-a': 'visit-a',
215
+ },
216
+ });
217
+ });
218
+
219
+ it('submits for next and advances to the requested patient after saving', () => {
220
+ const dispatchEventSpy = jest.spyOn(window, 'dispatchEvent');
221
+ const state = buildState(
222
+ {
223
+ workflowState: 'EDIT_FORM',
224
+ activePatientUuid: 'patient-a',
225
+ patientUuids: ['patient-a', 'patient-b', 'patient-c'],
226
+ visits: {
227
+ 'patient-c': 'visit-c',
228
+ },
229
+ },
230
+ {
231
+ nextPatientUuid: null,
232
+ },
233
+ );
234
+
235
+ const submittingState = reducer(state, {
236
+ type: 'SUBMIT_FOR_NEXT',
237
+ nextPatientUuid: 'patient-c',
238
+ });
239
+
240
+ expect(submittingState.forms['group-form'].workflowState).toBe('SUBMIT_FOR_NEXT');
241
+ expect(submittingState.nextPatientUuid).toBe('patient-c');
242
+ const submitEvent = dispatchEventSpy.mock.calls[0][0] as CustomEvent;
243
+ expect(submitEvent.detail).toEqual({
244
+ formUuid: 'group-form',
245
+ patientUuid: 'patient-a',
246
+ action: 'onSubmit',
247
+ });
248
+
249
+ const savedState = reducer(submittingState, {
250
+ type: 'SAVE_ENCOUNTER',
251
+ encounterUuid: 'encounter-a',
252
+ });
253
+
254
+ expect(savedState.forms['group-form']).toMatchObject({
255
+ workflowState: 'EDIT_FORM',
256
+ activePatientUuid: 'patient-c',
257
+ activeEncounterUuid: null,
258
+ activeVisitUuid: 'visit-c',
259
+ encounters: {
260
+ 'patient-a': 'encounter-a',
261
+ },
262
+ });
263
+ });
264
+
265
+ it('clears the active session pointers when going to review', () => {
266
+ const state = buildState({
267
+ workflowState: 'EDIT_FORM',
268
+ activePatientUuid: 'patient-a',
269
+ activeEncounterUuid: 'encounter-a',
270
+ activeVisitUuid: 'visit-a',
271
+ activeSessionUuid: 'session-a',
272
+ });
273
+
274
+ const nextState = reducer(state, {
275
+ type: 'GO_TO_REVIEW',
276
+ });
277
+
278
+ expect(nextState.forms['group-form']).toMatchObject({
279
+ workflowState: 'REVIEW',
280
+ activePatientUuid: null,
281
+ activeEncounterUuid: null,
282
+ activeVisitUuid: null,
283
+ activeSessionUuid: null,
284
+ });
285
+ });
286
+
287
+ it('destroys the active group session and navigates back to forms', () => {
288
+ const state = buildState({
289
+ workflowState: 'SUBMIT_FOR_COMPLETE',
290
+ activePatientUuid: 'patient-a',
291
+ });
292
+
293
+ const nextState = reducer(state, {
294
+ type: 'DESTROY_SESSION',
295
+ });
296
+
297
+ expect(nextState.activeFormUuid).toBeNull();
298
+ expect(nextState.forms).toEqual({});
299
+ expect(nextState.formDestroyed).toBe(true);
300
+ expect(mockNavigate).toHaveBeenCalledWith({ to: '${openmrsSpaBase}/forms' });
301
+ });
302
+ });
@@ -365,7 +365,7 @@ const reducer = (state, action) => {
365
365
  [state.activeFormUuid]: {
366
366
  ...state.forms[state.activeFormUuid],
367
367
  activeEncounterUuid: null,
368
- activVisitUuid: null,
368
+ activeVisitUuid: null,
369
369
  activePatientUuid: null,
370
370
  activeSessionUuid: null,
371
371
  workflowState: 'REVIEW',
@@ -1,3 +1,2 @@
1
1
  declare module '*.css';
2
2
  declare module '*.scss';
3
- declare type SideNavProps = object;
@@ -0,0 +1,190 @@
1
+ import React from 'react';
2
+ import { act, render, screen } from '@testing-library/react';
3
+ import userEvent from '@testing-library/user-event';
4
+ import { getGlobalStore, useConfig, useSession, useStore } from '@openmrs/esm-framework';
5
+ import FormBootstrap from '../FormBootstrap';
6
+ import GroupFormWorkflowContext from '../context/GroupFormWorkflowContext';
7
+ import GroupSessionWorkspace from './GroupSessionWorkspace';
8
+
9
+ jest.mock('@openmrs/esm-framework', () => ({
10
+ getGlobalStore: jest.fn(),
11
+ useConfig: jest.fn(),
12
+ useSession: jest.fn(),
13
+ useStore: jest.fn(),
14
+ }));
15
+
16
+ jest.mock('uuid', () => ({
17
+ v4: jest.fn(() => 'generated-visit-uuid'),
18
+ }));
19
+
20
+ jest.mock('../FormBootstrap', () => ({
21
+ __esModule: true,
22
+ default: jest.fn(() => <div data-testid="form-bootstrap" />),
23
+ }));
24
+
25
+ jest.mock('../patient-card/PatientCard', () => ({
26
+ __esModule: true,
27
+ default: ({ patientUuid, editEncounter }) => (
28
+ <button data-testid={`patient-card-${patientUuid}`} onClick={() => editEncounter(patientUuid)}>
29
+ {patientUuid}
30
+ </button>
31
+ ),
32
+ }));
33
+
34
+ jest.mock('../CancelModal', () => ({
35
+ __esModule: true,
36
+ default: () => null,
37
+ }));
38
+
39
+ jest.mock('../CompleteModal', () => ({
40
+ __esModule: true,
41
+ default: () => null,
42
+ }));
43
+
44
+ const mockGetGlobalStore = jest.mocked(getGlobalStore);
45
+ const mockUseConfig = jest.mocked(useConfig);
46
+ const mockUseSession = jest.mocked(useSession);
47
+ const mockUseStore = jest.mocked(useStore);
48
+ const mockFormBootstrap = FormBootstrap as jest.Mock;
49
+
50
+ const renderWorkspace = (contextOverrides = {}) => {
51
+ const defaultContext = {
52
+ workflowState: 'EDIT_FORM',
53
+ patientUuids: ['patient-a', 'patient-b'],
54
+ activePatientUuid: 'patient-a',
55
+ activeEncounterUuid: null,
56
+ activeVisitUuid: null,
57
+ activeFormUuid: 'group-form',
58
+ activeGroupUuid: 'group-1',
59
+ activeGroupName: 'Nutrition Cohort',
60
+ activeSessionUuid: 'session-1',
61
+ activeSessionMeta: {
62
+ sessionName: 'April Session',
63
+ practitionerName: 'Alice',
64
+ sessionDate: '2026-04-15',
65
+ sessionNotes: 'Bring notebooks',
66
+ },
67
+ groupVisitTypeUuid: 'visit-type-1',
68
+ encounters: {},
69
+ saveEncounter: jest.fn(),
70
+ updateVisitUuid: jest.fn(),
71
+ submitForNext: jest.fn(),
72
+ };
73
+
74
+ return render(
75
+ <GroupFormWorkflowContext.Provider value={{ ...defaultContext, ...contextOverrides } as never}>
76
+ <GroupSessionWorkspace />
77
+ </GroupFormWorkflowContext.Provider>,
78
+ );
79
+ };
80
+
81
+ describe('GroupSessionWorkspace', () => {
82
+ beforeEach(() => {
83
+ mockGetGlobalStore.mockReturnValue('ampath-form-state' as never);
84
+ mockUseStore.mockReturnValue({
85
+ 'group-form': 'ready',
86
+ } as never);
87
+ mockUseSession.mockReturnValue({
88
+ sessionLocation: {
89
+ uuid: 'session-location',
90
+ display: 'General Hospital',
91
+ },
92
+ } as never);
93
+ mockUseConfig.mockReturnValue({
94
+ groupSessionConcepts: {
95
+ sessionName: 'concept-session-name',
96
+ practitionerName: 'concept-practitioner',
97
+ sessionNotes: 'concept-notes',
98
+ sessionDate: 'concept-date',
99
+ cohortId: 'concept-cohort-id',
100
+ cohortName: 'concept-cohort-name',
101
+ sessionUuid: 'concept-session-uuid',
102
+ },
103
+ } as never);
104
+ });
105
+
106
+ it('builds encounter payloads with group-session metadata when no visit exists yet', () => {
107
+ const updateVisitUuid = jest.fn();
108
+ renderWorkspace({ updateVisitUuid });
109
+
110
+ const [formBootstrapProps] = mockFormBootstrap.mock.calls[0];
111
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
112
+ const payload: Record<string, any> = {
113
+ obs: [
114
+ {
115
+ concept: 'weight-concept',
116
+ value: '70',
117
+ groupMembers: [{ concept: 'height-concept', value: '175' }],
118
+ },
119
+ ],
120
+ };
121
+
122
+ act(() => {
123
+ formBootstrapProps.handleEncounterCreate(payload);
124
+ });
125
+
126
+ const expectedObsDatetime = new Date('2026-04-15').toISOString();
127
+
128
+ expect(payload.location).toBe('session-location');
129
+ expect(payload.encounterDatetime).toBe(expectedObsDatetime);
130
+ expect(payload.obs[0]).toEqual(
131
+ expect.objectContaining({
132
+ obsDatetime: expectedObsDatetime,
133
+ groupMembers: [
134
+ expect.objectContaining({
135
+ concept: 'height-concept',
136
+ value: '175',
137
+ obsDatetime: expectedObsDatetime,
138
+ }),
139
+ ],
140
+ }),
141
+ );
142
+ expect(payload.obs).toEqual(
143
+ expect.arrayContaining([
144
+ expect.objectContaining({ concept: 'concept-session-name', value: 'April Session' }),
145
+ expect.objectContaining({ concept: 'concept-practitioner', value: 'Alice' }),
146
+ expect.objectContaining({ concept: 'concept-notes', value: 'Bring notebooks' }),
147
+ expect.objectContaining({ concept: 'concept-date', value: '2026-04-15' }),
148
+ expect.objectContaining({ concept: 'concept-cohort-id', value: 'group-1' }),
149
+ expect.objectContaining({ concept: 'concept-cohort-name', value: 'Nutrition Cohort' }),
150
+ expect.objectContaining({ concept: 'concept-session-uuid', value: 'session-1' }),
151
+ ]),
152
+ );
153
+ expect(payload.visit).toEqual({
154
+ startDatetime: '2026-04-15',
155
+ stopDatetime: '2026-04-15',
156
+ uuid: 'generated-visit-uuid',
157
+ patient: {
158
+ uuid: 'patient-a',
159
+ },
160
+ location: {
161
+ uuid: 'session-location',
162
+ },
163
+ visitType: {
164
+ uuid: 'visit-type-1',
165
+ },
166
+ });
167
+ expect(updateVisitUuid).toHaveBeenCalledWith('generated-visit-uuid');
168
+ });
169
+
170
+ it('wires patient switching and save actions through the workflow callbacks', async () => {
171
+ const user = userEvent.setup();
172
+ const saveEncounter = jest.fn();
173
+ const submitForNext = jest.fn();
174
+ renderWorkspace({ saveEncounter, submitForNext });
175
+
176
+ const [formBootstrapProps] = mockFormBootstrap.mock.calls[0];
177
+
178
+ act(() => {
179
+ formBootstrapProps.handlePostResponse({ uuid: 'encounter-1' });
180
+ });
181
+
182
+ expect(saveEncounter).toHaveBeenCalledWith('encounter-1');
183
+
184
+ await user.click(screen.getByTestId('patient-card-patient-b'));
185
+ expect(submitForNext).toHaveBeenCalledWith('patient-b');
186
+
187
+ await user.click(screen.getByRole('button', { name: 'Next patient' }));
188
+ expect(submitForNext).toHaveBeenCalledWith();
189
+ });
190
+ });