@abstraks-dev/ui-library 1.1.24 → 1.1.28

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.
Files changed (110) hide show
  1. package/dist/__tests__/AccountBox.test.js +61 -0
  2. package/dist/__tests__/AccountCircle.test.js +69 -0
  3. package/dist/__tests__/Alert.test.js +144 -0
  4. package/dist/__tests__/ArrowIcon.test.js +61 -0
  5. package/dist/__tests__/ArrowRight.test.js +12 -7
  6. package/dist/__tests__/BookOpen.test.js +61 -0
  7. package/dist/__tests__/Camera.test.js +69 -0
  8. package/dist/__tests__/CaretDown.test.js +69 -0
  9. package/dist/__tests__/ChevronDown.test.js +13 -8
  10. package/dist/__tests__/Comment.test.js +69 -0
  11. package/dist/__tests__/Ellipses.test.js +61 -0
  12. package/dist/__tests__/Explore.test.js +61 -0
  13. package/dist/__tests__/FileInput.test.js +148 -0
  14. package/dist/__tests__/Filter.test.js +69 -0
  15. package/dist/__tests__/Form.test.js +471 -0
  16. package/dist/__tests__/Group.test.js +61 -0
  17. package/dist/__tests__/GroupReview.test.js +61 -0
  18. package/dist/__tests__/Hamburger.test.js +69 -0
  19. package/dist/__tests__/Header.test.js +198 -0
  20. package/dist/__tests__/Heart.test.js +69 -0
  21. package/dist/__tests__/Home.test.js +69 -0
  22. package/dist/__tests__/LoadingSpinner.test.js +78 -0
  23. package/dist/__tests__/LogOut.test.js +69 -0
  24. package/dist/__tests__/Magnify.test.js +69 -0
  25. package/dist/__tests__/News.test.js +61 -0
  26. package/dist/__tests__/Review.test.js +61 -0
  27. package/dist/__tests__/SaveIcon.test.js +61 -0
  28. package/dist/__tests__/Search.test.js +101 -0
  29. package/dist/__tests__/utils/accessibility.test.js +361 -0
  30. package/dist/__tests__/utils/inputValidation-core.test.js +80 -0
  31. package/dist/__tests__/utils/validation-core.test.js +123 -0
  32. package/dist/__tests__/utils/validation.test.js +362 -0
  33. package/dist/components/Alert.js +104 -0
  34. package/dist/components/FileInput.js +96 -0
  35. package/dist/components/Form.js +87 -39
  36. package/dist/components/Header.js +29 -1
  37. package/dist/components/Radio.js +1 -3
  38. package/dist/components/Search.js +236 -0
  39. package/dist/icons/AccountBox.js +33 -0
  40. package/dist/icons/AccountCircle.js +33 -0
  41. package/dist/icons/ArrowIcon.js +3 -2
  42. package/dist/icons/ArrowRight.js +23 -12
  43. package/dist/icons/BookOpen.js +33 -0
  44. package/dist/icons/Camera.js +33 -0
  45. package/dist/icons/CaretDown.js +33 -0
  46. package/dist/icons/ChevronDown.js +19 -9
  47. package/dist/icons/Comment.js +33 -0
  48. package/dist/icons/Explore.js +33 -0
  49. package/dist/icons/Filter.js +33 -0
  50. package/dist/icons/Group.js +33 -0
  51. package/dist/icons/GroupReview.js +33 -0
  52. package/dist/icons/Hamburger.js +14 -20
  53. package/dist/icons/Heart.js +33 -0
  54. package/dist/icons/Home.js +33 -0
  55. package/dist/icons/LoadingSpinner.js +3 -2
  56. package/dist/icons/LogOut.js +33 -0
  57. package/dist/icons/Magnify.js +33 -0
  58. package/dist/icons/News.js +33 -0
  59. package/dist/icons/Review.js +35 -0
  60. package/dist/icons/SaveIcon.js +3 -2
  61. package/dist/icons/index.js +112 -0
  62. package/dist/index.js +32 -0
  63. package/dist/styles/_variables.scss +2 -0
  64. package/dist/styles/alert.css +218 -0
  65. package/dist/styles/alert.css.map +1 -0
  66. package/dist/styles/alert.scss +128 -0
  67. package/dist/styles/anchor.css.map +1 -1
  68. package/dist/styles/avatar.css.map +1 -1
  69. package/dist/styles/button.css.map +1 -1
  70. package/dist/styles/card.css.map +1 -1
  71. package/dist/styles/checkbox.css.map +1 -1
  72. package/dist/styles/crud.css.map +1 -1
  73. package/dist/styles/dragAndDrop.css.map +1 -1
  74. package/dist/styles/error.css.map +1 -1
  75. package/dist/styles/file-input.css +165 -0
  76. package/dist/styles/file-input.css.map +1 -0
  77. package/dist/styles/file-input.scss +69 -0
  78. package/dist/styles/footer.css.map +1 -1
  79. package/dist/styles/form.css.map +1 -1
  80. package/dist/styles/header.css +9 -0
  81. package/dist/styles/header.css.map +1 -1
  82. package/dist/styles/header.scss +16 -7
  83. package/dist/styles/heading.css.map +1 -1
  84. package/dist/styles/hero.css.map +1 -1
  85. package/dist/styles/htmlElements.css.map +1 -1
  86. package/dist/styles/label.css.map +1 -1
  87. package/dist/styles/loader.css.map +1 -1
  88. package/dist/styles/main.css +320 -0
  89. package/dist/styles/main.css.map +1 -1
  90. package/dist/styles/menu-hover.css.map +1 -1
  91. package/dist/styles/paragraph.css.map +1 -1
  92. package/dist/styles/prompt.css.map +1 -1
  93. package/dist/styles/radio.css.map +1 -1
  94. package/dist/styles/search.css +269 -0
  95. package/dist/styles/search.css.map +1 -0
  96. package/dist/styles/search.scss +215 -0
  97. package/dist/styles/select.css.map +1 -1
  98. package/dist/styles/side-menu.css.map +1 -1
  99. package/dist/styles/tabs.css.map +1 -1
  100. package/dist/styles/text-area.css.map +1 -1
  101. package/dist/styles/text-input.css.map +1 -1
  102. package/dist/utils/utils/validation.js +2 -2
  103. package/dist/utils/validation.js +2 -2
  104. package/package.json +2 -2
  105. package/dist/icons/__tests__/CheckCircle.test.js +0 -9
  106. package/dist/icons/__tests__/ChevronDown.test.js +0 -9
  107. package/dist/icons/__tests__/Close.test.js +0 -9
  108. package/dist/icons/__tests__/EditSquare.test.js +0 -9
  109. package/dist/icons/__tests__/PlusCircle.test.js +0 -9
  110. package/dist/icons/__tests__/TrashX.test.js +0 -9
@@ -0,0 +1,471 @@
1
+ "use strict";
2
+
3
+ var _react = _interopRequireDefault(require("react"));
4
+ var _react2 = require("@testing-library/react");
5
+ var _userEvent = _interopRequireDefault(require("@testing-library/user-event"));
6
+ var _Form = _interopRequireDefault(require("../components/Form"));
7
+ var _TextInput = _interopRequireDefault(require("../components/TextInput"));
8
+ var _Button = _interopRequireDefault(require("../components/Button"));
9
+ var _Checkbox = _interopRequireDefault(require("../components/Checkbox"));
10
+ var _Radio = _interopRequireDefault(require("../components/Radio"));
11
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
12
+ // Mock accessibility utils
13
+ jest.mock('../utils/accessibility.js', () => ({
14
+ announceToScreenReader: jest.fn(() => jest.fn()),
15
+ safeFocus: jest.fn()
16
+ }));
17
+ const {
18
+ announceToScreenReader,
19
+ safeFocus
20
+ } = require('../utils/accessibility.js');
21
+ describe('Form Component', () => {
22
+ beforeEach(() => {
23
+ jest.clearAllMocks();
24
+ });
25
+ describe('Basic Rendering', () => {
26
+ it('renders form element with default props', () => {
27
+ (0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Form.default, null, /*#__PURE__*/_react.default.createElement("div", null, "Form content")));
28
+ const form = _react2.screen.getByRole('form');
29
+ expect(form).toBeInTheDocument();
30
+ expect(form).toHaveClass('form');
31
+ expect(form).toHaveAttribute('noValidate');
32
+ expect(form).toHaveAttribute('autoComplete', 'on');
33
+ expect(form).toHaveAttribute('method', 'post');
34
+ });
35
+ it('applies custom component name and additional class', () => {
36
+ (0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Form.default, {
37
+ componentName: "custom-form",
38
+ additionalClassName: "extra-class"
39
+ }, /*#__PURE__*/_react.default.createElement("div", null, "Form content")));
40
+ const form = _react2.screen.getByRole('form');
41
+ expect(form).toHaveClass('custom-form', 'extra-class');
42
+ });
43
+ it('renders with custom HTML form attributes', () => {
44
+ (0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Form.default, {
45
+ method: "get",
46
+ action: "/submit",
47
+ encType: "multipart/form-data",
48
+ target: "_blank",
49
+ acceptCharset: "UTF-8",
50
+ ariaLabel: "Registration form",
51
+ ariaDescribedBy: "form-description",
52
+ ariaLabelledBy: "form-title",
53
+ id: "registration-form"
54
+ }, /*#__PURE__*/_react.default.createElement("div", null, "Form content")));
55
+ const form = _react2.screen.getByRole('form');
56
+ expect(form).toHaveAttribute('method', 'get');
57
+ expect(form).toHaveAttribute('action', '/submit');
58
+ expect(form).toHaveAttribute('encType', 'multipart/form-data');
59
+ expect(form).toHaveAttribute('target', '_blank');
60
+ expect(form).toHaveAttribute('accept-charset', 'UTF-8');
61
+ expect(form).toHaveAttribute('aria-label', 'Registration form');
62
+ expect(form).toHaveAttribute('aria-describedby', 'form-description');
63
+ expect(form).toHaveAttribute('aria-labelledby', 'form-title');
64
+ expect(form).toHaveAttribute('id', 'registration-form');
65
+ });
66
+ it('renders children correctly', () => {
67
+ (0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Form.default, null, /*#__PURE__*/_react.default.createElement(_TextInput.default, {
68
+ name: "email"
69
+ }), /*#__PURE__*/_react.default.createElement(_Button.default, {
70
+ type: "submit"
71
+ }, "Submit")));
72
+ expect(_react2.screen.getByRole('textbox')).toBeInTheDocument();
73
+ // The button accessible name includes the helper text
74
+ expect(_react2.screen.getByRole('button', {
75
+ name: /submit/i
76
+ })).toBeInTheDocument();
77
+ });
78
+ });
79
+ describe('Form State Management', () => {
80
+ it('updates form data when input values change', async () => {
81
+ const user = _userEvent.default.setup();
82
+ const mockChange = jest.fn();
83
+ (0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Form.default, {
84
+ onChange: mockChange
85
+ }, /*#__PURE__*/_react.default.createElement(_TextInput.default, {
86
+ name: "email",
87
+ placeholder: "Email"
88
+ }), /*#__PURE__*/_react.default.createElement(_TextInput.default, {
89
+ name: "name",
90
+ placeholder: "Name"
91
+ })));
92
+ const emailInput = _react2.screen.getByPlaceholderText('Email');
93
+ const nameInput = _react2.screen.getByPlaceholderText('Name');
94
+ await user.type(emailInput, 'test@example.com');
95
+ await user.type(nameInput, 'John Doe');
96
+ expect(mockChange).toHaveBeenCalledWith(expect.objectContaining({
97
+ email: 'test@example.com'
98
+ }), 'email', 'test@example.com');
99
+ expect(mockChange).toHaveBeenCalledWith(expect.objectContaining({
100
+ name: 'John Doe'
101
+ }), 'name', 'John Doe');
102
+ });
103
+ it('handles checkbox inputs correctly', async () => {
104
+ const user = _userEvent.default.setup();
105
+ const mockChange = jest.fn();
106
+ (0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Form.default, {
107
+ onChange: mockChange
108
+ }, /*#__PURE__*/_react.default.createElement(_Checkbox.default, {
109
+ name: "subscribe",
110
+ label: "Subscribe to newsletter"
111
+ })));
112
+ const checkbox = _react2.screen.getByRole('checkbox');
113
+ await user.click(checkbox);
114
+ expect(mockChange).toHaveBeenCalledWith(expect.objectContaining({
115
+ subscribe: true
116
+ }), 'subscribe', true);
117
+ });
118
+ it('handles radio button inputs correctly', async () => {
119
+ const user = _userEvent.default.setup();
120
+ const mockChange = jest.fn();
121
+ (0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Form.default, {
122
+ onChange: mockChange
123
+ }, /*#__PURE__*/_react.default.createElement(_Radio.default, {
124
+ name: "gender",
125
+ value: "male",
126
+ label: "Male"
127
+ }), /*#__PURE__*/_react.default.createElement(_Radio.default, {
128
+ name: "gender",
129
+ value: "female",
130
+ label: "Female"
131
+ })));
132
+ const maleRadio = _react2.screen.getByDisplayValue('male');
133
+ await user.click(maleRadio);
134
+ expect(mockChange).toHaveBeenCalledWith(expect.objectContaining({
135
+ gender: 'male'
136
+ }), 'gender', 'male');
137
+ });
138
+ });
139
+ describe('Form Submission', () => {
140
+ it('calls onSubmit with form data when submitted', async () => {
141
+ const user = _userEvent.default.setup();
142
+ const mockSubmit = jest.fn().mockResolvedValue();
143
+ (0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Form.default, {
144
+ onSubmit: mockSubmit
145
+ }, /*#__PURE__*/_react.default.createElement(_TextInput.default, {
146
+ name: "email",
147
+ placeholder: "Email"
148
+ }), /*#__PURE__*/_react.default.createElement(_Button.default, {
149
+ type: "submit"
150
+ }, "Submit")));
151
+ const emailInput = _react2.screen.getByPlaceholderText('Email');
152
+ const submitButton = _react2.screen.getByRole('button', {
153
+ name: /submit/i
154
+ });
155
+ await user.type(emailInput, 'test@example.com');
156
+ await user.click(submitButton);
157
+ expect(mockSubmit).toHaveBeenCalledWith({
158
+ email: 'test@example.com'
159
+ }, expect.objectContaining({
160
+ setErrors: expect.any(Function),
161
+ setFormData: expect.any(Function),
162
+ resetForm: expect.any(Function),
163
+ updateField: expect.any(Function)
164
+ }), expect.any(Object));
165
+ });
166
+ it('prevents submission when form is disabled', async () => {
167
+ const user = _userEvent.default.setup();
168
+ const mockSubmit = jest.fn();
169
+ (0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Form.default, {
170
+ onSubmit: mockSubmit,
171
+ disabled: true
172
+ }, /*#__PURE__*/_react.default.createElement(_TextInput.default, {
173
+ name: "email",
174
+ placeholder: "Email"
175
+ }), /*#__PURE__*/_react.default.createElement(_Button.default, {
176
+ type: "submit"
177
+ }, "Submit")));
178
+ const submitButton = _react2.screen.getByRole('button', {
179
+ name: /submit/i
180
+ });
181
+ await user.click(submitButton);
182
+ expect(mockSubmit).not.toHaveBeenCalled();
183
+ });
184
+ it('prevents submission when form is currently submitting', async () => {
185
+ const user = _userEvent.default.setup();
186
+ const mockSubmit = jest.fn();
187
+ (0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Form.default, {
188
+ onSubmit: mockSubmit,
189
+ isSubmitting: true
190
+ }, /*#__PURE__*/_react.default.createElement(_TextInput.default, {
191
+ name: "email",
192
+ placeholder: "Email"
193
+ }), /*#__PURE__*/_react.default.createElement(_Button.default, {
194
+ type: "submit"
195
+ }, "Submit")));
196
+ const submitButton = _react2.screen.getByRole('button', {
197
+ name: /submit/i
198
+ });
199
+ await user.click(submitButton);
200
+ expect(mockSubmit).not.toHaveBeenCalled();
201
+ });
202
+ it('resets form after submission when resetOnSubmit is true', async () => {
203
+ const user = _userEvent.default.setup();
204
+ const mockSubmit = jest.fn().mockResolvedValue();
205
+ (0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Form.default, {
206
+ onSubmit: mockSubmit,
207
+ resetOnSubmit: true
208
+ }, /*#__PURE__*/_react.default.createElement(_TextInput.default, {
209
+ name: "email",
210
+ placeholder: "Email"
211
+ }), /*#__PURE__*/_react.default.createElement(_Button.default, {
212
+ type: "submit"
213
+ }, "Submit")));
214
+ const emailInput = _react2.screen.getByPlaceholderText('Email');
215
+ const submitButton = _react2.screen.getByRole('button', {
216
+ name: /submit/i
217
+ });
218
+ await user.type(emailInput, 'test@example.com');
219
+ await user.click(submitButton);
220
+ await (0, _react2.waitFor)(() => {
221
+ expect(emailInput).toHaveValue('');
222
+ });
223
+ });
224
+ });
225
+ describe('Validation', () => {
226
+ const mockValidation = (fieldName, value) => {
227
+ if (fieldName === 'email' && !value?.includes('@')) {
228
+ return 'Please enter a valid email address';
229
+ }
230
+ if (fieldName === 'name' && (!value || value.length < 2)) {
231
+ return 'Name must be at least 2 characters';
232
+ }
233
+ return null;
234
+ };
235
+ it('validates on submit by default', async () => {
236
+ const user = _userEvent.default.setup();
237
+ const mockSubmit = jest.fn();
238
+ (0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Form.default, {
239
+ onSubmit: mockSubmit,
240
+ onValidate: mockValidation
241
+ }, /*#__PURE__*/_react.default.createElement(_TextInput.default, {
242
+ name: "email",
243
+ placeholder: "Email"
244
+ }), /*#__PURE__*/_react.default.createElement(_Button.default, {
245
+ type: "submit"
246
+ }, "Submit")));
247
+ const emailInput = _react2.screen.getByPlaceholderText('Email');
248
+ const submitButton = _react2.screen.getByRole('button', {
249
+ name: /submit/i
250
+ });
251
+ await user.type(emailInput, 'invalid-email');
252
+ await user.click(submitButton);
253
+ expect(mockSubmit).not.toHaveBeenCalled();
254
+ expect(emailInput).toHaveAttribute('aria-invalid', 'true');
255
+ });
256
+ it('validates on blur when validationMode is onBlur', async () => {
257
+ const user = _userEvent.default.setup();
258
+ (0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Form.default, {
259
+ onValidate: mockValidation,
260
+ validationMode: "onBlur"
261
+ }, /*#__PURE__*/_react.default.createElement(_TextInput.default, {
262
+ name: "email",
263
+ placeholder: "Email"
264
+ })));
265
+ const emailInput = _react2.screen.getByPlaceholderText('Email');
266
+ await user.type(emailInput, 'invalid-email');
267
+ await user.tab(); // Blur the input
268
+
269
+ await (0, _react2.waitFor)(() => {
270
+ expect(emailInput).toHaveAttribute('aria-invalid', 'true');
271
+ });
272
+ });
273
+ it('validates on change when validationMode is onChange', async () => {
274
+ const user = _userEvent.default.setup();
275
+ (0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Form.default, {
276
+ onValidate: mockValidation,
277
+ validationMode: "onChange"
278
+ }, /*#__PURE__*/_react.default.createElement(_TextInput.default, {
279
+ name: "email",
280
+ placeholder: "Email"
281
+ })));
282
+ const emailInput = _react2.screen.getByPlaceholderText('Email');
283
+ await user.type(emailInput, 'invalid');
284
+ await (0, _react2.waitFor)(() => {
285
+ expect(emailInput).toHaveAttribute('aria-invalid', 'true');
286
+ });
287
+ });
288
+ it('displays external errors in individual fields', () => {
289
+ const errors = {
290
+ email: 'This email is already taken',
291
+ name: 'Name is required'
292
+ };
293
+ (0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Form.default, {
294
+ errors: errors
295
+ }, /*#__PURE__*/_react.default.createElement(_TextInput.default, {
296
+ name: "email",
297
+ placeholder: "Email"
298
+ }), /*#__PURE__*/_react.default.createElement(_TextInput.default, {
299
+ name: "name",
300
+ placeholder: "Name"
301
+ })));
302
+
303
+ // Check that errors appear (may be in multiple places due to form structure)
304
+ expect(_react2.screen.getAllByText('This email is already taken')[0]).toBeInTheDocument();
305
+ expect(_react2.screen.getAllByText('Name is required')[0]).toBeInTheDocument();
306
+ });
307
+ it('focuses first error field on validation failure', async () => {
308
+ const user = _userEvent.default.setup();
309
+ const mockSubmit = jest.fn();
310
+ (0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Form.default, {
311
+ onSubmit: mockSubmit,
312
+ onValidate: mockValidation
313
+ }, /*#__PURE__*/_react.default.createElement(_TextInput.default, {
314
+ name: "name",
315
+ placeholder: "Name"
316
+ }), /*#__PURE__*/_react.default.createElement(_TextInput.default, {
317
+ name: "email",
318
+ placeholder: "Email"
319
+ }), /*#__PURE__*/_react.default.createElement(_Button.default, {
320
+ type: "submit"
321
+ }, "Submit")));
322
+ const nameInput = _react2.screen.getByPlaceholderText('Name');
323
+ const submitButton = _react2.screen.getByRole('button', {
324
+ name: /submit/i
325
+ });
326
+
327
+ // Submit without entering data
328
+ await user.click(submitButton);
329
+ await (0, _react2.waitFor)(() => {
330
+ expect(safeFocus).toHaveBeenCalledWith(nameInput);
331
+ });
332
+ });
333
+ });
334
+ describe('Accessibility Features', () => {
335
+ it('announces validation errors to screen readers', async () => {
336
+ const user = _userEvent.default.setup();
337
+ const mockValidation = (fieldName, value) => {
338
+ if (fieldName === 'email' && !value?.includes('@')) {
339
+ return 'Please enter a valid email address';
340
+ }
341
+ return null;
342
+ };
343
+ (0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Form.default, {
344
+ onValidate: mockValidation,
345
+ validationMode: "onBlur"
346
+ }, /*#__PURE__*/_react.default.createElement(_TextInput.default, {
347
+ name: "email",
348
+ placeholder: "Email"
349
+ })));
350
+ const emailInput = _react2.screen.getByPlaceholderText('Email');
351
+ await user.type(emailInput, 'invalid-email');
352
+ await user.tab(); // Blur the input
353
+
354
+ expect(announceToScreenReader).toHaveBeenCalledWith('email: Please enter a valid email address', 'assertive');
355
+ });
356
+ it('announces form submission success', async () => {
357
+ const user = _userEvent.default.setup();
358
+ const mockSubmit = jest.fn().mockResolvedValue();
359
+ (0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Form.default, {
360
+ onSubmit: mockSubmit
361
+ }, /*#__PURE__*/_react.default.createElement(_TextInput.default, {
362
+ name: "email",
363
+ placeholder: "Email"
364
+ }), /*#__PURE__*/_react.default.createElement(_Button.default, {
365
+ type: "submit"
366
+ }, "Submit")));
367
+ const emailInput = _react2.screen.getByPlaceholderText('Email');
368
+ const submitButton = _react2.screen.getByRole('button', {
369
+ name: /submit/i
370
+ });
371
+ await user.type(emailInput, 'test@example.com');
372
+ await user.click(submitButton);
373
+ await (0, _react2.waitFor)(() => {
374
+ expect(announceToScreenReader).toHaveBeenCalledWith('Form submitted successfully', 'polite');
375
+ });
376
+ });
377
+ it('announces validation failure on submit', async () => {
378
+ const user = _userEvent.default.setup();
379
+ const mockSubmit = jest.fn();
380
+ const mockValidation = (fieldName, value) => {
381
+ if (fieldName === 'email' && !value?.includes('@')) {
382
+ return 'Please enter a valid email address';
383
+ }
384
+ return null;
385
+ };
386
+ (0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Form.default, {
387
+ onSubmit: mockSubmit,
388
+ onValidate: mockValidation
389
+ }, /*#__PURE__*/_react.default.createElement(_TextInput.default, {
390
+ name: "email",
391
+ placeholder: "Email"
392
+ }), /*#__PURE__*/_react.default.createElement(_Button.default, {
393
+ type: "submit"
394
+ }, "Submit")));
395
+ const emailInput = _react2.screen.getByPlaceholderText('Email');
396
+ const submitButton = _react2.screen.getByRole('button', {
397
+ name: /submit/i
398
+ });
399
+ await user.type(emailInput, 'invalid-email');
400
+ await user.click(submitButton);
401
+ expect(announceToScreenReader).toHaveBeenCalledWith('Form submission failed. 1 field has validation errors.', 'assertive');
402
+ });
403
+ it('shows submitting status for screen readers', () => {
404
+ (0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Form.default, {
405
+ isSubmitting: true
406
+ }, /*#__PURE__*/_react.default.createElement(_TextInput.default, {
407
+ name: "email",
408
+ placeholder: "Email"
409
+ }), /*#__PURE__*/_react.default.createElement(_Button.default, {
410
+ type: "submit"
411
+ }, "Submit")));
412
+ expect(_react2.screen.getByText('Form is being submitted, please wait...')).toBeInTheDocument();
413
+ });
414
+ });
415
+ describe('Form State Utilities', () => {
416
+ it('provides form utilities to onSubmit handler', async () => {
417
+ const user = _userEvent.default.setup();
418
+ let capturedUtils = null;
419
+ const mockSubmit = jest.fn((formData, utils) => {
420
+ capturedUtils = utils;
421
+ });
422
+ (0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Form.default, {
423
+ onSubmit: mockSubmit
424
+ }, /*#__PURE__*/_react.default.createElement(_TextInput.default, {
425
+ name: "email",
426
+ placeholder: "Email"
427
+ }), /*#__PURE__*/_react.default.createElement(_Button.default, {
428
+ type: "submit"
429
+ }, "Submit")));
430
+ const emailInput = _react2.screen.getByPlaceholderText('Email');
431
+ const submitButton = _react2.screen.getByRole('button', {
432
+ name: /submit/i
433
+ });
434
+ await user.type(emailInput, 'test@example.com');
435
+ await user.click(submitButton);
436
+ expect(capturedUtils).toHaveProperty('setErrors');
437
+ expect(capturedUtils).toHaveProperty('setFormData');
438
+ expect(capturedUtils).toHaveProperty('resetForm');
439
+ expect(capturedUtils).toHaveProperty('updateField');
440
+ expect(typeof capturedUtils.setErrors).toBe('function');
441
+ expect(typeof capturedUtils.resetForm).toBe('function');
442
+ });
443
+ it('allows manual form reset through utilities', async () => {
444
+ const user = _userEvent.default.setup();
445
+ let formUtils = null;
446
+ const mockSubmit = jest.fn((formData, utils) => {
447
+ formUtils = utils;
448
+ });
449
+ (0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Form.default, {
450
+ onSubmit: mockSubmit
451
+ }, /*#__PURE__*/_react.default.createElement(_TextInput.default, {
452
+ name: "email",
453
+ placeholder: "Email"
454
+ }), /*#__PURE__*/_react.default.createElement(_Button.default, {
455
+ type: "submit"
456
+ }, "Submit")));
457
+ const emailInput = _react2.screen.getByPlaceholderText('Email');
458
+ const submitButton = _react2.screen.getByRole('button', {
459
+ name: /submit/i
460
+ });
461
+ await user.type(emailInput, 'test@example.com');
462
+ await user.click(submitButton);
463
+
464
+ // Reset form manually
465
+ (0, _react2.act)(() => {
466
+ formUtils.resetForm();
467
+ });
468
+ expect(emailInput).toHaveValue('');
469
+ });
470
+ });
471
+ });
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+
3
+ var _react = _interopRequireDefault(require("react"));
4
+ var _react2 = require("@testing-library/react");
5
+ var _Group = require("../icons/Group");
6
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
7
+ describe('Group Icon', () => {
8
+ test('renders with default props', () => {
9
+ (0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Group.Group, null));
10
+ const svg = document.querySelector('svg');
11
+ expect(svg).toBeInTheDocument();
12
+ expect(svg.tagName).toBe('svg');
13
+ });
14
+ test('applies correct default dimensions', () => {
15
+ (0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Group.Group, null));
16
+ const svg = document.querySelector('svg');
17
+ expect(svg).toHaveAttribute('width', '24');
18
+ expect(svg).toHaveAttribute('height', '24');
19
+ });
20
+ test('applies custom dimensions', () => {
21
+ (0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Group.Group, {
22
+ dimensions: 32
23
+ }));
24
+ const svg = document.querySelector('svg');
25
+ expect(svg).toHaveAttribute('width', '32');
26
+ expect(svg).toHaveAttribute('height', '32');
27
+ });
28
+ test('applies correct CSS classes', () => {
29
+ (0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Group.Group, null));
30
+ const svg = document.querySelector('svg');
31
+ expect(svg).toHaveClass('icon', 'group');
32
+ });
33
+ test('applies additional className', () => {
34
+ (0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Group.Group, {
35
+ additionalClassName: "custom-class"
36
+ }));
37
+ const svg = document.querySelector('svg');
38
+ expect(svg).toHaveClass('icon', 'group', 'custom-class');
39
+ });
40
+ test('applies custom fill color', () => {
41
+ (0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Group.Group, {
42
+ fill: "#ff0000"
43
+ }));
44
+ const svg = document.querySelector('svg');
45
+ expect(svg).toHaveAttribute('fill', '#ff0000');
46
+ });
47
+ test('contains correct path data', () => {
48
+ const {
49
+ container
50
+ } = (0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Group.Group, null));
51
+ const path = container.querySelector('path');
52
+ expect(path).toHaveAttribute('d', 'M40-160v-112q0-34 17.5-62.5T104-378q62-31 126-46.5T360-440q66 0 130 15.5T616-378q29 15 46.5 43.5T680-272v112H40Zm720 0v-120q0-44-24.5-84.5T666-434q51 6 96 20.5t84 35.5q36 20 55 44.5t19 53.5v120H760ZM360-480q-66 0-113-47t-47-113q0-66 47-113t113-47q66 0 113 47t47 113q0 66-47 113t-113 47Zm400-160q0 66-47 113t-113 47q-11 0-28-2.5t-28-5.5q27-32 41.5-71t14.5-81q0-42-14.5-81T544-792q14-5 28-6.5t28-1.5q66 0 113 47t47 113ZM120-240h480v-32q0-11-5.5-20T580-306q-54-27-109-40.5T360-360q-56 0-111 13.5T140-306q-9 5-14.5 14t-5.5 20v32Zm240-320q33 0 56.5-23.5T440-640q0-33-23.5-56.5T360-720q-33 0-56.5 23.5T280-640q0 33 23.5 56.5T360-560Zm0 320Zm0-400Z');
53
+ });
54
+ test('contains single path element', () => {
55
+ const {
56
+ container
57
+ } = (0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Group.Group, null));
58
+ const paths = container.querySelectorAll('path');
59
+ expect(paths).toHaveLength(1);
60
+ });
61
+ });
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+
3
+ var _react = _interopRequireDefault(require("react"));
4
+ var _react2 = require("@testing-library/react");
5
+ var _GroupReview = require("../icons/GroupReview");
6
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
7
+ describe('GroupReview Icon', () => {
8
+ test('renders with default props', () => {
9
+ (0, _react2.render)(/*#__PURE__*/_react.default.createElement(_GroupReview.GroupReview, null));
10
+ const svg = document.querySelector('svg');
11
+ expect(svg).toBeInTheDocument();
12
+ expect(svg.tagName).toBe('svg');
13
+ });
14
+ test('applies correct default dimensions', () => {
15
+ (0, _react2.render)(/*#__PURE__*/_react.default.createElement(_GroupReview.GroupReview, null));
16
+ const svg = document.querySelector('svg');
17
+ expect(svg).toHaveAttribute('width', '24');
18
+ expect(svg).toHaveAttribute('height', '24');
19
+ });
20
+ test('applies custom dimensions', () => {
21
+ (0, _react2.render)(/*#__PURE__*/_react.default.createElement(_GroupReview.GroupReview, {
22
+ dimensions: 32
23
+ }));
24
+ const svg = document.querySelector('svg');
25
+ expect(svg).toHaveAttribute('width', '32');
26
+ expect(svg).toHaveAttribute('height', '32');
27
+ });
28
+ test('applies correct CSS classes', () => {
29
+ (0, _react2.render)(/*#__PURE__*/_react.default.createElement(_GroupReview.GroupReview, null));
30
+ const svg = document.querySelector('svg');
31
+ expect(svg).toHaveClass('icon', 'group-review');
32
+ });
33
+ test('applies additional className', () => {
34
+ (0, _react2.render)(/*#__PURE__*/_react.default.createElement(_GroupReview.GroupReview, {
35
+ additionalClassName: "custom-class"
36
+ }));
37
+ const svg = document.querySelector('svg');
38
+ expect(svg).toHaveClass('icon', 'group-review', 'custom-class');
39
+ });
40
+ test('applies custom fill color', () => {
41
+ (0, _react2.render)(/*#__PURE__*/_react.default.createElement(_GroupReview.GroupReview, {
42
+ fill: "#ff0000"
43
+ }));
44
+ const svg = document.querySelector('svg');
45
+ expect(svg).toHaveAttribute('fill', '#ff0000');
46
+ });
47
+ test('contains correct path data', () => {
48
+ const {
49
+ container
50
+ } = (0, _react2.render)(/*#__PURE__*/_react.default.createElement(_GroupReview.GroupReview, null));
51
+ const path = container.querySelector('path');
52
+ expect(path).toHaveAttribute('d', 'M0-240v-63q0-43 44-70t116-27q13 0 25 .5t23 2.5q-14 21-21 44t-7 48v65H0Zm240 0v-65q0-32 17.5-58.5T307-410q32-20 76.5-30t96.5-10q53 0 97.5 10t76.5 30q32 20 49 46.5t17 58.5v65H240Zm540 0v-65q0-26-6.5-49T754-397q11-2 22.5-2.5t23.5-.5q72 0 116 26.5t44 70.5v63H780Zm-455-80h311q-10-20-55.5-35T480-370q-55 0-100.5 15T325-320ZM160-440q-33 0-56.5-23.5T80-520q0-34 23.5-57t56.5-23q34 0 57 23t23 57q0 33-23 56.5T160-440Zm640 0q-33 0-56.5-23.5T720-520q0-34 23.5-57t56.5-23q34 0 57 23t23 57q0 33-23 56.5T800-440Zm-320-40q-50 0-85-35t-35-85q0-51 35-85.5t85-34.5q51 0 85.5 34.5T600-600q0 50-34.5 85T480-480Zm0-80q17 0 28.5-11.5T520-600q0-17-11.5-28.5T480-640q-17 0-28.5 11.5T440-600q0 17 11.5 28.5T480-560Zm1 240Zm-1-280Z');
53
+ });
54
+ test('contains single path element', () => {
55
+ const {
56
+ container
57
+ } = (0, _react2.render)(/*#__PURE__*/_react.default.createElement(_GroupReview.GroupReview, null));
58
+ const paths = container.querySelectorAll('path');
59
+ expect(paths).toHaveLength(1);
60
+ });
61
+ });
@@ -0,0 +1,69 @@
1
+ "use strict";
2
+
3
+ var _react = _interopRequireDefault(require("react"));
4
+ var _react2 = require("@testing-library/react");
5
+ var _Hamburger = require("../icons/Hamburger.js");
6
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
7
+ // Suppress console.error during tests
8
+ let consoleErrorSpy;
9
+ beforeAll(() => {
10
+ consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
11
+ });
12
+ afterAll(() => {
13
+ consoleErrorSpy.mockRestore();
14
+ });
15
+ describe('Hamburger Icon', () => {
16
+ test('renders SVG element', () => {
17
+ (0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Hamburger.Hamburger, null));
18
+ const svg = document.querySelector('svg');
19
+ expect(svg).toBeInTheDocument();
20
+ expect(svg.tagName).toBe('svg');
21
+ });
22
+ test('has correct default props', () => {
23
+ (0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Hamburger.Hamburger, null));
24
+ const svg = document.querySelector('svg');
25
+ expect(svg).toHaveAttribute('width', '24');
26
+ expect(svg).toHaveAttribute('height', '24');
27
+ expect(svg).toHaveAttribute('viewBox', '0 -960 960 960');
28
+ expect(svg).toHaveAttribute('fill', '#adb5bd');
29
+ expect(svg).toHaveClass('icon');
30
+ expect(svg).toHaveClass('hamburger');
31
+ });
32
+ test('applies custom dimensions', () => {
33
+ (0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Hamburger.Hamburger, {
34
+ dimensions: 32
35
+ }));
36
+ const svg = document.querySelector('svg');
37
+ expect(svg).toHaveAttribute('width', '32');
38
+ expect(svg).toHaveAttribute('height', '32');
39
+ });
40
+ test('applies custom componentName and additionalClassName', () => {
41
+ (0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Hamburger.Hamburger, {
42
+ componentName: "custom-hamburger",
43
+ additionalClassName: "extra-class"
44
+ }));
45
+ const svg = document.querySelector('svg');
46
+ expect(svg).toHaveClass('icon');
47
+ expect(svg).toHaveClass('custom-hamburger');
48
+ expect(svg).toHaveClass('extra-class');
49
+ });
50
+ test('applies custom fill color', () => {
51
+ (0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Hamburger.Hamburger, {
52
+ fill: "#ff0000"
53
+ }));
54
+ const svg = document.querySelector('svg');
55
+ expect(svg).toHaveAttribute('fill', '#ff0000');
56
+ });
57
+ test('has correct path data', () => {
58
+ (0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Hamburger.Hamburger, null));
59
+ const svg = document.querySelector('svg');
60
+ const path = svg.querySelector('path');
61
+ expect(path).toHaveAttribute('d', 'M120-240v-80h720v80H120Zm0-200v-80h720v80H120Zm0-200v-80h720v80H120Z');
62
+ });
63
+ test('contains exactly one path element', () => {
64
+ (0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Hamburger.Hamburger, null));
65
+ const svg = document.querySelector('svg');
66
+ const paths = svg.querySelectorAll('path');
67
+ expect(paths).toHaveLength(1);
68
+ });
69
+ });