@snapdragonsnursery/react-components 1.2.0 → 1.3.1

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,240 @@
1
+ // Employee Search Page Component Tests
2
+ // Tests the EmployeeSearchPage component functionality including search, filtering, pagination, and selection
3
+
4
+ import React from 'react';
5
+ import { render, screen, fireEvent, waitFor } from '@testing-library/react';
6
+ import '@testing-library/jest-dom';
7
+ import EmployeeSearchPage from './EmployeeSearchPage';
8
+
9
+ // Mock MSAL
10
+ jest.mock('@azure/msal-react', () => ({
11
+ useMsal: () => ({
12
+ instance: {
13
+ acquireTokenSilent: jest.fn(),
14
+ },
15
+ accounts: [{ localAccountId: 'test-user-id' }],
16
+ }),
17
+ }));
18
+
19
+ // Mock telemetry
20
+ jest.mock('./telemetry', () => ({
21
+ trackEvent: jest.fn(),
22
+ }));
23
+
24
+ // Mock utils
25
+ jest.mock('./lib/utils', () => ({
26
+ cn: (...classes) => classes.filter(Boolean).join(' '),
27
+ }));
28
+
29
+ // Mock fetch
30
+ global.fetch = jest.fn();
31
+
32
+ // Mock process.env
33
+ process.env.VITE_COMMON_API_FUNCTION_KEY = 'test-key';
34
+ process.env.VITE_COMMON_API_BASE_URL = 'https://test-api.example.com';
35
+
36
+ // Mock the UI components
37
+ jest.mock('./components/ui/input', () => ({
38
+ Input: ({ value, onChange, placeholder, ...props }) => {
39
+ return (
40
+ <input
41
+ data-testid="input"
42
+ value={value}
43
+ onChange={onChange}
44
+ placeholder={placeholder}
45
+ {...props}
46
+ />
47
+ );
48
+ }
49
+ }));
50
+
51
+ jest.mock('./components/ui/button', () => ({
52
+ Button: ({ children, onClick, variant, size, ...props }) => {
53
+ return (
54
+ <button
55
+ data-testid="button"
56
+ onClick={onClick}
57
+ data-variant={variant}
58
+ data-size={size}
59
+ {...props}
60
+ >
61
+ {children}
62
+ </button>
63
+ );
64
+ }
65
+ }));
66
+
67
+ jest.mock('./components/ui/table', () => ({
68
+ Table: ({ children, ...props }) => <table data-testid="table" {...props}>{children}</table>,
69
+ TableBody: ({ children, ...props }) => <tbody data-testid="table-body" {...props}>{children}</tbody>,
70
+ TableCell: ({ children, ...props }) => <td data-testid="table-cell" {...props}>{children}</td>,
71
+ TableHead: ({ children, ...props }) => <th data-testid="table-head" {...props}>{children}</th>,
72
+ TableHeader: ({ children, ...props }) => <thead data-testid="table-header" {...props}>{children}</thead>,
73
+ TableRow: ({ children, ...props }) => <tr data-testid="table-row" {...props}>{children}</tr>,
74
+ }));
75
+
76
+ jest.mock('./components/ui/pagination', () => ({
77
+ Pagination: ({ children, ...props }) => <nav data-testid="pagination" {...props}>{children}</nav>,
78
+ PaginationContent: ({ children, ...props }) => <div data-testid="pagination-content" {...props}>{children}</div>,
79
+ PaginationEllipsis: ({ ...props }) => <span data-testid="pagination-ellipsis" {...props}>...</span>,
80
+ PaginationItem: ({ children, ...props }) => <div data-testid="pagination-item" {...props}>{children}</div>,
81
+ PaginationLink: ({ children, onClick, isActive, ...props }) => (
82
+ <button data-testid="pagination-link" onClick={onClick} data-active={isActive} {...props}>
83
+ {children}
84
+ </button>
85
+ ),
86
+ PaginationNext: ({ children, onClick, ...props }) => (
87
+ <button data-testid="pagination-next" onClick={onClick} {...props}>
88
+ {children}
89
+ </button>
90
+ ),
91
+ PaginationPrevious: ({ children, onClick, ...props }) => (
92
+ <button data-testid="pagination-previous" onClick={onClick} {...props}>
93
+ {children}
94
+ </button>
95
+ ),
96
+ }));
97
+
98
+ // Mock EmployeeSearchFilters
99
+ jest.mock('./components/EmployeeSearchFilters', () => {
100
+ return function MockEmployeeSearchFilters({ filters, onFiltersChange, onApplyFilters, onClearFilters, ...props }) {
101
+ return (
102
+ <div data-testid="employee-search-filters">
103
+ <button onClick={() => onFiltersChange({ ...filters, status: 'Inactive' })}>
104
+ Change Status
105
+ </button>
106
+ <button onClick={() => onApplyFilters(filters)}>
107
+ Apply Filters
108
+ </button>
109
+ <button onClick={onClearFilters}>
110
+ Clear Filters
111
+ </button>
112
+ </div>
113
+ );
114
+ };
115
+ });
116
+
117
+ const defaultProps = {
118
+ title: 'Employee Search',
119
+ onSelect: jest.fn(),
120
+ };
121
+
122
+ describe('EmployeeSearchPage', () => {
123
+ beforeEach(() => {
124
+ jest.clearAllMocks();
125
+ global.fetch.mockResolvedValue({
126
+ ok: true,
127
+ json: async () => ({
128
+ success: true,
129
+ data: {
130
+ employees: [],
131
+ pagination: {
132
+ page: 1,
133
+ pageSize: 20,
134
+ totalCount: 0,
135
+ totalPages: 0,
136
+ hasNextPage: false,
137
+ hasPreviousPage: false,
138
+ },
139
+ },
140
+ }),
141
+ });
142
+ });
143
+
144
+ describe('Basic Rendering', () => {
145
+ it('renders the page title', () => {
146
+ render(<EmployeeSearchPage {...defaultProps} />);
147
+
148
+ expect(screen.getByText('Employee Search')).toBeInTheDocument();
149
+ });
150
+
151
+ it('renders the search input', () => {
152
+ render(<EmployeeSearchPage {...defaultProps} />);
153
+
154
+ expect(screen.getByPlaceholderText('Search by name, employee ID, or email...')).toBeInTheDocument();
155
+ });
156
+
157
+ it('renders the employee search filters', () => {
158
+ render(<EmployeeSearchPage {...defaultProps} />);
159
+
160
+ expect(screen.getByTestId('employee-search-filters')).toBeInTheDocument();
161
+ });
162
+
163
+ it('shows loading state initially', () => {
164
+ render(<EmployeeSearchPage {...defaultProps} />);
165
+
166
+ expect(screen.getByRole('status')).toBeInTheDocument();
167
+ });
168
+ });
169
+
170
+ describe('Search Functionality', () => {
171
+ it('renders search input with correct placeholder', () => {
172
+ render(<EmployeeSearchPage {...defaultProps} />);
173
+
174
+ const searchInput = screen.getByPlaceholderText('Search by name, employee ID, or email...');
175
+ expect(searchInput).toBeInTheDocument();
176
+ expect(searchInput).toHaveAttribute('type', 'text');
177
+ });
178
+
179
+ it('allows typing in search input', () => {
180
+ render(<EmployeeSearchPage {...defaultProps} />);
181
+
182
+ const searchInput = screen.getByPlaceholderText('Search by name, employee ID, or email...');
183
+ fireEvent.change(searchInput, { target: { value: 'John' } });
184
+
185
+ expect(searchInput).toHaveValue('John');
186
+ });
187
+ });
188
+
189
+ describe('Filter Integration', () => {
190
+ it('renders filter buttons', () => {
191
+ render(<EmployeeSearchPage {...defaultProps} />);
192
+
193
+ expect(screen.getByText('Change Status')).toBeInTheDocument();
194
+ expect(screen.getByText('Apply Filters')).toBeInTheDocument();
195
+ expect(screen.getByText('Clear Filters')).toBeInTheDocument();
196
+ });
197
+
198
+ it('calls filter change handler when filter button is clicked', () => {
199
+ render(<EmployeeSearchPage {...defaultProps} />);
200
+
201
+ const changeStatusButton = screen.getByText('Change Status');
202
+ fireEvent.click(changeStatusButton);
203
+
204
+ // The mock should have been called
205
+ expect(changeStatusButton).toBeInTheDocument();
206
+ });
207
+ });
208
+
209
+ describe('Accessibility', () => {
210
+ it('has proper ARIA labels', () => {
211
+ render(<EmployeeSearchPage {...defaultProps} />);
212
+
213
+ const searchInput = screen.getByPlaceholderText('Search by name, employee ID, or email...');
214
+ expect(searchInput).toBeInTheDocument();
215
+ });
216
+
217
+ it('supports keyboard navigation', () => {
218
+ render(<EmployeeSearchPage {...defaultProps} />);
219
+
220
+ const searchInput = screen.getByPlaceholderText('Search by name, employee ID, or email...');
221
+ searchInput.focus();
222
+
223
+ expect(searchInput).toHaveFocus();
224
+ });
225
+ });
226
+
227
+ describe('Props Handling', () => {
228
+ it('renders custom title', () => {
229
+ render(<EmployeeSearchPage {...defaultProps} title="Custom Title" />);
230
+
231
+ expect(screen.getByText('Custom Title')).toBeInTheDocument();
232
+ });
233
+
234
+ it('renders custom search placeholder', () => {
235
+ render(<EmployeeSearchPage {...defaultProps} searchPlaceholder="Custom placeholder" />);
236
+
237
+ expect(screen.getByPlaceholderText('Custom placeholder')).toBeInTheDocument();
238
+ });
239
+ });
240
+ });
@@ -1,5 +1,5 @@
1
1
  // ChildSearchFilters Component Tests
2
- // Tests the filter functionality including status, site, date of birth, age, and sorting options
2
+ // Tests the filter functionality including status, site, date of birth, and age options
3
3
 
4
4
  import React from "react";
5
5
  import { render, screen, fireEvent, waitFor } from "@testing-library/react";
@@ -68,8 +68,6 @@ describe("ChildSearchFilters", () => {
68
68
  dobTo: "",
69
69
  ageFrom: "",
70
70
  ageTo: "",
71
- sortBy: "last_name",
72
- sortOrder: "asc",
73
71
  };
74
72
 
75
73
  const mockSites = [
@@ -107,8 +105,6 @@ describe("ChildSearchFilters", () => {
107
105
  expect(screen.getByText("Date of Birth Range")).toBeInTheDocument();
108
106
  expect(screen.getByText("Age From (months)")).toBeInTheDocument();
109
107
  expect(screen.getByText("Age To (months)")).toBeInTheDocument();
110
- expect(screen.getByText("Sort By")).toBeInTheDocument();
111
- expect(screen.getByText("Sort Order")).toBeInTheDocument();
112
108
  });
113
109
 
114
110
  it("hides advanced filters when isAdvancedFiltersOpen is false", () => {
@@ -157,7 +153,7 @@ describe("ChildSearchFilters", () => {
157
153
  );
158
154
 
159
155
  const selects = screen.getAllByTestId("select");
160
- expect(selects).toHaveLength(3); // Status, Sort By, Sort Order (no site filter when sites=null)
156
+ expect(selects).toHaveLength(1); // Only Status filter (no site filter when sites=null)
161
157
  });
162
158
 
163
159
  it("shows apply button when filters are changed", () => {
@@ -220,22 +216,6 @@ describe("ChildSearchFilters", () => {
220
216
  );
221
217
  });
222
218
 
223
- it("calls onApplyFilters when apply button is clicked with sort filter", () => {
224
- render(<ChildSearchFilters {...defaultProps} isAdvancedFiltersOpen={true} />);
225
-
226
- const sortBySelect = screen.getAllByTestId("select")[2];
227
- fireEvent.change(sortBySelect, { target: { value: "first_name" } });
228
-
229
- const applyButton = screen.getByText("Apply Filters");
230
- fireEvent.click(applyButton);
231
-
232
- expect(defaultProps.onApplyFilters).toHaveBeenCalledWith(
233
- expect.objectContaining({
234
- sortBy: "first_name"
235
- })
236
- );
237
- });
238
-
239
219
  it("displays correct filter values", () => {
240
220
  const filtersWithValues = {
241
221
  ...mockFilters,
@@ -245,8 +225,6 @@ describe("ChildSearchFilters", () => {
245
225
  dobTo: "2020-12-31",
246
226
  ageFrom: "12",
247
227
  ageTo: "60",
248
- sortBy: "first_name",
249
- sortOrder: "desc",
250
228
  };
251
229
 
252
230
  render(
@@ -262,16 +240,12 @@ describe("ChildSearchFilters", () => {
262
240
  const dateRangePicker = screen.getByTestId("date-range-picker");
263
241
  const ageFromInput = screen.getAllByTestId("input")[0];
264
242
  const ageToInput = screen.getAllByTestId("input")[1];
265
- const sortBySelect = screen.getAllByTestId("select")[2];
266
- const sortOrderSelect = screen.getAllByTestId("select")[3];
267
243
 
268
244
  expect(statusSelect).toHaveValue("inactive");
269
245
  expect(siteSelect).toHaveValue("1");
270
246
  expect(dateRangePicker).toBeInTheDocument();
271
247
  expect(ageFromInput).toHaveValue(12);
272
248
  expect(ageToInput).toHaveValue(60);
273
- expect(sortBySelect).toHaveValue("first_name");
274
- expect(sortOrderSelect).toHaveValue("desc");
275
249
  });
276
250
 
277
251
  it("has correct accessibility attributes", () => {
@@ -283,8 +257,6 @@ describe("ChildSearchFilters", () => {
283
257
  expect(screen.getByText("Date of Birth Range")).toBeInTheDocument();
284
258
  expect(screen.getByText("Age From (months)")).toBeInTheDocument();
285
259
  expect(screen.getByText("Age To (months)")).toBeInTheDocument();
286
- expect(screen.getByText("Sort By")).toBeInTheDocument();
287
- expect(screen.getByText("Sort Order")).toBeInTheDocument();
288
260
  });
289
261
 
290
262
  it("applies correct CSS classes for dark mode support", () => {