@openmrs/esm-styleguide 8.0.1-pre.3511 → 8.0.1-pre.3525
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 +3 -3
- package/dist/location-picker/location-picker.resource.d.ts +1 -0
- package/dist/openmrs-esm-styleguide.css +1 -1
- package/dist/openmrs-esm-styleguide.css.map +1 -1
- package/dist/openmrs-esm-styleguide.js +2 -2
- package/dist/openmrs-esm-styleguide.js.map +1 -1
- package/package.json +15 -13
- package/src/location-picker/location-picker.component.tsx +50 -24
- package/src/location-picker/location-picker.module.scss +4 -17
- package/src/location-picker/location-picker.resource.ts +4 -13
- package/src/location-picker/location-picker.test.tsx +347 -51
- package/dist/brand.d.ts +0 -1
- package/dist/breakpoints/index.d.ts +0 -11
- package/dist/config-schema.d.ts +0 -23
- package/dist/custom-overflow-menu/custom-overflow-menu.component.d.ts +0 -8
- package/dist/custom-overflow-menu/index.d.ts +0 -1
- package/dist/datepicker/DatePickerIcon.d.ts +0 -6
- package/dist/datepicker/DatePickerInput.d.ts +0 -11
- package/dist/datepicker/MonthYear.d.ts +0 -10
- package/dist/datepicker/locale-context.d.ts +0 -2
- package/dist/datepicker/utils.d.ts +0 -15
- package/dist/error-state/error-state.component.d.ts +0 -6
- package/dist/error-state/index.d.ts +0 -1
- package/dist/icons/icon-registration.d.ts +0 -1
- package/dist/icons/icons.d.ts +0 -329
- package/dist/icons/index.d.ts +0 -1
- package/dist/index.d.ts +0 -1
- package/dist/left-nav/index.d.ts +0 -23
- package/dist/logo/index.d.ts +0 -1
- package/dist/modals/index.d.ts +0 -25
- package/dist/notifications/actionable-notification.component.d.ts +0 -20
- package/dist/notifications/active-actionable-notifications.component.d.ts +0 -8
- package/dist/notifications/active-notifications.component.d.ts +0 -8
- package/dist/notifications/index.d.ts +0 -19
- package/dist/notifications/notification.component.d.ts +0 -19
- package/dist/pictograms/pictogram-registration.d.ts +0 -1
- package/dist/pictograms/pictograms.d.ts +0 -64
- package/dist/snackbars/active-snackbar.component.d.ts +0 -9
- package/dist/snackbars/index.d.ts +0 -12
- package/dist/snackbars/snackbar.component.d.ts +0 -22
- package/dist/svg-utils.d.ts +0 -1
- package/dist/toasts/active-toasts.component.d.ts +0 -9
- package/dist/toasts/index.d.ts +0 -12
- package/dist/toasts/toast.component.d.ts +0 -19
- package/dist/utils.d.ts +0 -6
- package/dist/workspaces/action-menu-button/action-menu-button.component.d.ts +0 -11
- package/dist/workspaces/container/action-menu.component.d.ts +0 -9
- package/dist/workspaces/container/workspace-container.component.d.ts +0 -54
- package/dist/workspaces/container/workspace-renderer.component.d.ts +0 -8
- package/dist/workspaces/notification/workspace-notification.component.d.ts +0 -6
- package/dist/workspaces/public.d.ts +0 -4
- package/dist/workspaces/workspace-sidebar-store/useWorkspaceGroupStore.d.ts +0 -11
- package/dist/workspaces/workspaces.d.ts +0 -236
- package/dist/workspaces2/workspace2-close-prompt.modal.d.ts +0 -11
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
/* eslint-disable */
|
|
2
1
|
import React from 'react';
|
|
3
|
-
import { describe, expect, it, vi } from 'vitest';
|
|
4
|
-
import
|
|
2
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
3
|
+
import '@testing-library/jest-dom/vitest';
|
|
4
|
+
import { render, screen, waitFor } from '@testing-library/react';
|
|
5
5
|
import userEvent from '@testing-library/user-event';
|
|
6
6
|
import { type LoggedInUser, type Session } from '@openmrs/esm-api';
|
|
7
|
+
import { type FHIRLocationResource } from '@openmrs/esm-emr-api';
|
|
7
8
|
import { useConfig, useSession } from '@openmrs/esm-react-utils';
|
|
8
9
|
import {
|
|
9
10
|
inpatientWardResponse,
|
|
@@ -13,21 +14,20 @@ import {
|
|
|
13
14
|
} from '../../__mocks__/locations.mock';
|
|
14
15
|
import { mockConfig } from '../../__mocks__/config.mock';
|
|
15
16
|
import { LocationPicker } from './location-picker.component';
|
|
17
|
+
import { useLocationByUuid, useLocations } from './location-picker.resource';
|
|
16
18
|
|
|
17
19
|
const validLocationUuid = '1ce1b7d4-c865-4178-82b0-5932e51503d6';
|
|
18
20
|
const inpatientWardLocationUuid = 'ba685651-ed3b-4e63-9b35-78893060758a';
|
|
19
21
|
|
|
20
22
|
const mockUseConfig = vi.mocked(useConfig);
|
|
21
23
|
const mockUseSession = vi.mocked(useSession);
|
|
24
|
+
const mockUseLocationByUuid = vi.mocked(useLocationByUuid);
|
|
25
|
+
const mockUseLocations = vi.mocked(useLocations);
|
|
22
26
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
uuid: '90bd24b3-e700-46b0-a5ef-c85afdfededd',
|
|
28
|
-
userProperties: {},
|
|
29
|
-
} as LoggedInUser,
|
|
30
|
-
} as Session);
|
|
27
|
+
vi.mock('./location-picker.resource', () => ({
|
|
28
|
+
useLocationByUuid: vi.fn(),
|
|
29
|
+
useLocations: vi.fn(),
|
|
30
|
+
}));
|
|
31
31
|
|
|
32
32
|
vi.mock('@openmrs/esm-api', async () => ({
|
|
33
33
|
...(await import('@openmrs/esm-api')),
|
|
@@ -48,33 +48,58 @@ vi.mock('@openmrs/esm-api', async () => ({
|
|
|
48
48
|
}));
|
|
49
49
|
|
|
50
50
|
describe('LocationPicker', () => {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
51
|
+
beforeEach(() => {
|
|
52
|
+
mockUseConfig.mockReturnValue(mockConfig);
|
|
53
|
+
mockUseSession.mockReturnValue({
|
|
54
|
+
user: {
|
|
55
|
+
display: 'Testy McTesterface',
|
|
56
|
+
uuid: '90bd24b3-e700-46b0-a5ef-c85afdfededd',
|
|
57
|
+
userProperties: {},
|
|
58
|
+
} as LoggedInUser,
|
|
59
|
+
} as Session);
|
|
60
|
+
|
|
61
|
+
mockUseLocationByUuid.mockReturnValue({
|
|
62
|
+
location: null,
|
|
63
|
+
error: null,
|
|
64
|
+
isLoading: false,
|
|
54
65
|
});
|
|
55
66
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
67
|
+
mockUseLocations.mockReturnValue({
|
|
68
|
+
locations: mockLoginLocations.data.entry as Array<FHIRLocationResource>,
|
|
69
|
+
isLoading: false,
|
|
70
|
+
totalResults: 4,
|
|
71
|
+
hasMore: false,
|
|
72
|
+
loadingNewData: false,
|
|
73
|
+
error: null,
|
|
74
|
+
setPage: vi.fn().mockResolvedValue(undefined),
|
|
75
|
+
});
|
|
76
|
+
});
|
|
62
77
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
const expectedLocations = [/community outreach/, /inpatient ward/, /mobile clinic/, /outpatient clinic/];
|
|
78
|
+
it('should render a search input and list of login locations', async () => {
|
|
79
|
+
render(<LocationPicker selectedLocationUuid={inpatientWardLocationUuid} onChange={vi.fn()} />);
|
|
66
80
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
81
|
+
const searchInput = screen.getByRole('searchbox', { name: /search for a location/i });
|
|
82
|
+
expect(searchInput).toBeInTheDocument();
|
|
83
|
+
|
|
84
|
+
await waitFor(() => {
|
|
85
|
+
const locations = screen.getAllByRole('radio');
|
|
86
|
+
expect(locations).toHaveLength(4);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
const expectedLocations = [/community outreach/, /inpatient ward/, /mobile clinic/, /outpatient clinic/];
|
|
90
|
+
expectedLocations.forEach((locationName) => {
|
|
91
|
+
expect(screen.getByRole('radio', { name: new RegExp(locationName, 'i') })).toBeInTheDocument();
|
|
92
|
+
});
|
|
70
93
|
});
|
|
71
94
|
|
|
72
|
-
it('call onChange when a location is selected', async () => {
|
|
95
|
+
it('should call onChange when a location is selected', async () => {
|
|
73
96
|
const user = userEvent.setup();
|
|
74
97
|
const handleChange = vi.fn();
|
|
75
98
|
|
|
76
|
-
|
|
77
|
-
|
|
99
|
+
render(<LocationPicker selectedLocationUuid={validLocationUuid} onChange={handleChange} />);
|
|
100
|
+
|
|
101
|
+
await waitFor(() => {
|
|
102
|
+
expect(screen.getByRole('radio', { name: /inpatient ward/i })).toBeInTheDocument();
|
|
78
103
|
});
|
|
79
104
|
|
|
80
105
|
const location = screen.getByRole('radio', { name: /inpatient ward/i });
|
|
@@ -83,51 +108,322 @@ describe('LocationPicker', () => {
|
|
|
83
108
|
expect(handleChange).toHaveBeenCalledWith(inpatientWardLocationUuid);
|
|
84
109
|
});
|
|
85
110
|
|
|
86
|
-
it('
|
|
87
|
-
|
|
88
|
-
|
|
111
|
+
it('should select the provided selectedLocation when the component is rendered', async () => {
|
|
112
|
+
render(<LocationPicker selectedLocationUuid={inpatientWardLocationUuid} onChange={vi.fn()} />);
|
|
113
|
+
|
|
114
|
+
await waitFor(() => {
|
|
115
|
+
const inpatientWardOption = screen.getByRole('radio', { name: /inpatient ward/i });
|
|
116
|
+
expect(inpatientWardOption).toBeChecked();
|
|
89
117
|
});
|
|
90
|
-
const inpatientWardOption = screen.getByRole('radio', { name: /inpatient ward/i });
|
|
91
|
-
expect(inpatientWardOption).toBeChecked();
|
|
92
118
|
});
|
|
93
119
|
|
|
94
|
-
it('
|
|
95
|
-
|
|
96
|
-
|
|
120
|
+
it('should load the default location on top of the list', async () => {
|
|
121
|
+
mockUseLocationByUuid.mockReturnValue({
|
|
122
|
+
location: inpatientWardResponse.data.entry[0] as any,
|
|
123
|
+
error: null,
|
|
124
|
+
isLoading: false,
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
render(<LocationPicker defaultLocationUuid={inpatientWardLocationUuid} onChange={vi.fn()} />);
|
|
128
|
+
|
|
129
|
+
await waitFor(() => {
|
|
130
|
+
const locations = screen.getAllByRole('radio');
|
|
131
|
+
expect(locations).toHaveLength(4);
|
|
97
132
|
});
|
|
98
133
|
|
|
134
|
+
// Verify the default location (Inpatient Ward) appears first in the list
|
|
99
135
|
const locations = screen.getAllByRole('radio');
|
|
100
|
-
expect(locations
|
|
101
|
-
expect(locations[0].getAttribute('value')).toBe(inpatientWardLocationUuid);
|
|
136
|
+
expect(locations[0]).toHaveAccessibleName(/inpatient ward/i);
|
|
102
137
|
|
|
103
138
|
const expectedLocations = [/community outreach/, /inpatient ward/, /mobile clinic/, /outpatient clinic/];
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
);
|
|
139
|
+
expectedLocations.forEach((locationName) => {
|
|
140
|
+
expect(screen.getByRole('radio', { name: new RegExp(locationName, 'i') })).toBeInTheDocument();
|
|
141
|
+
});
|
|
108
142
|
});
|
|
109
143
|
|
|
110
144
|
it('should not display the default location if search result does not contain the default location', async () => {
|
|
111
145
|
const user = userEvent.setup();
|
|
112
|
-
|
|
113
|
-
|
|
146
|
+
|
|
147
|
+
mockUseLocationByUuid.mockReturnValue({
|
|
148
|
+
location: inpatientWardResponse.data.entry[0] as any,
|
|
149
|
+
error: null,
|
|
150
|
+
isLoading: false,
|
|
114
151
|
});
|
|
152
|
+
|
|
153
|
+
// Mock useLocations to return different results based on search query
|
|
154
|
+
mockUseLocations.mockImplementation((locationTag, count, searchQuery) => {
|
|
155
|
+
if (searchQuery === 'outpatient') {
|
|
156
|
+
return {
|
|
157
|
+
locations: outpatientClinicResponse.data.entry as any,
|
|
158
|
+
isLoading: false,
|
|
159
|
+
totalResults: 1,
|
|
160
|
+
hasMore: false,
|
|
161
|
+
loadingNewData: false,
|
|
162
|
+
error: null,
|
|
163
|
+
setPage: vi.fn().mockResolvedValue(undefined),
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
return {
|
|
167
|
+
locations: mockLoginLocations.data.entry as any,
|
|
168
|
+
isLoading: false,
|
|
169
|
+
totalResults: 4,
|
|
170
|
+
hasMore: false,
|
|
171
|
+
loadingNewData: false,
|
|
172
|
+
error: null,
|
|
173
|
+
setPage: vi.fn().mockResolvedValue(undefined),
|
|
174
|
+
};
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
render(<LocationPicker defaultLocationUuid={inpatientWardLocationUuid} onChange={vi.fn()} />);
|
|
178
|
+
|
|
179
|
+
await waitFor(() => {
|
|
180
|
+
expect(screen.getByRole('searchbox', { name: /search for a location/i })).toBeInTheDocument();
|
|
181
|
+
});
|
|
182
|
+
|
|
115
183
|
const searchInput = screen.getByRole('searchbox', { name: /search for a location/i });
|
|
116
184
|
await user.type(searchInput, 'outpatient');
|
|
117
185
|
|
|
118
|
-
|
|
186
|
+
await waitFor(() => {
|
|
187
|
+
expect(screen.queryByRole('radio', { name: /inpatient ward/i })).not.toBeInTheDocument();
|
|
188
|
+
});
|
|
119
189
|
});
|
|
120
190
|
|
|
121
|
-
it('should display a message and
|
|
191
|
+
it('should display a message and not display locations when search results are empty', async () => {
|
|
122
192
|
const user = userEvent.setup();
|
|
123
|
-
|
|
124
|
-
|
|
193
|
+
|
|
194
|
+
mockUseLocationByUuid.mockReturnValue({
|
|
195
|
+
location: inpatientWardResponse.data.entry[0] as any,
|
|
196
|
+
error: null,
|
|
197
|
+
isLoading: false,
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
// Mock useLocations to return empty results when searching for non-existent location
|
|
201
|
+
mockUseLocations.mockImplementation((locationTag, count, searchQuery) => {
|
|
202
|
+
if (searchQuery === 'search_for_no_location') {
|
|
203
|
+
return {
|
|
204
|
+
locations: [] as any,
|
|
205
|
+
isLoading: false,
|
|
206
|
+
totalResults: 0,
|
|
207
|
+
hasMore: false,
|
|
208
|
+
loadingNewData: false,
|
|
209
|
+
error: null,
|
|
210
|
+
setPage: vi.fn().mockResolvedValue(undefined),
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
return {
|
|
214
|
+
locations: mockLoginLocations.data.entry as any,
|
|
215
|
+
isLoading: false,
|
|
216
|
+
totalResults: 4,
|
|
217
|
+
hasMore: false,
|
|
218
|
+
loadingNewData: false,
|
|
219
|
+
error: null,
|
|
220
|
+
setPage: vi.fn().mockResolvedValue(undefined),
|
|
221
|
+
};
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
render(<LocationPicker defaultLocationUuid={inpatientWardLocationUuid} onChange={vi.fn()} />);
|
|
225
|
+
|
|
226
|
+
await waitFor(() => {
|
|
227
|
+
expect(screen.getByRole('searchbox', { name: /search for a location/i })).toBeInTheDocument();
|
|
125
228
|
});
|
|
229
|
+
|
|
126
230
|
const searchInput = screen.getByRole('searchbox', { name: /search for a location/i });
|
|
127
231
|
await user.type(searchInput, 'search_for_no_location');
|
|
128
232
|
|
|
129
|
-
|
|
233
|
+
await waitFor(() => {
|
|
234
|
+
expect(screen.getByText(/no results to display/i)).toBeInTheDocument();
|
|
235
|
+
});
|
|
236
|
+
|
|
130
237
|
const locations = screen.queryAllByRole('radio');
|
|
131
|
-
expect(locations
|
|
238
|
+
expect(locations).toHaveLength(0);
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
it('should display skeleton loaders when loading initial data', () => {
|
|
242
|
+
mockUseLocations.mockReturnValue({
|
|
243
|
+
locations: [] as any,
|
|
244
|
+
isLoading: true,
|
|
245
|
+
totalResults: undefined,
|
|
246
|
+
hasMore: false,
|
|
247
|
+
loadingNewData: false,
|
|
248
|
+
error: null,
|
|
249
|
+
setPage: vi.fn().mockResolvedValue(undefined),
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
render(<LocationPicker onChange={vi.fn()} />);
|
|
253
|
+
|
|
254
|
+
const skeletons = screen.getAllByRole('progressbar');
|
|
255
|
+
expect(skeletons).toHaveLength(5);
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
it('should display loading indicator when loading new data', async () => {
|
|
259
|
+
mockUseLocations.mockReturnValue({
|
|
260
|
+
locations: mockLoginLocations.data.entry as any,
|
|
261
|
+
isLoading: false,
|
|
262
|
+
totalResults: 4,
|
|
263
|
+
hasMore: true,
|
|
264
|
+
loadingNewData: true,
|
|
265
|
+
error: null,
|
|
266
|
+
setPage: vi.fn().mockResolvedValue(undefined),
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
render(<LocationPicker onChange={vi.fn()} />);
|
|
270
|
+
|
|
271
|
+
await waitFor(() => {
|
|
272
|
+
// Find the loading text in the InlineLoading component (not in SVG title)
|
|
273
|
+
const loadingTexts = screen.getAllByText(/loading/i);
|
|
274
|
+
const loadingIndicator = loadingTexts.find((element) => element.className.includes('cds--inline-loading__text'));
|
|
275
|
+
expect(loadingIndicator).toBeInTheDocument();
|
|
276
|
+
});
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
it('should call onChange with undefined when search input changes', async () => {
|
|
280
|
+
const user = userEvent.setup();
|
|
281
|
+
const handleChange = vi.fn();
|
|
282
|
+
|
|
283
|
+
render(<LocationPicker onChange={handleChange} />);
|
|
284
|
+
|
|
285
|
+
await waitFor(() => {
|
|
286
|
+
expect(screen.getByRole('searchbox', { name: /search for a location/i })).toBeInTheDocument();
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
const searchInput = screen.getByRole('searchbox', { name: /search for a location/i });
|
|
290
|
+
await user.type(searchInput, 'test');
|
|
291
|
+
|
|
292
|
+
// onChange is called without arguments when search changes, which means locationUuid is undefined
|
|
293
|
+
expect(handleChange).toHaveBeenCalled();
|
|
294
|
+
expect(handleChange.mock.calls[0][0]).toBeUndefined();
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
it('should trim whitespace from search terms', async () => {
|
|
298
|
+
const user = userEvent.setup();
|
|
299
|
+
const handleChange = vi.fn();
|
|
300
|
+
|
|
301
|
+
render(<LocationPicker onChange={handleChange} />);
|
|
302
|
+
|
|
303
|
+
await waitFor(() => {
|
|
304
|
+
expect(screen.getByRole('searchbox', { name: /search for a location/i })).toBeInTheDocument();
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
const searchInput = screen.getByRole('searchbox', { name: /search for a location/i });
|
|
308
|
+
await user.type(searchInput, ' outpatient ');
|
|
309
|
+
|
|
310
|
+
// Verify that the trimmed search term is used (check if the mock was called with trimmed value)
|
|
311
|
+
// The actual trimming happens in the component, so we verify by checking the search was performed
|
|
312
|
+
await waitFor(() => {
|
|
313
|
+
// The search should filter results - verify outpatient clinic appears
|
|
314
|
+
expect(screen.getByRole('radio', { name: /outpatient clinic/i })).toBeInTheDocument();
|
|
315
|
+
});
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
it('should filter out default location from fetched locations to avoid duplicates', async () => {
|
|
319
|
+
const defaultLocationEntry = inpatientWardResponse.data.entry[0];
|
|
320
|
+
const locationsWithDuplicate = [defaultLocationEntry, ...mockLoginLocations.data.entry];
|
|
321
|
+
|
|
322
|
+
mockUseLocationByUuid.mockReturnValue({
|
|
323
|
+
location: defaultLocationEntry as any,
|
|
324
|
+
error: null,
|
|
325
|
+
isLoading: false,
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
mockUseLocations.mockReturnValue({
|
|
329
|
+
locations: locationsWithDuplicate as any,
|
|
330
|
+
isLoading: false,
|
|
331
|
+
totalResults: 5,
|
|
332
|
+
hasMore: false,
|
|
333
|
+
loadingNewData: false,
|
|
334
|
+
error: null,
|
|
335
|
+
setPage: vi.fn().mockResolvedValue(undefined),
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
render(<LocationPicker defaultLocationUuid={inpatientWardLocationUuid} onChange={vi.fn()} />);
|
|
339
|
+
|
|
340
|
+
await waitFor(() => {
|
|
341
|
+
const locations = screen.getAllByRole('radio');
|
|
342
|
+
expect(locations).toHaveLength(4);
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
// Verify the default location (Inpatient Ward) appears first in the list
|
|
346
|
+
const locations = screen.getAllByRole('radio');
|
|
347
|
+
expect(locations[0]).toHaveAccessibleName(/inpatient ward/i);
|
|
348
|
+
|
|
349
|
+
// Verify Inpatient Ward only appears once
|
|
350
|
+
const inpatientWardLocations = screen.getAllByRole('radio', { name: /inpatient ward/i });
|
|
351
|
+
expect(inpatientWardLocations).toHaveLength(1);
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
it('should not show default location when search term is provided', async () => {
|
|
355
|
+
const user = userEvent.setup();
|
|
356
|
+
const defaultLocationEntry = inpatientWardResponse.data.entry[0];
|
|
357
|
+
|
|
358
|
+
mockUseLocationByUuid.mockReturnValue({
|
|
359
|
+
location: defaultLocationEntry as any,
|
|
360
|
+
error: null,
|
|
361
|
+
isLoading: false,
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
// Mock useLocations to return filtered results when searching
|
|
365
|
+
mockUseLocations.mockImplementation((locationTag, count, searchQuery) => {
|
|
366
|
+
if (searchQuery === 'mobile') {
|
|
367
|
+
// Return only Mobile Clinic when searching for "mobile"
|
|
368
|
+
const mobileClinic = mockLoginLocations.data.entry.find((entry) => entry.resource.name === 'Mobile Clinic');
|
|
369
|
+
return {
|
|
370
|
+
locations: mobileClinic ? [mobileClinic] : ([] as any),
|
|
371
|
+
isLoading: false,
|
|
372
|
+
totalResults: 1,
|
|
373
|
+
hasMore: false,
|
|
374
|
+
loadingNewData: false,
|
|
375
|
+
error: null,
|
|
376
|
+
setPage: vi.fn().mockResolvedValue(undefined),
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
return {
|
|
380
|
+
locations: mockLoginLocations.data.entry as any,
|
|
381
|
+
isLoading: false,
|
|
382
|
+
totalResults: 4,
|
|
383
|
+
hasMore: false,
|
|
384
|
+
loadingNewData: false,
|
|
385
|
+
error: null,
|
|
386
|
+
setPage: vi.fn().mockResolvedValue(undefined),
|
|
387
|
+
};
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
render(<LocationPicker defaultLocationUuid={inpatientWardLocationUuid} onChange={vi.fn()} />);
|
|
391
|
+
|
|
392
|
+
await waitFor(() => {
|
|
393
|
+
expect(screen.getByRole('searchbox', { name: /search for a location/i })).toBeInTheDocument();
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
const searchInput = screen.getByRole('searchbox', { name: /search for a location/i });
|
|
397
|
+
await user.type(searchInput, 'mobile');
|
|
398
|
+
|
|
399
|
+
await waitFor(() => {
|
|
400
|
+
// Default location should not appear when searching
|
|
401
|
+
expect(screen.queryByRole('radio', { name: /inpatient ward/i })).not.toBeInTheDocument();
|
|
402
|
+
});
|
|
403
|
+
});
|
|
404
|
+
|
|
405
|
+
it('should display inline error notification when location loading fails', async () => {
|
|
406
|
+
const mockError = new Error('Failed to load locations');
|
|
407
|
+
|
|
408
|
+
mockUseLocations.mockReturnValue({
|
|
409
|
+
locations: [] as any,
|
|
410
|
+
isLoading: false,
|
|
411
|
+
totalResults: undefined,
|
|
412
|
+
hasMore: false,
|
|
413
|
+
loadingNewData: false,
|
|
414
|
+
error: mockError,
|
|
415
|
+
setPage: vi.fn().mockResolvedValue(undefined),
|
|
416
|
+
});
|
|
417
|
+
|
|
418
|
+
render(<LocationPicker onChange={vi.fn()} />);
|
|
419
|
+
|
|
420
|
+
await waitFor(() => {
|
|
421
|
+
// Find the error text in the InlineNotification (not in SVG title)
|
|
422
|
+
const errorTexts = screen.getAllByText(/error/i);
|
|
423
|
+
const errorNotification = errorTexts.find((element) => element.textContent === 'Error');
|
|
424
|
+
expect(errorNotification).toBeInTheDocument();
|
|
425
|
+
});
|
|
426
|
+
|
|
427
|
+
expect(screen.getByText(/unable to load login locations/i)).toBeInTheDocument();
|
|
132
428
|
});
|
|
133
429
|
});
|
package/dist/brand.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function setupBranding(): void;
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
export declare const Breakpoint: {
|
|
2
|
-
readonly PHONE_MIN: 0;
|
|
3
|
-
readonly PHONE_MAX: 600;
|
|
4
|
-
readonly TABLET_MIN: 601;
|
|
5
|
-
readonly TABLET_MAX: 1023;
|
|
6
|
-
readonly SMALL_DESKTOP_MIN: 1024;
|
|
7
|
-
readonly SMALL_DESKTOP_MAX: 1439;
|
|
8
|
-
readonly LARGE_DESKTOP_MIN: 1440;
|
|
9
|
-
readonly LARGE_DESKTOP_MAX: number;
|
|
10
|
-
};
|
|
11
|
-
export declare function integrateBreakpoints(): void;
|
package/dist/config-schema.d.ts
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { type ConfigSchema } from '@openmrs/esm-config';
|
|
2
|
-
import { type CarbonTagColor } from './utils';
|
|
3
|
-
export interface StyleguideConfigObject {
|
|
4
|
-
'Brand color #1': string;
|
|
5
|
-
'Brand color #2': string;
|
|
6
|
-
'Brand color #3': string;
|
|
7
|
-
excludePatientIdentifierCodeTypes: {
|
|
8
|
-
uuids: Array<string>;
|
|
9
|
-
};
|
|
10
|
-
implementationName: string;
|
|
11
|
-
patientPhotoConceptUuid: string;
|
|
12
|
-
preferredCalendar: {
|
|
13
|
-
[key: string]: string;
|
|
14
|
-
};
|
|
15
|
-
preferredDateLocale: {
|
|
16
|
-
[key: string]: string;
|
|
17
|
-
};
|
|
18
|
-
diagnosisTags: {
|
|
19
|
-
primaryColor: CarbonTagColor;
|
|
20
|
-
secondaryColor: CarbonTagColor;
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
export declare const esmStyleGuideSchema: ConfigSchema;
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
/** @module @category UI */
|
|
2
|
-
import React from 'react';
|
|
3
|
-
interface CustomOverflowMenuProps {
|
|
4
|
-
menuTitle: React.ReactNode;
|
|
5
|
-
children: React.ReactNode;
|
|
6
|
-
}
|
|
7
|
-
export declare function CustomOverflowMenu({ menuTitle, children }: CustomOverflowMenuProps): React.JSX.Element;
|
|
8
|
-
export {};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './custom-overflow-menu.component';
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
/**
|
|
3
|
-
* Component to render the Calendar icon for the DatePicker component with the same styling as
|
|
4
|
-
* the Carbon DatePicker component.
|
|
5
|
-
*/
|
|
6
|
-
export declare const DatePickerIcon: React.ForwardRefExoticComponent<React.RefAttributes<SVGSVGElement>>;
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { type DateInputProps } from 'react-aria-components';
|
|
3
|
-
interface OpenmrsDateInputProps {
|
|
4
|
-
id?: string;
|
|
5
|
-
}
|
|
6
|
-
/**
|
|
7
|
-
* This is just the standard React Aria Components DatePickerInput with an added `onClick` handler to open
|
|
8
|
-
* the calendar when the group is clicked. This is used to emulate Carbon's behaviour in the DatePicker.
|
|
9
|
-
*/
|
|
10
|
-
export declare const DatePickerInput: React.ForwardRefExoticComponent<DateInputProps & OpenmrsDateInputProps & React.RefAttributes<HTMLDivElement>>;
|
|
11
|
-
export {};
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
/**
|
|
3
|
-
* Custom component to render the month and year on the DatePicker and provide the standard Carbon
|
|
4
|
-
* UI to change them.
|
|
5
|
-
*
|
|
6
|
-
* Should work with any calendar system supported by the @internationalized/date package.
|
|
7
|
-
*/
|
|
8
|
-
export declare const MonthYear: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLSpanElement> & {
|
|
9
|
-
children?: React.ReactNode | undefined;
|
|
10
|
-
} & React.RefAttributes<HTMLSpanElement>>;
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { type Calendar, type DateValue } from '@internationalized/date';
|
|
2
|
-
import { type DateInputValue } from './OpenmrsDatePicker';
|
|
3
|
-
/**
|
|
4
|
-
* Function to convert relatively arbitrary date values into a React Aria `DateValue`,
|
|
5
|
-
* normally a `CalendarDate`, which represents a date without time or timezone.
|
|
6
|
-
*/
|
|
7
|
-
export declare function dateToInternationalizedDate(date: DateInputValue, calendar: Calendar | undefined, allowNull: true): DateValue | null | undefined;
|
|
8
|
-
export declare function dateToInternationalizedDate(date: DateInputValue, calendar: Calendar | undefined, allowNull: false): DateValue | undefined;
|
|
9
|
-
export declare function dateToInternationalizedDate(date: DateInputValue, calendar: Calendar | undefined): DateValue | undefined;
|
|
10
|
-
/**
|
|
11
|
-
* Function to convert a `DateValue` (from React Aria) into a standard JS `Date`.
|
|
12
|
-
*/
|
|
13
|
-
export declare function internationalizedDateToDate(date: DateValue): Date | undefined;
|
|
14
|
-
/** Removes any data attributes from an object */
|
|
15
|
-
export declare function removeDataAttributes<T>(props: T): T;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './error-state.component';
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function setupIcons(): void;
|