@snapdragonsnursery/react-components 1.3.0 → 1.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/EmployeeSearchDemo.jsx +275 -0
- package/src/EmployeeSearchModal.jsx +817 -0
- package/src/EmployeeSearchPage.jsx +804 -0
- package/src/EmployeeSearchPage.test.jsx +240 -0
- package/src/components/EmployeeSearchFilters.jsx +418 -0
- package/src/components/EmployeeSearchFilters.test.jsx +546 -0
- package/src/index.js +7 -0
|
@@ -0,0 +1,546 @@
|
|
|
1
|
+
// Employee Search Filters Component Tests
|
|
2
|
+
// Tests the EmployeeSearchFilters component functionality including filter changes, validation, and UI interactions
|
|
3
|
+
|
|
4
|
+
import React from 'react';
|
|
5
|
+
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
|
|
6
|
+
import '@testing-library/jest-dom';
|
|
7
|
+
import EmployeeSearchFilters from './EmployeeSearchFilters';
|
|
8
|
+
|
|
9
|
+
// Mock the UI components
|
|
10
|
+
jest.mock('./ui/input', () => ({
|
|
11
|
+
Input: ({ value, onChange, placeholder, ...props }) => {
|
|
12
|
+
return (
|
|
13
|
+
<input
|
|
14
|
+
data-testid="input"
|
|
15
|
+
value={value}
|
|
16
|
+
onChange={onChange}
|
|
17
|
+
placeholder={placeholder}
|
|
18
|
+
{...props}
|
|
19
|
+
/>
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
}));
|
|
23
|
+
|
|
24
|
+
jest.mock('./ui/select', () => {
|
|
25
|
+
const MockSelect = ({ value, onChange, children, ...props }) => {
|
|
26
|
+
return (
|
|
27
|
+
<select data-testid="select" value={value} onChange={onChange} {...props}>
|
|
28
|
+
{children}
|
|
29
|
+
</select>
|
|
30
|
+
);
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const MockSelectOption = ({ value, children, ...props }) => {
|
|
34
|
+
return (
|
|
35
|
+
<option value={value} {...props}>
|
|
36
|
+
{children}
|
|
37
|
+
</option>
|
|
38
|
+
);
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
return {
|
|
42
|
+
Select: MockSelect,
|
|
43
|
+
SelectOption: MockSelectOption,
|
|
44
|
+
};
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
jest.mock('./ui/date-range-picker', () => ({
|
|
48
|
+
DateRangePicker: ({ selectedRange, onSelect, placeholder, ...props }) => {
|
|
49
|
+
return (
|
|
50
|
+
<div data-testid="date-range-picker">
|
|
51
|
+
<input
|
|
52
|
+
data-testid="date-range-input"
|
|
53
|
+
placeholder={placeholder}
|
|
54
|
+
value={selectedRange ? `${selectedRange.from?.toISOString() || ''} - ${selectedRange.to?.toISOString() || ''}` : ''}
|
|
55
|
+
onChange={(e) => {
|
|
56
|
+
// Simulate date range selection
|
|
57
|
+
if (e.target.value.includes('2024-01-01')) {
|
|
58
|
+
onSelect({
|
|
59
|
+
from: new Date('2024-01-01'),
|
|
60
|
+
to: new Date('2024-01-31')
|
|
61
|
+
});
|
|
62
|
+
} else {
|
|
63
|
+
onSelect(null);
|
|
64
|
+
}
|
|
65
|
+
}}
|
|
66
|
+
{...props}
|
|
67
|
+
/>
|
|
68
|
+
</div>
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
}));
|
|
72
|
+
|
|
73
|
+
jest.mock('./ui/button', () => ({
|
|
74
|
+
Button: ({ children, onClick, variant, size, ...props }) => {
|
|
75
|
+
return (
|
|
76
|
+
<button
|
|
77
|
+
data-testid="button"
|
|
78
|
+
onClick={onClick}
|
|
79
|
+
data-variant={variant}
|
|
80
|
+
data-size={size}
|
|
81
|
+
{...props}
|
|
82
|
+
>
|
|
83
|
+
{children}
|
|
84
|
+
</button>
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
}));
|
|
88
|
+
|
|
89
|
+
const mockSites = [
|
|
90
|
+
{ site_id: 1, site_name: "Nursery A" },
|
|
91
|
+
{ site_id: 2, site_name: "Nursery B" },
|
|
92
|
+
{ site_id: 3, site_name: "Nursery C" },
|
|
93
|
+
];
|
|
94
|
+
|
|
95
|
+
const mockRoles = [
|
|
96
|
+
{ role_id: 1, role_name: "Manager" },
|
|
97
|
+
{ role_id: 2, role_name: "Deputy Manager" },
|
|
98
|
+
{ role_id: 3, role_name: "Room Leader" },
|
|
99
|
+
];
|
|
100
|
+
|
|
101
|
+
const mockManagers = [
|
|
102
|
+
{ entra_id: "manager1", full_name: "John Smith" },
|
|
103
|
+
{ entra_id: "manager2", full_name: "Jane Doe" },
|
|
104
|
+
];
|
|
105
|
+
|
|
106
|
+
const defaultFilters = {
|
|
107
|
+
status: "Active",
|
|
108
|
+
selectedSiteId: "",
|
|
109
|
+
roleId: "",
|
|
110
|
+
managerId: "",
|
|
111
|
+
startDateFrom: "",
|
|
112
|
+
startDateTo: "",
|
|
113
|
+
endDateFrom: "",
|
|
114
|
+
endDateTo: "",
|
|
115
|
+
termTimeOnly: "",
|
|
116
|
+
onMaternityLeave: "",
|
|
117
|
+
dbsNumber: "",
|
|
118
|
+
minHoursPerWeek: "",
|
|
119
|
+
sortBy: "surname",
|
|
120
|
+
sortOrder: "asc",
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
const defaultProps = {
|
|
124
|
+
filters: defaultFilters,
|
|
125
|
+
onFiltersChange: jest.fn(),
|
|
126
|
+
onApplyFilters: jest.fn(),
|
|
127
|
+
onClearFilters: jest.fn(),
|
|
128
|
+
onCancelChanges: jest.fn(),
|
|
129
|
+
sites: mockSites,
|
|
130
|
+
roles: mockRoles,
|
|
131
|
+
managers: mockManagers,
|
|
132
|
+
activeOnly: true,
|
|
133
|
+
isAdvancedFiltersOpen: false,
|
|
134
|
+
onToggleAdvancedFilters: jest.fn(),
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
describe('EmployeeSearchFilters', () => {
|
|
138
|
+
beforeEach(() => {
|
|
139
|
+
jest.clearAllMocks();
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
describe('Basic Rendering', () => {
|
|
143
|
+
it('renders the advanced filters toggle button', () => {
|
|
144
|
+
render(<EmployeeSearchFilters {...defaultProps} />);
|
|
145
|
+
|
|
146
|
+
expect(screen.getByText('Advanced Filters')).toBeInTheDocument();
|
|
147
|
+
expect(screen.getByText('Clear Filters')).toBeInTheDocument();
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it('shows advanced filters when isAdvancedFiltersOpen is true', () => {
|
|
151
|
+
render(<EmployeeSearchFilters {...defaultProps} isAdvancedFiltersOpen={true} />);
|
|
152
|
+
|
|
153
|
+
// Use getAllByText to handle multiple elements with same text
|
|
154
|
+
const statusLabels = screen.getAllByText('Status');
|
|
155
|
+
expect(statusLabels.length).toBeGreaterThan(0);
|
|
156
|
+
const siteLabels = screen.getAllByText('Site');
|
|
157
|
+
expect(siteLabels.length).toBeGreaterThan(0);
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
it('hides advanced filters when isAdvancedFiltersOpen is false', () => {
|
|
161
|
+
render(<EmployeeSearchFilters {...defaultProps} isAdvancedFiltersOpen={false} />);
|
|
162
|
+
|
|
163
|
+
expect(screen.queryByText('Status')).not.toBeInTheDocument();
|
|
164
|
+
expect(screen.queryByText('Site')).not.toBeInTheDocument();
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
describe('Filter Interactions', () => {
|
|
169
|
+
it('calls onToggleAdvancedFilters when toggle button is clicked', () => {
|
|
170
|
+
render(<EmployeeSearchFilters {...defaultProps} />);
|
|
171
|
+
|
|
172
|
+
fireEvent.click(screen.getByText('Advanced Filters'));
|
|
173
|
+
|
|
174
|
+
expect(defaultProps.onToggleAdvancedFilters).toHaveBeenCalledTimes(1);
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
it('calls onClearFilters when clear filters button is clicked', () => {
|
|
178
|
+
render(<EmployeeSearchFilters {...defaultProps} />);
|
|
179
|
+
|
|
180
|
+
fireEvent.click(screen.getByText('Clear Filters'));
|
|
181
|
+
|
|
182
|
+
expect(defaultProps.onClearFilters).toHaveBeenCalledTimes(1);
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
it('updates status filter when changed', () => {
|
|
186
|
+
render(<EmployeeSearchFilters {...defaultProps} isAdvancedFiltersOpen={true} />);
|
|
187
|
+
|
|
188
|
+
const statusSelect = screen.getAllByTestId('select')[0];
|
|
189
|
+
fireEvent.change(statusSelect, { target: { value: 'Inactive' } });
|
|
190
|
+
|
|
191
|
+
expect(defaultProps.onFiltersChange).toHaveBeenCalledWith({
|
|
192
|
+
...defaultFilters,
|
|
193
|
+
status: 'Inactive',
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
it('updates site filter when changed', () => {
|
|
198
|
+
render(<EmployeeSearchFilters {...defaultProps} isAdvancedFiltersOpen={true} />);
|
|
199
|
+
|
|
200
|
+
const siteSelect = screen.getAllByTestId('select')[1];
|
|
201
|
+
fireEvent.change(siteSelect, { target: { value: '2' } });
|
|
202
|
+
|
|
203
|
+
expect(defaultProps.onFiltersChange).toHaveBeenCalledWith({
|
|
204
|
+
...defaultFilters,
|
|
205
|
+
selectedSiteId: '2',
|
|
206
|
+
});
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
it('updates role filter when changed', () => {
|
|
210
|
+
render(<EmployeeSearchFilters {...defaultProps} isAdvancedFiltersOpen={true} />);
|
|
211
|
+
|
|
212
|
+
const roleSelect = screen.getAllByTestId('select')[2];
|
|
213
|
+
fireEvent.change(roleSelect, { target: { value: '3' } });
|
|
214
|
+
|
|
215
|
+
expect(defaultProps.onFiltersChange).toHaveBeenCalledWith({
|
|
216
|
+
...defaultFilters,
|
|
217
|
+
roleId: '3',
|
|
218
|
+
});
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
it('updates manager filter when changed', () => {
|
|
222
|
+
render(<EmployeeSearchFilters {...defaultProps} isAdvancedFiltersOpen={true} />);
|
|
223
|
+
|
|
224
|
+
const managerSelect = screen.getAllByTestId('select')[3];
|
|
225
|
+
fireEvent.change(managerSelect, { target: { value: 'manager2' } });
|
|
226
|
+
|
|
227
|
+
expect(defaultProps.onFiltersChange).toHaveBeenCalledWith({
|
|
228
|
+
...defaultFilters,
|
|
229
|
+
managerId: 'manager2',
|
|
230
|
+
});
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
it('updates DBS number filter when changed', () => {
|
|
234
|
+
render(<EmployeeSearchFilters {...defaultProps} isAdvancedFiltersOpen={true} />);
|
|
235
|
+
|
|
236
|
+
const dbsInput = screen.getAllByTestId('input')[0];
|
|
237
|
+
fireEvent.change(dbsInput, { target: { value: 'DBS123456' } });
|
|
238
|
+
|
|
239
|
+
expect(defaultProps.onFiltersChange).toHaveBeenCalledWith({
|
|
240
|
+
...defaultFilters,
|
|
241
|
+
dbsNumber: 'DBS123456',
|
|
242
|
+
});
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
it('updates working hours filter when changed', () => {
|
|
246
|
+
render(<EmployeeSearchFilters {...defaultProps} isAdvancedFiltersOpen={true} />);
|
|
247
|
+
|
|
248
|
+
const hoursInput = screen.getAllByTestId('input')[1];
|
|
249
|
+
fireEvent.change(hoursInput, { target: { value: '30' } });
|
|
250
|
+
|
|
251
|
+
expect(defaultProps.onFiltersChange).toHaveBeenCalledWith({
|
|
252
|
+
...defaultFilters,
|
|
253
|
+
minHoursPerWeek: '30',
|
|
254
|
+
});
|
|
255
|
+
});
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
describe('Date Range Filters', () => {
|
|
259
|
+
it('handles start date range selection', async () => {
|
|
260
|
+
render(<EmployeeSearchFilters {...defaultProps} isAdvancedFiltersOpen={true} />);
|
|
261
|
+
|
|
262
|
+
const startDatePicker = screen.getAllByTestId('date-range-input')[0];
|
|
263
|
+
fireEvent.change(startDatePicker, { target: { value: '2024-01-01T00:00:00.000Z - 2024-01-31T00:00:00.000Z' } });
|
|
264
|
+
|
|
265
|
+
// The component uses local state, so we just check that the unsaved changes indicator appears
|
|
266
|
+
await waitFor(() => {
|
|
267
|
+
expect(screen.getByText('You have unsaved filter changes')).toBeInTheDocument();
|
|
268
|
+
});
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
it('handles end date range selection', async () => {
|
|
272
|
+
render(<EmployeeSearchFilters {...defaultProps} isAdvancedFiltersOpen={true} />);
|
|
273
|
+
|
|
274
|
+
const endDatePicker = screen.getAllByTestId('date-range-input')[1];
|
|
275
|
+
fireEvent.change(endDatePicker, { target: { value: '2024-01-01T00:00:00.000Z - 2024-01-31T00:00:00.000Z' } });
|
|
276
|
+
|
|
277
|
+
// The component uses local state, so we just check that the unsaved changes indicator appears
|
|
278
|
+
await waitFor(() => {
|
|
279
|
+
expect(screen.getByText('You have unsaved filter changes')).toBeInTheDocument();
|
|
280
|
+
});
|
|
281
|
+
});
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
describe('Filter Visibility', () => {
|
|
285
|
+
it('shows all filters by default', () => {
|
|
286
|
+
render(<EmployeeSearchFilters {...defaultProps} isAdvancedFiltersOpen={true} />);
|
|
287
|
+
|
|
288
|
+
// Use getAllByText to get all elements with "Role" text and check the label specifically
|
|
289
|
+
const roleLabels = screen.getAllByText('Role');
|
|
290
|
+
expect(roleLabels.length).toBeGreaterThan(0);
|
|
291
|
+
|
|
292
|
+
// Use getAllByText to get all elements with "Manager" text and check the label specifically
|
|
293
|
+
const managerLabels = screen.getAllByText('Manager');
|
|
294
|
+
expect(managerLabels.length).toBeGreaterThan(0);
|
|
295
|
+
|
|
296
|
+
// Use getAllByText for other filters that might have conflicts
|
|
297
|
+
const termTimeLabels = screen.getAllByText('Term Time Only');
|
|
298
|
+
expect(termTimeLabels.length).toBeGreaterThan(0);
|
|
299
|
+
|
|
300
|
+
const maternityLabels = screen.getAllByText('Maternity Leave');
|
|
301
|
+
expect(maternityLabels.length).toBeGreaterThan(0);
|
|
302
|
+
|
|
303
|
+
expect(screen.getByText('Start Date Range')).toBeInTheDocument();
|
|
304
|
+
expect(screen.getByText('End Date Range')).toBeInTheDocument();
|
|
305
|
+
expect(screen.getByText('DBS Number')).toBeInTheDocument();
|
|
306
|
+
expect(screen.getByText('Min Hours Per Week')).toBeInTheDocument();
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
it('hides role filter when showRoleFilter is false', () => {
|
|
310
|
+
render(
|
|
311
|
+
<EmployeeSearchFilters
|
|
312
|
+
{...defaultProps}
|
|
313
|
+
isAdvancedFiltersOpen={true}
|
|
314
|
+
showRoleFilter={false}
|
|
315
|
+
/>
|
|
316
|
+
);
|
|
317
|
+
|
|
318
|
+
// Check that the role label is not present (but the sort option might still be there)
|
|
319
|
+
const roleLabels = screen.queryAllByText('Role');
|
|
320
|
+
const roleLabel = roleLabels.find(element => element.tagName === 'LABEL');
|
|
321
|
+
expect(roleLabel).toBeUndefined();
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
it('hides manager filter when showManagerFilter is false', () => {
|
|
325
|
+
render(
|
|
326
|
+
<EmployeeSearchFilters
|
|
327
|
+
{...defaultProps}
|
|
328
|
+
isAdvancedFiltersOpen={true}
|
|
329
|
+
showManagerFilter={false}
|
|
330
|
+
/>
|
|
331
|
+
);
|
|
332
|
+
|
|
333
|
+
// Check that the manager label is not present (but role options might still be there)
|
|
334
|
+
const managerLabels = screen.queryAllByText('Manager');
|
|
335
|
+
const managerLabel = managerLabels.find(element => element.tagName === 'LABEL');
|
|
336
|
+
expect(managerLabel).toBeUndefined();
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
it('hides term time filter when showTermTimeFilter is false', () => {
|
|
340
|
+
render(
|
|
341
|
+
<EmployeeSearchFilters
|
|
342
|
+
{...defaultProps}
|
|
343
|
+
isAdvancedFiltersOpen={true}
|
|
344
|
+
showTermTimeFilter={false}
|
|
345
|
+
/>
|
|
346
|
+
);
|
|
347
|
+
|
|
348
|
+
const termTimeLabels = screen.queryAllByText('Term Time Only');
|
|
349
|
+
const termTimeLabel = termTimeLabels.find(element => element.tagName === 'LABEL');
|
|
350
|
+
expect(termTimeLabel).toBeUndefined();
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
it('hides maternity filter when showMaternityFilter is false', () => {
|
|
354
|
+
render(
|
|
355
|
+
<EmployeeSearchFilters
|
|
356
|
+
{...defaultProps}
|
|
357
|
+
isAdvancedFiltersOpen={true}
|
|
358
|
+
showMaternityFilter={false}
|
|
359
|
+
/>
|
|
360
|
+
);
|
|
361
|
+
|
|
362
|
+
const maternityLabels = screen.queryAllByText('Maternity Leave');
|
|
363
|
+
const maternityLabel = maternityLabels.find(element => element.tagName === 'LABEL');
|
|
364
|
+
expect(maternityLabel).toBeUndefined();
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
it('hides start date filter when showStartDateFilter is false', () => {
|
|
368
|
+
render(
|
|
369
|
+
<EmployeeSearchFilters
|
|
370
|
+
{...defaultProps}
|
|
371
|
+
isAdvancedFiltersOpen={true}
|
|
372
|
+
showStartDateFilter={false}
|
|
373
|
+
/>
|
|
374
|
+
);
|
|
375
|
+
|
|
376
|
+
expect(screen.queryByText('Start Date Range')).not.toBeInTheDocument();
|
|
377
|
+
});
|
|
378
|
+
|
|
379
|
+
it('hides end date filter when showEndDateFilter is false', () => {
|
|
380
|
+
render(
|
|
381
|
+
<EmployeeSearchFilters
|
|
382
|
+
{...defaultProps}
|
|
383
|
+
isAdvancedFiltersOpen={true}
|
|
384
|
+
showEndDateFilter={false}
|
|
385
|
+
/>
|
|
386
|
+
);
|
|
387
|
+
|
|
388
|
+
expect(screen.queryByText('End Date Range')).not.toBeInTheDocument();
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
it('hides DBS filter when showDbsFilter is false', () => {
|
|
392
|
+
render(
|
|
393
|
+
<EmployeeSearchFilters
|
|
394
|
+
{...defaultProps}
|
|
395
|
+
isAdvancedFiltersOpen={true}
|
|
396
|
+
showDbsFilter={false}
|
|
397
|
+
/>
|
|
398
|
+
);
|
|
399
|
+
|
|
400
|
+
expect(screen.queryByText('DBS Number')).not.toBeInTheDocument();
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
it('hides working hours filter when showWorkingHoursFilter is false', () => {
|
|
404
|
+
render(
|
|
405
|
+
<EmployeeSearchFilters
|
|
406
|
+
{...defaultProps}
|
|
407
|
+
isAdvancedFiltersOpen={true}
|
|
408
|
+
showWorkingHoursFilter={false}
|
|
409
|
+
/>
|
|
410
|
+
);
|
|
411
|
+
|
|
412
|
+
expect(screen.queryByText('Min Hours Per Week')).not.toBeInTheDocument();
|
|
413
|
+
});
|
|
414
|
+
});
|
|
415
|
+
|
|
416
|
+
describe('Apply/Cancel Buttons', () => {
|
|
417
|
+
it('shows apply/cancel buttons when there are unsaved changes', () => {
|
|
418
|
+
render(<EmployeeSearchFilters {...defaultProps} isAdvancedFiltersOpen={true} />);
|
|
419
|
+
|
|
420
|
+
// Change a filter to trigger unsaved changes
|
|
421
|
+
const statusSelect = screen.getAllByTestId('select')[0];
|
|
422
|
+
fireEvent.change(statusSelect, { target: { value: 'Inactive' } });
|
|
423
|
+
|
|
424
|
+
expect(screen.getByText('You have unsaved filter changes')).toBeInTheDocument();
|
|
425
|
+
expect(screen.getByText('Cancel')).toBeInTheDocument();
|
|
426
|
+
expect(screen.getByText('Apply Filters')).toBeInTheDocument();
|
|
427
|
+
});
|
|
428
|
+
|
|
429
|
+
it('calls onApplyFilters when apply button is clicked', () => {
|
|
430
|
+
render(<EmployeeSearchFilters {...defaultProps} isAdvancedFiltersOpen={true} />);
|
|
431
|
+
|
|
432
|
+
// Change a filter to trigger unsaved changes
|
|
433
|
+
const statusSelect = screen.getAllByTestId('select')[0];
|
|
434
|
+
fireEvent.change(statusSelect, { target: { value: 'Inactive' } });
|
|
435
|
+
|
|
436
|
+
fireEvent.click(screen.getByText('Apply Filters'));
|
|
437
|
+
|
|
438
|
+
expect(defaultProps.onApplyFilters).toHaveBeenCalledWith({
|
|
439
|
+
...defaultFilters,
|
|
440
|
+
status: 'Inactive',
|
|
441
|
+
});
|
|
442
|
+
});
|
|
443
|
+
|
|
444
|
+
it('calls onCancelChanges when cancel button is clicked', () => {
|
|
445
|
+
render(<EmployeeSearchFilters {...defaultProps} isAdvancedFiltersOpen={true} />);
|
|
446
|
+
|
|
447
|
+
// Change a filter to trigger unsaved changes
|
|
448
|
+
const statusSelect = screen.getAllByTestId('select')[0];
|
|
449
|
+
fireEvent.change(statusSelect, { target: { value: 'Inactive' } });
|
|
450
|
+
|
|
451
|
+
fireEvent.click(screen.getByText('Cancel'));
|
|
452
|
+
|
|
453
|
+
expect(defaultProps.onCancelChanges).toHaveBeenCalledTimes(1);
|
|
454
|
+
});
|
|
455
|
+
});
|
|
456
|
+
|
|
457
|
+
describe('Sorting Options', () => {
|
|
458
|
+
it('updates sort by field when changed', () => {
|
|
459
|
+
render(<EmployeeSearchFilters {...defaultProps} isAdvancedFiltersOpen={true} />);
|
|
460
|
+
|
|
461
|
+
const sortBySelect = screen.getAllByTestId('select').find(select =>
|
|
462
|
+
select.querySelector('option[value="first_name"]')
|
|
463
|
+
);
|
|
464
|
+
fireEvent.change(sortBySelect, { target: { value: 'first_name' } });
|
|
465
|
+
|
|
466
|
+
// The component should show unsaved changes indicator
|
|
467
|
+
expect(screen.getByText('You have unsaved filter changes')).toBeInTheDocument();
|
|
468
|
+
});
|
|
469
|
+
|
|
470
|
+
it('updates sort order when changed', () => {
|
|
471
|
+
render(<EmployeeSearchFilters {...defaultProps} isAdvancedFiltersOpen={true} />);
|
|
472
|
+
|
|
473
|
+
const sortOrderSelect = screen.getAllByTestId('select').find(select =>
|
|
474
|
+
select.querySelector('option[value="desc"]')
|
|
475
|
+
);
|
|
476
|
+
fireEvent.change(sortOrderSelect, { target: { value: 'desc' } });
|
|
477
|
+
|
|
478
|
+
// The component should show unsaved changes indicator
|
|
479
|
+
expect(screen.getByText('You have unsaved filter changes')).toBeInTheDocument();
|
|
480
|
+
});
|
|
481
|
+
});
|
|
482
|
+
|
|
483
|
+
describe('Edge Cases', () => {
|
|
484
|
+
it('handles empty sites array', () => {
|
|
485
|
+
render(
|
|
486
|
+
<EmployeeSearchFilters
|
|
487
|
+
{...defaultProps}
|
|
488
|
+
sites={[]}
|
|
489
|
+
isAdvancedFiltersOpen={true}
|
|
490
|
+
/>
|
|
491
|
+
);
|
|
492
|
+
|
|
493
|
+
// When sites array is empty, the site filter should not be rendered
|
|
494
|
+
const siteLabels = screen.queryAllByText('Site');
|
|
495
|
+
const siteLabel = siteLabels.find(element => element.tagName === 'LABEL');
|
|
496
|
+
expect(siteLabel).toBeUndefined();
|
|
497
|
+
});
|
|
498
|
+
|
|
499
|
+
it('handles empty roles array', () => {
|
|
500
|
+
render(
|
|
501
|
+
<EmployeeSearchFilters
|
|
502
|
+
{...defaultProps}
|
|
503
|
+
roles={[]}
|
|
504
|
+
isAdvancedFiltersOpen={true}
|
|
505
|
+
/>
|
|
506
|
+
);
|
|
507
|
+
|
|
508
|
+
// When roles array is empty, the role filter should not be rendered
|
|
509
|
+
const roleLabels = screen.queryAllByText('Role');
|
|
510
|
+
const roleLabel = roleLabels.find(element => element.tagName === 'LABEL');
|
|
511
|
+
expect(roleLabel).toBeUndefined();
|
|
512
|
+
});
|
|
513
|
+
|
|
514
|
+
it('handles empty managers array', () => {
|
|
515
|
+
render(
|
|
516
|
+
<EmployeeSearchFilters
|
|
517
|
+
{...defaultProps}
|
|
518
|
+
managers={[]}
|
|
519
|
+
isAdvancedFiltersOpen={true}
|
|
520
|
+
/>
|
|
521
|
+
);
|
|
522
|
+
|
|
523
|
+
// When managers array is empty, the manager filter should not be rendered
|
|
524
|
+
const managerLabels = screen.queryAllByText('Manager');
|
|
525
|
+
const managerLabel = managerLabels.find(element => element.tagName === 'LABEL');
|
|
526
|
+
expect(managerLabel).toBeUndefined();
|
|
527
|
+
});
|
|
528
|
+
|
|
529
|
+
it('handles null props gracefully', () => {
|
|
530
|
+
render(
|
|
531
|
+
<EmployeeSearchFilters
|
|
532
|
+
{...defaultProps}
|
|
533
|
+
sites={null}
|
|
534
|
+
roles={null}
|
|
535
|
+
managers={null}
|
|
536
|
+
isAdvancedFiltersOpen={true}
|
|
537
|
+
/>
|
|
538
|
+
);
|
|
539
|
+
|
|
540
|
+
// Should still render basic filters
|
|
541
|
+
const statusLabels = screen.getAllByText('Status');
|
|
542
|
+
expect(statusLabels.length).toBeGreaterThan(0);
|
|
543
|
+
expect(screen.getByText('Sort By')).toBeInTheDocument();
|
|
544
|
+
});
|
|
545
|
+
});
|
|
546
|
+
});
|
package/src/index.js
CHANGED
|
@@ -10,6 +10,13 @@ export { default as DateRangePickerDemo } from "./DateRangePickerDemo";
|
|
|
10
10
|
export { default as CalendarDemo } from "./CalendarDemo";
|
|
11
11
|
export { default as DateRangePickerTest } from "./DateRangePickerTest";
|
|
12
12
|
export { default as ApplyButtonDemo } from "./ApplyButtonDemo";
|
|
13
|
+
|
|
14
|
+
// Employee Search Components
|
|
15
|
+
export { default as EmployeeSearchPage } from "./EmployeeSearchPage";
|
|
16
|
+
export { default as EmployeeSearchModal } from "./EmployeeSearchModal";
|
|
17
|
+
export { default as EmployeeSearchDemo } from "./EmployeeSearchDemo";
|
|
18
|
+
export { default as EmployeeSearchFilters } from "./components/EmployeeSearchFilters";
|
|
19
|
+
|
|
13
20
|
export { configureTelemetry } from "./telemetry";
|
|
14
21
|
|
|
15
22
|
// UI Components
|