ywana-core8 0.1.103 → 0.2.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.
Files changed (172) hide show
  1. package/dist/index.css +4941 -324
  2. package/dist/index.js +42339 -0
  3. package/dist/index.js.map +1 -0
  4. package/dist/index.modern.js +37459 -31678
  5. package/dist/index.modern.js.map +1 -1
  6. package/dist/index.umd.js +39635 -34010
  7. package/dist/index.umd.js.map +1 -1
  8. package/package.json +26 -29
  9. package/src/Test.stories.jsx +28 -0
  10. package/src/desktop/Desktop.stories.jsx +110 -0
  11. package/src/desktop/WindowContext.js +135 -0
  12. package/src/desktop/WindowManager.js +355 -0
  13. package/src/desktop/desktop.css +55 -4
  14. package/src/desktop/desktop.js +312 -6
  15. package/src/desktop/index.js +7 -0
  16. package/src/desktop/window.css +229 -36
  17. package/src/desktop/window.js +255 -20
  18. package/src/desktop.backup/desktop.css +6 -0
  19. package/src/desktop.backup/desktop.js +13 -0
  20. package/src/desktop.backup/window.css +58 -0
  21. package/src/desktop.backup/window.js +27 -0
  22. package/src/html/Accordion.stories.jsx +178 -0
  23. package/src/html/Button.stories.jsx +175 -0
  24. package/src/html/Checkbox.stories.jsx +131 -0
  25. package/src/html/Chip.stories.jsx +189 -0
  26. package/src/html/Color.stories.jsx +234 -0
  27. package/src/html/Form.stories.jsx +271 -0
  28. package/src/html/Icon.stories.jsx +233 -0
  29. package/src/html/Progress.stories.jsx +247 -0
  30. package/src/html/Radio.stories.jsx +289 -0
  31. package/src/html/StyleTest.stories.jsx +81 -0
  32. package/src/html/Switch.stories.jsx +329 -0
  33. package/src/html/Tab.stories.jsx +239 -0
  34. package/src/html/Table.stories.jsx +188 -0
  35. package/src/html/Table2.stories.jsx +238 -0
  36. package/src/html/TextField2.stories.jsx +337 -0
  37. package/src/html/Tree.stories.jsx +285 -0
  38. package/src/html/accordion.example.js +0 -74
  39. package/src/html/accordion.js +1 -6
  40. package/src/html/button.js +2 -13
  41. package/src/html/checkbox.js +1 -9
  42. package/src/html/chip.js +2 -19
  43. package/src/html/color.js +1 -14
  44. package/src/html/form.js +4 -15
  45. package/src/html/header2.js +1 -12
  46. package/src/html/icon.js +1 -7
  47. package/src/html/index.js +1 -1
  48. package/src/html/list.js +1 -19
  49. package/src/html/menu.js +9 -5
  50. package/src/html/progress.js +5 -53
  51. package/src/html/property.js +9 -25
  52. package/src/html/radio.js +2 -16
  53. package/src/html/section.js +1 -6
  54. package/src/html/selector.js +2 -19
  55. package/src/html/switch.css +134 -100
  56. package/src/html/switch.example.js +46 -36
  57. package/src/html/switch.js +43 -192
  58. package/src/html/tab.js +3 -24
  59. package/src/html/text.js +1 -12
  60. package/src/html/textfield2.js +5 -42
  61. package/src/html/thumbnail.js +1 -12
  62. package/src/html/tokenfield.js +2 -21
  63. package/src/html/tree.js +3 -35
  64. package/src/index.js +1 -0
  65. package/__previewjs__/Wrapper.tsx +0 -14
  66. package/build-doc.sh +0 -10
  67. package/db/db.json +0 -89
  68. package/db/routes.json +0 -0
  69. package/dist/index.cjs +0 -36722
  70. package/dist/index.cjs.map +0 -1
  71. package/dist/index.css.map +0 -1
  72. package/doc/README.md +0 -196
  73. package/doc/evalulations/ACCORDION_EVALUATION.md +0 -583
  74. package/doc/evalulations/CHECKBOX_EVALUATION.md +0 -273
  75. package/doc/evalulations/CHIP_EVALUATION.md +0 -542
  76. package/doc/evalulations/COLOR_EVALUATION.md +0 -524
  77. package/doc/evalulations/COMPONENTS_EVALUATION.md +0 -477
  78. package/doc/evalulations/FORM_EVALUATION.md +0 -459
  79. package/doc/evalulations/HEADER_EVALUATION.md +0 -436
  80. package/doc/evalulations/ICON_EVALUATION.md +0 -254
  81. package/doc/evalulations/LIST_EVALUATION.md +0 -574
  82. package/doc/evalulations/PROGRESS_EVALUATION.md +0 -450
  83. package/doc/evalulations/RADIO_EVALUATION.md +0 -439
  84. package/doc/evalulations/RADIO_VISUAL_FIX.md +0 -183
  85. package/doc/evalulations/SECTION_IMPROVEMENTS.md +0 -153
  86. package/doc/evalulations/SWITCH_EVALUATION.md +0 -335
  87. package/doc/evalulations/SWITCH_VISUAL_FIX.md +0 -232
  88. package/doc/evalulations/TAB_EVALUATION.md +0 -626
  89. package/doc/evalulations/TEXTFIELD_EVALUATION.md +0 -747
  90. package/doc/evalulations/TOOLTIP_FIX.md +0 -157
  91. package/doc/evalulations/TREE_EVALUATION.md +0 -708
  92. package/doc/index.html +0 -0
  93. package/doc/package-lock.json +0 -17298
  94. package/doc/package.json +0 -34
  95. package/doc/public/index.html +0 -24
  96. package/doc/scripts/generate-examples.js +0 -129
  97. package/doc/src/App.css +0 -171
  98. package/doc/src/App.js +0 -114
  99. package/doc/src/components/ExamplePage.js +0 -129
  100. package/doc/src/components/WelcomePage.js +0 -84
  101. package/doc/src/index.css +0 -246
  102. package/doc/src/index.js +0 -17
  103. package/doc/src/theme.css +0 -256
  104. package/jest.config.js +0 -24
  105. package/preview.config.js +0 -38
  106. package/publish.sh +0 -6
  107. package/src/desktop/dektop.test.js +0 -11
  108. package/src/domain/CollectionAPI.test.js +0 -19
  109. package/src/domain/ContentEditor.test.js +0 -52
  110. package/src/domain2/CollectionAPI.test.js +0 -19
  111. package/src/domain2/CollectionContext.test.js +0 -71
  112. package/src/domain2/CollectionPage.test.js +0 -112
  113. package/src/domain2/DynamicForm.test.js +0 -47
  114. package/src/html/accordion.test.js +0 -37
  115. package/src/html/accordion.unit.test.js +0 -334
  116. package/src/html/button.example.new.js +0 -416
  117. package/src/html/button.test.js +0 -422
  118. package/src/html/checkbox.test.js +0 -285
  119. package/src/html/chip.test.js +0 -425
  120. package/src/html/color.example.js.backup +0 -527
  121. package/src/html/color.test.js +0 -377
  122. package/src/html/components.example.js.backup +0 -492
  123. package/src/html/components_enhanced.test.js +0 -581
  124. package/src/html/form.example.js.backup +0 -385
  125. package/src/html/form.test.js +0 -369
  126. package/src/html/header2.example.js.backup +0 -411
  127. package/src/html/header2.test.js +0 -377
  128. package/src/html/icon.example.js.backup +0 -268
  129. package/src/html/icon.test.js +0 -231
  130. package/src/html/label.test.js +0 -0
  131. package/src/html/list.example.js.backup +0 -404
  132. package/src/html/list.test.js +0 -383
  133. package/src/html/progress.example.js.backup +0 -424
  134. package/src/html/progress.test.js +0 -313
  135. package/src/html/property.example.js.backup +0 -553
  136. package/src/html/property.test.js +0 -371
  137. package/src/html/radio.example.js.backup +0 -389
  138. package/src/html/radio.test.js +0 -318
  139. package/src/html/section.example.js.backup +0 -99
  140. package/src/html/section.test.js +0 -131
  141. package/src/html/selector.test.js +0 -20
  142. package/src/html/switch.example.js.backup +0 -461
  143. package/src/html/switch.test.js +0 -355
  144. package/src/html/tab.example.js.backup +0 -446
  145. package/src/html/tab.test.js +0 -25
  146. package/src/html/tab_enhanced.test.js +0 -504
  147. package/src/html/table.test.js +0 -70
  148. package/src/html/table2.test.js +0 -582
  149. package/src/html/text.test.js +0 -15
  150. package/src/html/textfield.test.js +0 -51
  151. package/src/html/textfield2.example.js.backup +0 -1370
  152. package/src/html/textfield2.test.js +0 -950
  153. package/src/html/tokenfield.example.js.backup +0 -503
  154. package/src/html/tokenfield.test.js +0 -423
  155. package/src/html/tree.example.js.backup +0 -475
  156. package/src/html/tree.test.js +0 -43
  157. package/src/html/tree_enhanced.test.js +0 -495
  158. package/src/http/token.test.js +0 -50
  159. package/src/incubator/pdfViewer.js +0 -33
  160. package/src/incubator/wizard.test.js +0 -127
  161. package/src/site/site.test.js +0 -230
  162. package/src/site/view.test.js +0 -41
  163. package/src/widgets/calendar/Calendar.test.js +0 -28
  164. package/src/widgets/explorer/Explorer.test.js +0 -121
  165. package/src/widgets/ide/editor.test.js +0 -33
  166. package/src/widgets/kanban/Kanban.test.js +0 -78
  167. package/src/widgets/login/LoginBox.test.js +0 -12
  168. package/src/widgets/login/ResetPasswordBox.test.js +0 -34
  169. package/src/widgets/login/validations.test.js +0 -51
  170. package/src/widgets/planner/Planner.test.js +0 -60
  171. package/src/widgets/upload/Upload.test.js +0 -32
  172. package/table2.test.js +0 -454
@@ -1,950 +0,0 @@
1
- import React from 'react'
2
- import { TextField2, TextArea2, PasswordField2, DropDown2, DateRange2 } from './textfield2'
3
-
4
- // Pruebas unitarias para los componentes TextField2
5
- describe('TextField2 Components', () => {
6
- // Mock de los componentes dependientes
7
- const mockText = jest.fn()
8
- const mockIcon = jest.fn()
9
- const mockSiteContext = {
10
- translate: jest.fn((text) => text),
11
- changeFocus: jest.fn()
12
- }
13
-
14
- beforeEach(() => {
15
- jest.clearAllMocks()
16
-
17
- // Mock del componente Text
18
- jest.doMock('./text', () => ({
19
- Text: mockText
20
- }))
21
-
22
- // Mock del componente Icon
23
- jest.doMock('./icon', () => ({
24
- Icon: mockIcon
25
- }))
26
-
27
- // Mock del SiteContext
28
- jest.doMock('../site/siteContext', () => ({
29
- SiteContext: {
30
- Provider: ({ children }) => children,
31
- Consumer: ({ children }) => children(mockSiteContext)
32
- }
33
- }))
34
-
35
- // Mock de console.warn para las pruebas
36
- jest.spyOn(console, 'warn').mockImplementation(() => {})
37
- })
38
-
39
- afterEach(() => {
40
- console.warn.mockRestore()
41
- })
42
-
43
- describe('TextField2 Component', () => {
44
- test('component exports correctly', () => {
45
- expect(TextField2).toBeDefined()
46
- expect(typeof TextField2).toBe('function')
47
- })
48
-
49
- test('component has correct PropTypes', () => {
50
- expect(TextField2.propTypes).toBeDefined()
51
- expect(TextField2.propTypes.id).toBeDefined()
52
- expect(TextField2.propTypes.type).toBeDefined()
53
- expect(TextField2.propTypes.className).toBeDefined()
54
- expect(TextField2.propTypes.label).toBeDefined()
55
- expect(TextField2.propTypes.labelPosition).toBeDefined()
56
- expect(TextField2.propTypes.placeholder).toBeDefined()
57
- expect(TextField2.propTypes.value).toBeDefined()
58
- expect(TextField2.propTypes.outlined).toBeDefined()
59
- expect(TextField2.propTypes.readOnly).toBeDefined()
60
- expect(TextField2.propTypes.disabled).toBeDefined()
61
- expect(TextField2.propTypes.required).toBeDefined()
62
- expect(TextField2.propTypes.canClear).toBeDefined()
63
- expect(TextField2.propTypes.showPasswordToggle).toBeDefined()
64
- expect(TextField2.propTypes.autoComplete).toBeDefined()
65
- expect(TextField2.propTypes.error).toBeDefined()
66
- expect(TextField2.propTypes.helperText).toBeDefined()
67
- expect(TextField2.propTypes.validation).toBeDefined()
68
- expect(TextField2.propTypes.onChange).toBeDefined()
69
- })
70
-
71
- test('component has correct defaultProps', () => {
72
- expect(TextField2.defaultProps).toBeDefined()
73
- expect(TextField2.defaultProps.type).toBe('text')
74
- expect(TextField2.defaultProps.labelPosition).toBe('top')
75
- expect(TextField2.defaultProps.outlined).toBe(false)
76
- expect(TextField2.defaultProps.readOnly).toBe(false)
77
- expect(TextField2.defaultProps.disabled).toBe(false)
78
- expect(TextField2.defaultProps.required).toBe(false)
79
- expect(TextField2.defaultProps.canClear).toBe(true)
80
- expect(TextField2.defaultProps.showPasswordToggle).toBe(true)
81
- expect(TextField2.defaultProps.autoComplete).toBe('off')
82
- expect(TextField2.defaultProps.debounceMs).toBe(0)
83
- expect(TextField2.defaultProps.className).toBe('')
84
- })
85
-
86
- test('warns when id prop is missing', () => {
87
- const validateId = (id) => {
88
- if (!id) {
89
- console.warn('TextField2 component: id prop is required')
90
- }
91
- }
92
-
93
- validateId(null)
94
- expect(console.warn).toHaveBeenCalledWith('TextField2 component: id prop is required')
95
-
96
- console.warn.mockClear()
97
- validateId('test-id')
98
- expect(console.warn).not.toHaveBeenCalled()
99
- })
100
-
101
- test('validation logic works correctly', () => {
102
- const validateField = (value, validation, required) => {
103
- if (validation && value !== undefined) {
104
- const validationResult = validation(value)
105
- const valid = typeof validationResult === 'boolean' ? validationResult : validationResult.valid
106
- const errorMessage = typeof validationResult === 'object' ? validationResult.message : ''
107
-
108
- return {
109
- isValid: valid,
110
- internalError: valid ? '' : errorMessage || (required && !value ? 'This field is required' : 'Invalid value')
111
- }
112
- } else if (required && !value) {
113
- return {
114
- isValid: false,
115
- internalError: 'This field is required'
116
- }
117
- } else {
118
- return {
119
- isValid: true,
120
- internalError: ''
121
- }
122
- }
123
- }
124
-
125
- // Valid value with validation
126
- const result1 = validateField('test@email.com', (v) => v.includes('@'), false)
127
- expect(result1.isValid).toBe(true)
128
- expect(result1.internalError).toBe('')
129
-
130
- // Invalid value with validation
131
- const result2 = validateField('invalid-email', (v) => v.includes('@'), false)
132
- expect(result2.isValid).toBe(false)
133
- expect(result2.internalError).toBe('Invalid value')
134
-
135
- // Required field empty
136
- const result3 = validateField('', null, true)
137
- expect(result3.isValid).toBe(false)
138
- expect(result3.internalError).toBe('This field is required')
139
-
140
- // Valid required field
141
- const result4 = validateField('value', null, true)
142
- expect(result4.isValid).toBe(true)
143
- expect(result4.internalError).toBe('')
144
-
145
- // Validation with custom error message
146
- const result5 = validateField('short', (v) => ({ valid: v.length >= 6, message: 'Must be at least 6 characters' }), false)
147
- expect(result5.isValid).toBe(false)
148
- expect(result5.internalError).toBe('Must be at least 6 characters')
149
- })
150
-
151
- test('CSS classes generation works correctly', () => {
152
- const generateClasses = (outlined, labelPosition, label, type, isFocused, disabled, readOnly, error, internalError, isValid, className, id) => {
153
- const borderStyle = outlined ? 'textfield2-outlined' : 'textfield2'
154
- const labelStyle = label ? '' : 'no-label'
155
- const labelPositionStyle = labelPosition === 'left' ? 'label-left' : 'label-top'
156
-
157
- return [
158
- 'textfield2',
159
- borderStyle,
160
- labelStyle,
161
- labelPositionStyle,
162
- `textfield2-${type}`,
163
- isFocused && 'focused',
164
- disabled && 'disabled',
165
- readOnly && 'readonly',
166
- error || internalError ? 'error' : '',
167
- !isValid && 'invalid',
168
- className || '',
169
- id
170
- ].filter(Boolean).join(' ')
171
- }
172
-
173
- expect(generateClasses(false, 'top', 'Label', 'text', false, false, false, '', '', true, '', 'test-id'))
174
- .toBe('textfield2 textfield2 label-top textfield2-text test-id')
175
-
176
- expect(generateClasses(true, 'left', '', 'email', true, false, false, '', '', true, 'custom', 'test-id'))
177
- .toBe('textfield2 textfield2-outlined no-label label-left textfield2-email focused custom test-id')
178
-
179
- expect(generateClasses(false, 'top', 'Label', 'password', false, true, false, '', '', true, '', 'test-id'))
180
- .toBe('textfield2 textfield2 label-top textfield2-password disabled test-id')
181
-
182
- expect(generateClasses(false, 'top', 'Label', 'text', false, false, false, 'Error message', '', false, '', 'test-id'))
183
- .toBe('textfield2 textfield2 label-top textfield2-text error invalid test-id')
184
- })
185
-
186
- test('accessibility attributes generation works correctly', () => {
187
- const generateAriaAttributes = (ariaLabel, label, ariaDescribedBy, error, internalError, helperText, id, isValid, required, disabled, readOnly) => {
188
- return {
189
- 'aria-label': ariaLabel || label,
190
- 'aria-describedby': ariaDescribedBy || (error || internalError || helperText ? `${id}-helper` : undefined),
191
- 'aria-invalid': !isValid || !!(error || internalError),
192
- 'aria-required': required,
193
- 'aria-disabled': disabled,
194
- 'aria-readonly': readOnly
195
- }
196
- }
197
-
198
- const basic = generateAriaAttributes(null, 'Test Label', null, '', '', '', 'test-id', true, false, false, false)
199
- expect(basic['aria-label']).toBe('Test Label')
200
- expect(basic['aria-describedby']).toBeUndefined()
201
- expect(basic['aria-invalid']).toBe(false)
202
- expect(basic['aria-required']).toBe(false)
203
- expect(basic['aria-disabled']).toBe(false)
204
- expect(basic['aria-readonly']).toBe(false)
205
-
206
- const withError = generateAriaAttributes(null, 'Test Label', null, 'Error message', '', '', 'test-id', false, true, false, false)
207
- expect(withError['aria-describedby']).toBe('test-id-helper')
208
- expect(withError['aria-invalid']).toBe(true)
209
- expect(withError['aria-required']).toBe(true)
210
-
211
- const disabled = generateAriaAttributes(null, 'Test Label', null, '', '', '', 'test-id', true, false, true, true)
212
- expect(disabled['aria-disabled']).toBe(true)
213
- expect(disabled['aria-readonly']).toBe(true)
214
- })
215
-
216
- test('input attributes generation works correctly', () => {
217
- const generateInputAttributes = (id, type, isPasswordVisible, placeholder, value, required, disabled, readOnly, maxLength, minLength, pattern, step, min, max, autoComplete, ariaAttributes, restProps) => {
218
- return {
219
- id,
220
- type: type === 'password' && isPasswordVisible ? 'text' : type,
221
- placeholder,
222
- value: value || '',
223
- required,
224
- disabled,
225
- readOnly,
226
- maxLength,
227
- minLength,
228
- pattern,
229
- step,
230
- min,
231
- max,
232
- autoComplete,
233
- ...ariaAttributes,
234
- ...restProps
235
- }
236
- }
237
-
238
- const basic = generateInputAttributes('test-id', 'text', false, 'Enter text', 'value', false, false, false, null, null, null, null, null, null, 'off', {}, {})
239
- expect(basic.id).toBe('test-id')
240
- expect(basic.type).toBe('text')
241
- expect(basic.placeholder).toBe('Enter text')
242
- expect(basic.value).toBe('value')
243
-
244
- const password = generateInputAttributes('pwd-id', 'password', true, 'Enter password', 'secret', true, false, false, null, null, null, null, null, null, 'off', {}, {})
245
- expect(password.type).toBe('text') // Password visible
246
- expect(password.required).toBe(true)
247
-
248
- const passwordHidden = generateInputAttributes('pwd-id', 'password', false, 'Enter password', 'secret', true, false, false, null, null, null, null, null, null, 'off', {}, {})
249
- expect(passwordHidden.type).toBe('password') // Password hidden
250
- })
251
-
252
- test('debounce logic works correctly', () => {
253
- jest.useFakeTimers()
254
-
255
- const mockOnChange = jest.fn()
256
- let debounceRef = { current: null }
257
-
258
- const simulateDebounce = (debounceMs, id, value, onChange) => {
259
- // Clear previous debounce
260
- if (debounceRef.current) {
261
- clearTimeout(debounceRef.current)
262
- }
263
-
264
- if (debounceMs > 0) {
265
- debounceRef.current = setTimeout(() => {
266
- if (onChange) onChange(id, value, {})
267
- }, debounceMs)
268
- } else {
269
- if (onChange) onChange(id, value, {})
270
- }
271
- }
272
-
273
- // No debounce
274
- simulateDebounce(0, 'test-id', 'value', mockOnChange)
275
- expect(mockOnChange).toHaveBeenCalledWith('test-id', 'value', {})
276
-
277
- mockOnChange.mockClear()
278
-
279
- // With debounce
280
- simulateDebounce(300, 'test-id', 'value1', mockOnChange)
281
- expect(mockOnChange).not.toHaveBeenCalled()
282
-
283
- jest.advanceTimersByTime(300)
284
- expect(mockOnChange).toHaveBeenCalledWith('test-id', 'value1', {})
285
-
286
- mockOnChange.mockClear()
287
-
288
- // Debounce cancellation
289
- simulateDebounce(300, 'test-id', 'value2', mockOnChange)
290
- simulateDebounce(300, 'test-id', 'value3', mockOnChange)
291
-
292
- jest.advanceTimersByTime(300)
293
- expect(mockOnChange).toHaveBeenCalledTimes(1)
294
- expect(mockOnChange).toHaveBeenCalledWith('test-id', 'value3', {})
295
-
296
- jest.useRealTimers()
297
- })
298
-
299
- test('password visibility toggle works correctly', () => {
300
- const togglePassword = (isPasswordVisible) => !isPasswordVisible
301
-
302
- expect(togglePassword(false)).toBe(true)
303
- expect(togglePassword(true)).toBe(false)
304
- })
305
-
306
- test('clear functionality works correctly', () => {
307
- const mockOnChange = jest.fn()
308
-
309
- const simulateClear = (disabled, readOnly, id, onChange) => {
310
- if (disabled || readOnly) return
311
-
312
- if (onChange) onChange(id, '', { target: { value: '' } })
313
- }
314
-
315
- // Normal clear
316
- simulateClear(false, false, 'test-id', mockOnChange)
317
- expect(mockOnChange).toHaveBeenCalledWith('test-id', '', { target: { value: '' } })
318
-
319
- mockOnChange.mockClear()
320
-
321
- // Disabled clear
322
- simulateClear(true, false, 'test-id', mockOnChange)
323
- expect(mockOnChange).not.toHaveBeenCalled()
324
-
325
- // ReadOnly clear
326
- simulateClear(false, true, 'test-id', mockOnChange)
327
- expect(mockOnChange).not.toHaveBeenCalled()
328
- })
329
-
330
- test('focus management works correctly', () => {
331
- const mockSite = {
332
- changeFocus: jest.fn()
333
- }
334
-
335
- const simulateFocus = (disabled, onFocus, site) => {
336
- if (disabled) return
337
-
338
- if (onFocus) onFocus({})
339
-
340
- if (site && site.changeFocus) {
341
- site.changeFocus({
342
- lose: () => {} // setIsFocused(false)
343
- })
344
- }
345
- }
346
-
347
- const mockOnFocus = jest.fn()
348
-
349
- simulateFocus(false, mockOnFocus, mockSite)
350
- expect(mockOnFocus).toHaveBeenCalled()
351
- expect(mockSite.changeFocus).toHaveBeenCalled()
352
-
353
- mockOnFocus.mockClear()
354
- mockSite.changeFocus.mockClear()
355
-
356
- // Disabled focus
357
- simulateFocus(true, mockOnFocus, mockSite)
358
- expect(mockOnFocus).not.toHaveBeenCalled()
359
- expect(mockSite.changeFocus).not.toHaveBeenCalled()
360
- })
361
-
362
- test('error and helper text display logic works correctly', () => {
363
- const getDisplayText = (error, internalError, helperText) => {
364
- const displayError = error || internalError
365
- const displayHelperText = helperText && !displayError
366
-
367
- return {
368
- displayError,
369
- displayHelperText,
370
- showHelper: !!(displayError || displayHelperText)
371
- }
372
- }
373
-
374
- const result1 = getDisplayText('External error', '', 'Helper text')
375
- expect(result1.displayError).toBe('External error')
376
- expect(result1.displayHelperText).toBe(false)
377
- expect(result1.showHelper).toBe(true)
378
-
379
- const result2 = getDisplayText('', 'Internal error', 'Helper text')
380
- expect(result2.displayError).toBe('Internal error')
381
- expect(result2.displayHelperText).toBe(false)
382
- expect(result2.showHelper).toBe(true)
383
-
384
- const result3 = getDisplayText('', '', 'Helper text')
385
- expect(result3.displayError).toBe('')
386
- expect(result3.displayHelperText).toBe(true)
387
- expect(result3.showHelper).toBe(true)
388
-
389
- const result4 = getDisplayText('', '', '')
390
- expect(result4.displayError).toBe('')
391
- expect(result4.displayHelperText).toBe('')
392
- expect(result4.showHelper).toBe(false)
393
- })
394
- })
395
-
396
- describe('TextArea2 Component', () => {
397
- test('component exports correctly', () => {
398
- expect(TextArea2).toBeDefined()
399
- expect(typeof TextArea2).toBe('function')
400
- })
401
-
402
- test('component has correct PropTypes', () => {
403
- expect(TextArea2.propTypes).toBeDefined()
404
- // Should inherit from TextField2
405
- expect(TextArea2.propTypes.id).toBeDefined()
406
- expect(TextArea2.propTypes.rows).toBeDefined()
407
- })
408
-
409
- test('component has correct defaultProps', () => {
410
- expect(TextArea2.defaultProps).toBeDefined()
411
- expect(TextArea2.defaultProps.type).toBe('textarea')
412
- })
413
- })
414
-
415
- describe('PasswordField2 Component', () => {
416
- test('component exports correctly', () => {
417
- expect(PasswordField2).toBeDefined()
418
- expect(typeof PasswordField2).toBe('function')
419
- })
420
-
421
- test('component has correct PropTypes', () => {
422
- expect(PasswordField2.propTypes).toBeDefined()
423
- // Should inherit from TextField2
424
- expect(PasswordField2.propTypes.id).toBeDefined()
425
- expect(PasswordField2.propTypes.showPasswordToggle).toBeDefined()
426
- })
427
-
428
- test('component has correct defaultProps', () => {
429
- expect(PasswordField2.defaultProps).toBeDefined()
430
- expect(PasswordField2.defaultProps.type).toBe('password')
431
- })
432
- })
433
-
434
- describe('DropDown2 Component', () => {
435
- test('component exports correctly', () => {
436
- expect(DropDown2).toBeDefined()
437
- expect(typeof DropDown2).toBe('function')
438
- })
439
-
440
- test('component has correct PropTypes', () => {
441
- expect(DropDown2.propTypes).toBeDefined()
442
- expect(DropDown2.propTypes.id).toBeDefined()
443
- expect(DropDown2.propTypes.options).toBeDefined()
444
- expect(DropDown2.propTypes.value).toBeDefined()
445
- expect(DropDown2.propTypes.placeholder).toBeDefined()
446
- expect(DropDown2.propTypes.label).toBeDefined()
447
- expect(DropDown2.propTypes.outlined).toBeDefined()
448
- expect(DropDown2.propTypes.disabled).toBeDefined()
449
- expect(DropDown2.propTypes.readOnly).toBeDefined()
450
- expect(DropDown2.propTypes.required).toBeDefined()
451
- expect(DropDown2.propTypes.searchable).toBeDefined()
452
- expect(DropDown2.propTypes.clearable).toBeDefined()
453
- expect(DropDown2.propTypes.multiple).toBeDefined()
454
- expect(DropDown2.propTypes.onChange).toBeDefined()
455
- })
456
-
457
- test('component has correct defaultProps', () => {
458
- expect(DropDown2.defaultProps).toBeDefined()
459
- expect(DropDown2.defaultProps.options).toEqual([])
460
- expect(DropDown2.defaultProps.outlined).toBe(false)
461
- expect(DropDown2.defaultProps.disabled).toBe(false)
462
- expect(DropDown2.defaultProps.readOnly).toBe(false)
463
- expect(DropDown2.defaultProps.required).toBe(false)
464
- expect(DropDown2.defaultProps.searchable).toBe(false)
465
- expect(DropDown2.defaultProps.clearable).toBe(false)
466
- expect(DropDown2.defaultProps.multiple).toBe(false)
467
- expect(DropDown2.defaultProps.position).toBe('bottom')
468
- expect(DropDown2.defaultProps.maxHeight).toBe('200px')
469
- expect(DropDown2.defaultProps.className).toBe('')
470
- })
471
-
472
- test('warns when id prop is missing', () => {
473
- const validateId = (id) => {
474
- if (!id) {
475
- console.warn('DropDown2 component: id prop is required')
476
- }
477
- }
478
-
479
- validateId(null)
480
- expect(console.warn).toHaveBeenCalledWith('DropDown2 component: id prop is required')
481
-
482
- console.warn.mockClear()
483
- validateId('test-id')
484
- expect(console.warn).not.toHaveBeenCalled()
485
- })
486
-
487
- test('warns when options is not an array', () => {
488
- const validateOptions = (options) => {
489
- if (!Array.isArray(options)) {
490
- console.warn('DropDown2 component: options must be an array')
491
- }
492
- }
493
-
494
- validateOptions('not an array')
495
- expect(console.warn).toHaveBeenCalledWith('DropDown2 component: options must be an array')
496
-
497
- console.warn.mockClear()
498
- validateOptions([])
499
- expect(console.warn).not.toHaveBeenCalled()
500
- })
501
-
502
- test('display value generation works correctly', () => {
503
- const options = [
504
- { value: 'option1', label: 'Option 1' },
505
- { value: 'option2', label: 'Option 2' },
506
- { value: 'option3', label: 'Option 3' }
507
- ]
508
-
509
- const getDisplayValue = (value, multiple, options, renderValue) => {
510
- if (!value) return ''
511
-
512
- if (multiple && Array.isArray(value)) {
513
- if (value.length === 0) return ''
514
- if (value.length === 1) {
515
- const option = options.find(opt => opt.value === value[0])
516
- return option ? option.label : value[0]
517
- }
518
- return `${value.length} items selected`
519
- }
520
-
521
- const option = options.find(opt => opt.value === value)
522
- if (renderValue && option) {
523
- return renderValue(option)
524
- }
525
- return option ? option.label : value
526
- }
527
-
528
- // Single selection
529
- expect(getDisplayValue('option1', false, options)).toBe('Option 1')
530
- expect(getDisplayValue('unknown', false, options)).toBe('unknown')
531
- expect(getDisplayValue('', false, options)).toBe('')
532
-
533
- // Multiple selection
534
- expect(getDisplayValue([], true, options)).toBe('')
535
- expect(getDisplayValue(['option1'], true, options)).toBe('Option 1')
536
- expect(getDisplayValue(['option1', 'option2'], true, options)).toBe('2 items selected')
537
-
538
- // Custom render
539
- const customRender = (option) => `Custom: ${option.label}`
540
- expect(getDisplayValue('option1', false, options, customRender)).toBe('Custom: Option 1')
541
- })
542
-
543
- test('option filtering works correctly', () => {
544
- const options = [
545
- { value: 'apple', label: 'Apple' },
546
- { value: 'banana', label: 'Banana' },
547
- { value: 'cherry', label: 'Cherry' }
548
- ]
549
-
550
- const filterOptions = (options, searchTerm, searchable, filterFunction) => {
551
- if (!searchTerm || !searchable) return options
552
-
553
- if (filterFunction) {
554
- return options.filter(option => filterFunction(option, searchTerm))
555
- }
556
-
557
- return options.filter(option =>
558
- option.label.toLowerCase().includes(searchTerm.toLowerCase())
559
- )
560
- }
561
-
562
- // No search
563
- expect(filterOptions(options, 'app', false)).toEqual(options)
564
- expect(filterOptions(options, '', true)).toEqual(options)
565
-
566
- // Default filtering
567
- expect(filterOptions(options, 'app', true)).toEqual([{ value: 'apple', label: 'Apple' }])
568
- expect(filterOptions(options, 'an', true)).toEqual([{ value: 'banana', label: 'Banana' }])
569
-
570
- // Custom filtering
571
- const customFilter = (option, term) => option.value.startsWith(term)
572
- expect(filterOptions(options, 'a', true, customFilter)).toEqual([{ value: 'apple', label: 'Apple' }])
573
- })
574
-
575
- test('option grouping works correctly', () => {
576
- const options = [
577
- { value: 'apple', label: 'Apple', category: 'Fruits' },
578
- { value: 'banana', label: 'Banana', category: 'Fruits' },
579
- { value: 'carrot', label: 'Carrot', category: 'Vegetables' }
580
- ]
581
-
582
- const groupOptions = (options, groupBy) => {
583
- if (!groupBy) return [{ options }]
584
-
585
- const groups = options.reduce((acc, option) => {
586
- const groupKey = typeof groupBy === 'function' ? groupBy(option) : option[groupBy]
587
- if (!acc[groupKey]) {
588
- acc[groupKey] = []
589
- }
590
- acc[groupKey].push(option)
591
- return acc
592
- }, {})
593
-
594
- return Object.entries(groups).map(([label, options]) => ({ label, options }))
595
- }
596
-
597
- // No grouping
598
- expect(groupOptions(options)).toEqual([{ options }])
599
-
600
- // Group by property
601
- const grouped = groupOptions(options, 'category')
602
- expect(grouped).toHaveLength(2)
603
- expect(grouped[0].label).toBe('Fruits')
604
- expect(grouped[0].options).toHaveLength(2)
605
- expect(grouped[1].label).toBe('Vegetables')
606
- expect(grouped[1].options).toHaveLength(1)
607
-
608
- // Group by function
609
- const groupByFirstLetter = (option) => option.label[0]
610
- const groupedByLetter = groupOptions(options, groupByFirstLetter)
611
- expect(groupedByLetter).toHaveLength(3) // A, B, C
612
- })
613
-
614
- test('selection logic works correctly', () => {
615
- const handleSelection = (selectedValue, multiple, currentValue) => {
616
- if (multiple) {
617
- const currentValues = Array.isArray(currentValue) ? currentValue : []
618
- if (currentValues.includes(selectedValue)) {
619
- return currentValues.filter(v => v !== selectedValue)
620
- } else {
621
- return [...currentValues, selectedValue]
622
- }
623
- } else {
624
- return selectedValue
625
- }
626
- }
627
-
628
- // Single selection
629
- expect(handleSelection('option1', false, '')).toBe('option1')
630
- expect(handleSelection('option2', false, 'option1')).toBe('option2')
631
-
632
- // Multiple selection - add
633
- expect(handleSelection('option1', true, [])).toEqual(['option1'])
634
- expect(handleSelection('option2', true, ['option1'])).toEqual(['option1', 'option2'])
635
-
636
- // Multiple selection - remove
637
- expect(handleSelection('option1', true, ['option1', 'option2'])).toEqual(['option2'])
638
- })
639
-
640
- test('keyboard navigation logic works correctly', () => {
641
- const handleKeyNavigation = (key, isOpen, focusedIndex, optionsLength) => {
642
- switch (key) {
643
- case 'ArrowDown':
644
- if (!isOpen) {
645
- return { isOpen: true, focusedIndex: -1 }
646
- } else {
647
- return {
648
- isOpen: true,
649
- focusedIndex: focusedIndex < optionsLength - 1 ? focusedIndex + 1 : 0
650
- }
651
- }
652
- case 'ArrowUp':
653
- if (isOpen) {
654
- return {
655
- isOpen: true,
656
- focusedIndex: focusedIndex > 0 ? focusedIndex - 1 : optionsLength - 1
657
- }
658
- }
659
- return { isOpen, focusedIndex }
660
- case 'Escape':
661
- return { isOpen: false, focusedIndex: -1 }
662
- default:
663
- return { isOpen, focusedIndex }
664
- }
665
- }
666
-
667
- // Arrow down when closed
668
- expect(handleKeyNavigation('ArrowDown', false, -1, 3)).toEqual({ isOpen: true, focusedIndex: -1 })
669
-
670
- // Arrow down when open
671
- expect(handleKeyNavigation('ArrowDown', true, -1, 3)).toEqual({ isOpen: true, focusedIndex: 0 })
672
- expect(handleKeyNavigation('ArrowDown', true, 0, 3)).toEqual({ isOpen: true, focusedIndex: 1 })
673
- expect(handleKeyNavigation('ArrowDown', true, 2, 3)).toEqual({ isOpen: true, focusedIndex: 0 }) // Wrap around
674
-
675
- // Arrow up
676
- expect(handleKeyNavigation('ArrowUp', true, 1, 3)).toEqual({ isOpen: true, focusedIndex: 0 })
677
- expect(handleKeyNavigation('ArrowUp', true, 0, 3)).toEqual({ isOpen: true, focusedIndex: 2 }) // Wrap around
678
-
679
- // Escape
680
- expect(handleKeyNavigation('Escape', true, 1, 3)).toEqual({ isOpen: false, focusedIndex: -1 })
681
- })
682
-
683
- test('CSS classes generation works correctly', () => {
684
- const generateClasses = (outlined, disabled, readOnly, isOpen, error, internalError, multiple, className) => {
685
- return [
686
- 'dropdown2',
687
- outlined && 'outlined',
688
- disabled && 'disabled',
689
- readOnly && 'readonly',
690
- isOpen && 'open',
691
- error || internalError ? 'error' : '',
692
- multiple && 'multiple',
693
- className || ''
694
- ].filter(Boolean).join(' ')
695
- }
696
-
697
- expect(generateClasses(false, false, false, false, '', '', false, '')).toBe('dropdown2')
698
- expect(generateClasses(true, false, false, false, '', '', false, '')).toBe('dropdown2 outlined')
699
- expect(generateClasses(false, true, false, false, '', '', false, '')).toBe('dropdown2 disabled')
700
- expect(generateClasses(false, false, true, false, '', '', false, '')).toBe('dropdown2 readonly')
701
- expect(generateClasses(false, false, false, true, '', '', false, '')).toBe('dropdown2 open')
702
- expect(generateClasses(false, false, false, false, 'Error', '', false, '')).toBe('dropdown2 error')
703
- expect(generateClasses(false, false, false, false, '', '', true, '')).toBe('dropdown2 multiple')
704
- expect(generateClasses(false, false, false, false, '', '', false, 'custom')).toBe('dropdown2 custom')
705
- })
706
-
707
- test('accessibility attributes generation works correctly', () => {
708
- const generateAriaAttributes = (ariaLabel, label, isOpen, disabled, readOnly, required, error, internalError, helperText, id) => {
709
- return {
710
- 'aria-label': ariaLabel || label,
711
- 'aria-expanded': isOpen,
712
- 'aria-haspopup': 'listbox',
713
- 'aria-disabled': disabled,
714
- 'aria-readonly': readOnly,
715
- 'aria-required': required,
716
- 'aria-invalid': !!(error || internalError),
717
- 'aria-describedby': error || internalError || helperText ? `${id}-helper` : undefined
718
- }
719
- }
720
-
721
- const basic = generateAriaAttributes(null, 'Test Label', false, false, false, false, '', '', '', 'test-id')
722
- expect(basic['aria-label']).toBe('Test Label')
723
- expect(basic['aria-expanded']).toBe(false)
724
- expect(basic['aria-haspopup']).toBe('listbox')
725
- expect(basic['aria-disabled']).toBe(false)
726
- expect(basic['aria-readonly']).toBe(false)
727
- expect(basic['aria-required']).toBe(false)
728
- expect(basic['aria-invalid']).toBe(false)
729
- expect(basic['aria-describedby']).toBeUndefined()
730
-
731
- const withError = generateAriaAttributes(null, 'Test Label', true, false, false, true, 'Error message', '', '', 'test-id')
732
- expect(withError['aria-expanded']).toBe(true)
733
- expect(withError['aria-required']).toBe(true)
734
- expect(withError['aria-invalid']).toBe(true)
735
- expect(withError['aria-describedby']).toBe('test-id-helper')
736
- })
737
- })
738
-
739
- describe('DateRange2 Component', () => {
740
- test('component exports correctly', () => {
741
- expect(DateRange2).toBeDefined()
742
- expect(typeof DateRange2).toBe('function')
743
- })
744
-
745
- test('component has correct PropTypes', () => {
746
- expect(DateRange2.propTypes).toBeDefined()
747
- expect(DateRange2.propTypes.id).toBeDefined()
748
- expect(DateRange2.propTypes.label).toBeDefined()
749
- expect(DateRange2.propTypes.value).toBeDefined()
750
- expect(DateRange2.propTypes.outlined).toBeDefined()
751
- expect(DateRange2.propTypes.disabled).toBeDefined()
752
- expect(DateRange2.propTypes.readOnly).toBeDefined()
753
- expect(DateRange2.propTypes.required).toBeDefined()
754
- expect(DateRange2.propTypes.minDate).toBeDefined()
755
- expect(DateRange2.propTypes.maxDate).toBeDefined()
756
- expect(DateRange2.propTypes.error).toBeDefined()
757
- expect(DateRange2.propTypes.helperText).toBeDefined()
758
- expect(DateRange2.propTypes.onChange).toBeDefined()
759
- expect(DateRange2.propTypes.onValidation).toBeDefined()
760
- })
761
-
762
- test('component has correct defaultProps', () => {
763
- expect(DateRange2.defaultProps).toBeDefined()
764
- expect(DateRange2.defaultProps.outlined).toBe(false)
765
- expect(DateRange2.defaultProps.disabled).toBe(false)
766
- expect(DateRange2.defaultProps.readOnly).toBe(false)
767
- expect(DateRange2.defaultProps.required).toBe(false)
768
- expect(DateRange2.defaultProps.className).toBe('')
769
- })
770
-
771
- test('warns when id prop is missing', () => {
772
- const validateId = (id) => {
773
- if (!id) {
774
- console.warn('DateRange2 component: id prop is required')
775
- }
776
- }
777
-
778
- validateId(null)
779
- expect(console.warn).toHaveBeenCalledWith('DateRange2 component: id prop is required')
780
-
781
- console.warn.mockClear()
782
- validateId('test-id')
783
- expect(console.warn).not.toHaveBeenCalled()
784
- })
785
-
786
- test('form initialization from value works correctly', () => {
787
- const initializeForm = (value) => {
788
- if (value && typeof value === 'object') {
789
- return {
790
- from: value.from || '',
791
- to: value.to || ''
792
- }
793
- }
794
- return { from: '', to: '' }
795
- }
796
-
797
- expect(initializeForm(null)).toEqual({ from: '', to: '' })
798
- expect(initializeForm({})).toEqual({ from: '', to: '' })
799
- expect(initializeForm({ from: '2023-01-01' })).toEqual({ from: '2023-01-01', to: '' })
800
- expect(initializeForm({ from: '2023-01-01', to: '2023-12-31' })).toEqual({ from: '2023-01-01', to: '2023-12-31' })
801
- })
802
-
803
- test('date range validation works correctly', () => {
804
- const validateDateRange = (form, required, minDate, maxDate) => {
805
- let valid = true
806
- let errorMessage = ''
807
-
808
- if (required && (!form.from || !form.to)) {
809
- valid = false
810
- errorMessage = 'Both dates are required'
811
- } else if (form.from && form.to) {
812
- const fromDate = new Date(form.from)
813
- const toDate = new Date(form.to)
814
-
815
- if (fromDate > toDate) {
816
- valid = false
817
- errorMessage = 'From date must be before To date'
818
- } else if (minDate && fromDate < new Date(minDate)) {
819
- valid = false
820
- errorMessage = `From date must be after ${minDate}`
821
- } else if (maxDate && toDate > new Date(maxDate)) {
822
- valid = false
823
- errorMessage = `To date must be before ${maxDate}`
824
- }
825
- }
826
-
827
- return { valid, errorMessage }
828
- }
829
-
830
- // Valid range
831
- const result1 = validateDateRange({ from: '2023-01-01', to: '2023-12-31' }, false, null, null)
832
- expect(result1.valid).toBe(true)
833
- expect(result1.errorMessage).toBe('')
834
-
835
- // Required but empty
836
- const result2 = validateDateRange({ from: '', to: '' }, true, null, null)
837
- expect(result2.valid).toBe(false)
838
- expect(result2.errorMessage).toBe('Both dates are required')
839
-
840
- // From after To
841
- const result3 = validateDateRange({ from: '2023-12-31', to: '2023-01-01' }, false, null, null)
842
- expect(result3.valid).toBe(false)
843
- expect(result3.errorMessage).toBe('From date must be before To date')
844
-
845
- // Before min date
846
- const result4 = validateDateRange({ from: '2022-01-01', to: '2023-12-31' }, false, '2023-01-01', null)
847
- expect(result4.valid).toBe(false)
848
- expect(result4.errorMessage).toBe('From date must be after 2023-01-01')
849
-
850
- // After max date
851
- const result5 = validateDateRange({ from: '2023-01-01', to: '2024-12-31' }, false, null, '2024-01-01')
852
- expect(result5.valid).toBe(false)
853
- expect(result5.errorMessage).toBe('To date must be before 2024-01-01')
854
- })
855
-
856
- test('form change handling works correctly', () => {
857
- const handleFormChange = (prevForm, fieldId, fieldValue) => {
858
- return {
859
- ...prevForm,
860
- [fieldId]: fieldValue
861
- }
862
- }
863
-
864
- const initialForm = { from: '', to: '' }
865
-
866
- const result1 = handleFormChange(initialForm, 'from', '2023-01-01')
867
- expect(result1).toEqual({ from: '2023-01-01', to: '' })
868
-
869
- const result2 = handleFormChange(result1, 'to', '2023-12-31')
870
- expect(result2).toEqual({ from: '2023-01-01', to: '2023-12-31' })
871
- })
872
-
873
- test('CSS classes generation works correctly', () => {
874
- const generateClasses = (outlined, disabled, readOnly, error, internalError, isValid, className) => {
875
- return [
876
- 'date-range2',
877
- outlined && 'outlined',
878
- disabled && 'disabled',
879
- readOnly && 'readonly',
880
- error || internalError ? 'error' : '',
881
- !isValid && 'invalid',
882
- className || ''
883
- ].filter(Boolean).join(' ')
884
- }
885
-
886
- expect(generateClasses(false, false, false, '', '', true, '')).toBe('date-range2')
887
- expect(generateClasses(true, false, false, '', '', true, '')).toBe('date-range2 outlined')
888
- expect(generateClasses(false, true, false, '', '', true, '')).toBe('date-range2 disabled')
889
- expect(generateClasses(false, false, true, '', '', true, '')).toBe('date-range2 readonly')
890
- expect(generateClasses(false, false, false, 'Error', '', true, '')).toBe('date-range2 error')
891
- expect(generateClasses(false, false, false, '', '', false, '')).toBe('date-range2 invalid')
892
- expect(generateClasses(false, false, false, '', '', true, 'custom')).toBe('date-range2 custom')
893
- })
894
-
895
- test('accessibility attributes generation works correctly', () => {
896
- const generateAriaAttributes = (ariaLabel, label, isValid, error, internalError, required, disabled, readOnly, helperText, id) => {
897
- return {
898
- 'aria-label': ariaLabel || label,
899
- 'aria-invalid': !isValid || !!(error || internalError),
900
- 'aria-required': required,
901
- 'aria-disabled': disabled,
902
- 'aria-readonly': readOnly,
903
- 'aria-describedby': error || internalError || helperText ? `${id}-helper` : undefined
904
- }
905
- }
906
-
907
- const basic = generateAriaAttributes(null, 'Date Range', true, '', '', false, false, false, '', 'test-id')
908
- expect(basic['aria-label']).toBe('Date Range')
909
- expect(basic['aria-invalid']).toBe(false)
910
- expect(basic['aria-required']).toBe(false)
911
- expect(basic['aria-disabled']).toBe(false)
912
- expect(basic['aria-readonly']).toBe(false)
913
- expect(basic['aria-describedby']).toBeUndefined()
914
-
915
- const withError = generateAriaAttributes(null, 'Date Range', false, 'Error message', '', true, false, false, '', 'test-id')
916
- expect(withError['aria-invalid']).toBe(true)
917
- expect(withError['aria-required']).toBe(true)
918
- expect(withError['aria-describedby']).toBe('test-id-helper')
919
- })
920
-
921
- test('min/max date constraints work correctly', () => {
922
- const getDateConstraints = (form, minDate, maxDate) => {
923
- return {
924
- fromMin: minDate,
925
- fromMax: form.to || maxDate,
926
- toMin: form.from || minDate,
927
- toMax: maxDate
928
- }
929
- }
930
-
931
- const form1 = { from: '', to: '' }
932
- const constraints1 = getDateConstraints(form1, '2023-01-01', '2023-12-31')
933
- expect(constraints1).toEqual({
934
- fromMin: '2023-01-01',
935
- fromMax: '2023-12-31',
936
- toMin: '2023-01-01',
937
- toMax: '2023-12-31'
938
- })
939
-
940
- const form2 = { from: '2023-06-01', to: '2023-09-01' }
941
- const constraints2 = getDateConstraints(form2, '2023-01-01', '2023-12-31')
942
- expect(constraints2).toEqual({
943
- fromMin: '2023-01-01',
944
- fromMax: '2023-09-01',
945
- toMin: '2023-06-01',
946
- toMax: '2023-12-31'
947
- })
948
- })
949
- })
950
- })