@coreui/react-pro 5.24.0 → 5.25.0

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 (180) hide show
  1. package/README.md +1 -1
  2. package/dist/cjs/components/calendar/CCalendar.js +4 -3
  3. package/dist/cjs/components/calendar/CCalendar.js.map +1 -1
  4. package/dist/cjs/components/date-picker/CDatePicker.d.ts +1 -1
  5. package/dist/cjs/components/date-picker/CDatePicker.js.map +1 -1
  6. package/dist/cjs/components/date-range-picker/CDateRangePicker.js +2 -0
  7. package/dist/cjs/components/date-range-picker/CDateRangePicker.js.map +1 -1
  8. package/dist/cjs/components/dropdown/CDropdown.js +1 -1
  9. package/dist/cjs/components/dropdown/CDropdown.js.map +1 -1
  10. package/dist/cjs/components/index.d.ts +1 -0
  11. package/dist/cjs/components/nav/CNavGroup.d.ts +3 -1
  12. package/dist/cjs/components/nav/CNavGroup.js +9 -5
  13. package/dist/cjs/components/nav/CNavGroup.js.map +1 -1
  14. package/dist/cjs/components/one-time-password-input/COneTimePassword.js +3 -3
  15. package/dist/cjs/components/one-time-password-input/COneTimePassword.js.map +1 -1
  16. package/dist/cjs/components/popover/CPopover.js +14 -17
  17. package/dist/cjs/components/popover/CPopover.js.map +1 -1
  18. package/dist/cjs/components/search-button/CSearchButton.d.ts +32 -0
  19. package/dist/cjs/components/search-button/CSearchButton.js +77 -0
  20. package/dist/cjs/components/search-button/CSearchButton.js.map +1 -0
  21. package/dist/cjs/components/search-button/index.d.ts +2 -0
  22. package/dist/cjs/components/search-button/types.d.ts +10 -0
  23. package/dist/cjs/components/search-button/utils.d.ts +11 -0
  24. package/dist/cjs/components/search-button/utils.js +115 -0
  25. package/dist/cjs/components/search-button/utils.js.map +1 -0
  26. package/dist/cjs/components/sidebar/CSidebarNav.d.ts +12 -0
  27. package/dist/cjs/components/sidebar/CSidebarNav.js +7 -2
  28. package/dist/cjs/components/sidebar/CSidebarNav.js.map +1 -1
  29. package/dist/cjs/components/smart-table/CSmartTable.js +2 -2
  30. package/dist/cjs/components/smart-table/CSmartTable.js.map +1 -1
  31. package/dist/cjs/components/smart-table/CSmartTableInterface.d.ts +2 -2
  32. package/dist/cjs/components/time-picker/CTimePicker.d.ts +1 -1
  33. package/dist/cjs/components/time-picker/CTimePicker.js +1 -1
  34. package/dist/cjs/components/time-picker/CTimePicker.js.map +1 -1
  35. package/dist/cjs/components/tooltip/CTooltip.js +14 -17
  36. package/dist/cjs/components/tooltip/CTooltip.js.map +1 -1
  37. package/dist/cjs/components/virtual-scroller/CVirtualScroller.js +11 -8
  38. package/dist/cjs/components/virtual-scroller/CVirtualScroller.js.map +1 -1
  39. package/dist/cjs/hooks/useDebouncedCallback.d.ts +1 -1
  40. package/dist/cjs/hooks/useDebouncedCallback.js +1 -1
  41. package/dist/cjs/hooks/useDebouncedCallback.js.map +1 -1
  42. package/dist/cjs/index.js +2 -0
  43. package/dist/cjs/index.js.map +1 -1
  44. package/dist/cjs/node_modules/@coreui/icons/dist/esm/free/cil-arrow-bottom.js +1 -1
  45. package/dist/cjs/node_modules/@coreui/icons/dist/esm/free/cil-arrow-bottom.js.map +1 -1
  46. package/dist/cjs/node_modules/@coreui/icons/dist/esm/free/cil-arrow-top.js +1 -1
  47. package/dist/cjs/node_modules/@coreui/icons/dist/esm/free/cil-arrow-top.js.map +1 -1
  48. package/dist/cjs/node_modules/@coreui/icons/dist/esm/free/cil-filter-x.js +1 -1
  49. package/dist/cjs/node_modules/@coreui/icons/dist/esm/free/cil-filter-x.js.map +1 -1
  50. package/dist/cjs/node_modules/@coreui/icons/dist/esm/free/cil-swap-vertical.js +1 -1
  51. package/dist/cjs/node_modules/@coreui/icons/dist/esm/free/cil-swap-vertical.js.map +1 -1
  52. package/dist/cjs/node_modules/ua-parser-js/dist/ua-parser.min.js +2 -2
  53. package/dist/cjs/node_modules/ua-parser-js/dist/ua-parser.min.js.map +1 -1
  54. package/dist/esm/components/calendar/CCalendar.js +4 -3
  55. package/dist/esm/components/calendar/CCalendar.js.map +1 -1
  56. package/dist/esm/components/date-picker/CDatePicker.d.ts +1 -1
  57. package/dist/esm/components/date-picker/CDatePicker.js.map +1 -1
  58. package/dist/esm/components/date-range-picker/CDateRangePicker.js +2 -0
  59. package/dist/esm/components/date-range-picker/CDateRangePicker.js.map +1 -1
  60. package/dist/esm/components/dropdown/CDropdown.js +1 -1
  61. package/dist/esm/components/dropdown/CDropdown.js.map +1 -1
  62. package/dist/esm/components/index.d.ts +1 -0
  63. package/dist/esm/components/nav/CNavGroup.d.ts +3 -1
  64. package/dist/esm/components/nav/CNavGroup.js +9 -5
  65. package/dist/esm/components/nav/CNavGroup.js.map +1 -1
  66. package/dist/esm/components/one-time-password-input/COneTimePassword.js +3 -3
  67. package/dist/esm/components/one-time-password-input/COneTimePassword.js.map +1 -1
  68. package/dist/esm/components/popover/CPopover.js +14 -17
  69. package/dist/esm/components/popover/CPopover.js.map +1 -1
  70. package/dist/esm/components/search-button/CSearchButton.d.ts +32 -0
  71. package/dist/esm/components/search-button/CSearchButton.js +75 -0
  72. package/dist/esm/components/search-button/CSearchButton.js.map +1 -0
  73. package/dist/esm/components/search-button/index.d.ts +2 -0
  74. package/dist/esm/components/search-button/types.d.ts +10 -0
  75. package/dist/esm/components/search-button/utils.d.ts +11 -0
  76. package/dist/esm/components/search-button/utils.js +104 -0
  77. package/dist/esm/components/search-button/utils.js.map +1 -0
  78. package/dist/esm/components/sidebar/CSidebarNav.d.ts +12 -0
  79. package/dist/esm/components/sidebar/CSidebarNav.js +7 -2
  80. package/dist/esm/components/sidebar/CSidebarNav.js.map +1 -1
  81. package/dist/esm/components/smart-table/CSmartTable.js +2 -2
  82. package/dist/esm/components/smart-table/CSmartTable.js.map +1 -1
  83. package/dist/esm/components/smart-table/CSmartTableInterface.d.ts +2 -2
  84. package/dist/esm/components/time-picker/CTimePicker.d.ts +1 -1
  85. package/dist/esm/components/time-picker/CTimePicker.js +1 -1
  86. package/dist/esm/components/time-picker/CTimePicker.js.map +1 -1
  87. package/dist/esm/components/tooltip/CTooltip.js +14 -17
  88. package/dist/esm/components/tooltip/CTooltip.js.map +1 -1
  89. package/dist/esm/components/virtual-scroller/CVirtualScroller.js +11 -8
  90. package/dist/esm/components/virtual-scroller/CVirtualScroller.js.map +1 -1
  91. package/dist/esm/hooks/useDebouncedCallback.d.ts +1 -1
  92. package/dist/esm/hooks/useDebouncedCallback.js +1 -1
  93. package/dist/esm/hooks/useDebouncedCallback.js.map +1 -1
  94. package/dist/esm/index.js +1 -0
  95. package/dist/esm/index.js.map +1 -1
  96. package/dist/esm/node_modules/@coreui/icons/dist/esm/free/cil-arrow-bottom.js +1 -1
  97. package/dist/esm/node_modules/@coreui/icons/dist/esm/free/cil-arrow-bottom.js.map +1 -1
  98. package/dist/esm/node_modules/@coreui/icons/dist/esm/free/cil-arrow-top.js +1 -1
  99. package/dist/esm/node_modules/@coreui/icons/dist/esm/free/cil-arrow-top.js.map +1 -1
  100. package/dist/esm/node_modules/@coreui/icons/dist/esm/free/cil-filter-x.js +1 -1
  101. package/dist/esm/node_modules/@coreui/icons/dist/esm/free/cil-filter-x.js.map +1 -1
  102. package/dist/esm/node_modules/@coreui/icons/dist/esm/free/cil-swap-vertical.js +1 -1
  103. package/dist/esm/node_modules/@coreui/icons/dist/esm/free/cil-swap-vertical.js.map +1 -1
  104. package/dist/esm/node_modules/ua-parser-js/dist/ua-parser.min.js +2 -2
  105. package/dist/esm/node_modules/ua-parser-js/dist/ua-parser.min.js.map +1 -1
  106. package/package.json +7 -5
  107. package/src/components/autocomplete/__tests__/CAutocomplete.spec.tsx +18 -16
  108. package/src/components/autocomplete/__tests__/CAutocompleteOptions.spec.tsx +37 -28
  109. package/src/components/autocomplete/__tests__/__snapshots__/CAutocomplete.spec.tsx.snap +129 -0
  110. package/src/components/autocomplete/__tests__/__snapshots__/CAutocompleteOptions.spec.tsx.snap +36 -0
  111. package/src/components/calendar/CCalendar.tsx +5 -4
  112. package/src/components/calendar/__tests__/CCalendar.spec.tsx +40 -45
  113. package/src/components/calendar/__tests__/__snapshots__/CCalendar.spec.tsx.snap +99 -75
  114. package/src/components/calendar/__tests__/utils.spec.tsx +8 -18
  115. package/src/components/date-picker/CDatePicker.tsx +12 -13
  116. package/src/components/date-picker/__tests__/CDatePicker.spec.tsx +1 -1
  117. package/src/components/date-picker/__tests__/__snapshots__/CDatePicker.spec.tsx.snap +12 -640
  118. package/src/components/date-range-picker/CDateRangePicker.tsx +2 -0
  119. package/src/components/date-range-picker/__tests__/CDateRangePicker.spec.tsx +1 -1
  120. package/src/components/date-range-picker/__tests__/__snapshots__/CDateRangePicker.spec.tsx.snap +21 -1259
  121. package/src/components/dropdown/CDropdown.tsx +1 -1
  122. package/src/components/dropdown/__tests__/CDropdown.spec.tsx +1 -1
  123. package/src/components/dropdown/__tests__/__snapshots__/CDropdown.spec.tsx.snap +2 -2
  124. package/src/components/dropdown/__tests__/__snapshots__/CDropdownMenu.spec.tsx.snap +1 -1
  125. package/src/components/form/__tests__/CFormInput.spec.tsx +17 -20
  126. package/src/components/form/__tests__/__snapshots__/CFormInput.spec.tsx.snap +12 -3
  127. package/src/components/index.ts +1 -0
  128. package/src/components/loading-button/__tests__/CLoadingButton.spec.tsx +1 -1
  129. package/src/components/loading-button/__tests__/__snapshots__/CLoadingButton.spec.tsx.snap +4 -4
  130. package/src/components/multi-select/__tests__/CMultiSelect.spec.tsx +15 -61
  131. package/src/components/multi-select/__tests__/CMultiSelectNativeSelect.spec.tsx +4 -5
  132. package/src/components/multi-select/__tests__/CMultiSelectOptions.spec.tsx +4 -4
  133. package/src/components/multi-select/__tests__/CMultiSelectSelection.spec.tsx +7 -24
  134. package/src/components/multi-select/__tests__/__snapshots__/CMultiSelect.spec.tsx.snap +50 -20
  135. package/src/components/multi-select/__tests__/__snapshots__/CMultiSelectNativeSelect.spec.tsx.snap +0 -2
  136. package/src/components/multi-select/__tests__/__snapshots__/CMultiSelectOptions.spec.tsx.snap +6 -0
  137. package/src/components/multi-select/__tests__/__snapshots__/CMultiSelectSelection.spec.tsx.snap +11 -8
  138. package/src/components/nav/CNavGroup.tsx +11 -6
  139. package/src/components/nav/__tests__/CNavGroup.spec.tsx +29 -1
  140. package/src/components/nav/__tests__/__snapshots__/CNavGroup.spec.tsx.snap +1 -1
  141. package/src/components/offcanvas/__tests__/COffcanvas.spec.tsx +1 -0
  142. package/src/components/one-time-password-input/COneTimePassword.tsx +10 -11
  143. package/src/components/picker/__tests__/CPicker.spec.tsx +1 -1
  144. package/src/components/picker/__tests__/__snapshots__/CPicker.spec.tsx.snap +2 -16
  145. package/src/components/popover/CPopover.tsx +15 -20
  146. package/src/components/popover/__tests__/CPopover.spec.tsx +10 -4
  147. package/src/components/search-button/CSearchButton.tsx +195 -0
  148. package/src/components/search-button/__tests__/CSearchButton.spec.tsx +95 -0
  149. package/src/components/search-button/__tests__/__snapshots__/CSearchButton.spec.tsx.snap +87 -0
  150. package/src/components/search-button/index.ts +3 -0
  151. package/src/components/search-button/types.ts +10 -0
  152. package/src/components/search-button/utils.ts +140 -0
  153. package/src/components/sidebar/CSidebarNav.tsx +27 -2
  154. package/src/components/smart-table/CSmartTable.tsx +5 -4
  155. package/src/components/smart-table/CSmartTableInterface.tsx +2 -2
  156. package/src/components/smart-table/__tests__/CSmartTable.spec.tsx +3 -2
  157. package/src/components/smart-table/__tests__/__snapshots__/CSmartTable.spec.tsx.snap +7 -15
  158. package/src/components/stepper/__tests__/CStepper.spec.tsx +24 -21
  159. package/src/components/stepper/__tests__/__snapshots__/CStepper.spec.tsx.snap +295 -0
  160. package/src/components/tabs/__tests__/CTabContent.spec.tsx +1 -0
  161. package/src/components/tabs/__tests__/CTabPane.spec.tsx +1 -0
  162. package/src/components/time-picker/CTimePicker.tsx +6 -7
  163. package/src/components/time-picker/__tests__/CTimePicker.spec.tsx +10 -1
  164. package/src/components/time-picker/__tests__/__snapshots__/CTimePicker.spec.tsx.snap +599 -315
  165. package/src/components/tooltip/CTooltip.tsx +15 -20
  166. package/src/components/tooltip/__tests__/CTooltip.spec.tsx +6 -0
  167. package/src/components/virtual-scroller/CVirtualScroller.tsx +13 -14
  168. package/src/hooks/useDebouncedCallback.ts +7 -4
  169. package/dist/cjs/components/accordion/CAccordionCollapse.d.ts +0 -3
  170. package/dist/esm/components/accordion/CAccordionCollapse.d.ts +0 -3
  171. package/src/components/accordion/CAccordionCollapse.tsx +0 -20
  172. package/src/components/accordion/__tests__/CAccordionCollapse.spec.tsx +0 -10
  173. package/src/components/accordion/__tests__/__snapshots__/CAccordionCollapse.spec.tsx.snap +0 -11
  174. package/src/components/button/__tests__/__snapshots__/CButtonClose.spec.tsx.snap +0 -26
  175. package/src/components/calendar/__tests__/CCalendar.accessibility.spec.tsx +0 -595
  176. package/src/components/calendar/__tests__/CCalendar.comprehensive.spec.tsx +0 -402
  177. package/src/components/calendar/__tests__/CCalendar.edge-cases.spec.tsx +0 -416
  178. package/src/components/calendar/__tests__/CCalendar.interactions.spec.tsx +0 -593
  179. package/src/components/header/CHeaderBrand.tsx~HEAD +0 -36
  180. /package/src/components/calendar/__tests__/{test-setup.ts → setup.ts} +0 -0
@@ -1,416 +0,0 @@
1
- import * as React from 'react'
2
- import { render, screen, fireEvent, act, waitFor } from '@testing-library/react'
3
- import userEvent from '@testing-library/user-event'
4
- import '@testing-library/jest-dom'
5
- import { CCalendar } from '../CCalendar'
6
-
7
- describe('CCalendar Edge Cases', () => {
8
- beforeEach(() => {
9
- jest.clearAllMocks()
10
- })
11
-
12
- describe('Memory Management', () => {
13
- it('cleans up event listeners on unmount', () => {
14
- const addEventListenerSpy = jest.spyOn(document, 'addEventListener')
15
- const removeEventListenerSpy = jest.spyOn(document, 'removeEventListener')
16
-
17
- const { unmount } = render(<CCalendar />)
18
-
19
- // Unmount the component
20
- unmount()
21
-
22
- // Verify cleanup (this is implementation dependent)
23
- expect(removeEventListenerSpy).toHaveBeenCalled()
24
-
25
- addEventListenerSpy.mockRestore()
26
- removeEventListenerSpy.mockRestore()
27
- })
28
-
29
- it('handles rapid prop changes without memory leaks', () => {
30
- const { rerender } = render(<CCalendar calendarDate="1/1/2022" />)
31
-
32
- // Rapidly change props
33
- for (let i = 1; i <= 31; i++) {
34
- rerender(<CCalendar calendarDate={`1/${i}/2022`} />)
35
- }
36
-
37
- expect(screen.getByRole('application')).toBeInTheDocument()
38
- })
39
-
40
- it('handles component re-mounting', () => {
41
- const { unmount, rerender } = render(<CCalendar calendarDate="1/1/2022" />)
42
-
43
- unmount()
44
-
45
- rerender(<CCalendar calendarDate="1/2/2022" />)
46
- expect(screen.getByRole('application')).toBeInTheDocument()
47
- })
48
- })
49
-
50
- describe('Extreme Date Values', () => {
51
- it('handles dates near JavaScript Date limits', () => {
52
- // JavaScript Date can handle dates from -8,640,000,000,000,000 to 8,640,000,000,000,000 milliseconds
53
- // relative to January 1, 1970 UTC
54
-
55
- // Very old date (but within JavaScript limits)
56
- render(<CCalendar calendarDate="1/1/1970" />)
57
- expect(screen.getByRole('application')).toBeInTheDocument()
58
-
59
- // Very future date (but within JavaScript limits)
60
- render(<CCalendar calendarDate="1/1/2030" />)
61
- expect(screen.getByRole('application')).toBeInTheDocument()
62
- })
63
-
64
- it('handles invalid date objects gracefully', () => {
65
- const invalidDate = new Date('invalid')
66
- render(<CCalendar calendarDate={invalidDate} />)
67
- expect(screen.getByRole('application')).toBeInTheDocument()
68
- })
69
-
70
- it('handles NaN dates gracefully', () => {
71
- const nanDate = new Date(NaN)
72
- render(<CCalendar calendarDate={nanDate} />)
73
- expect(screen.getByRole('application')).toBeInTheDocument()
74
- })
75
- })
76
-
77
- describe('Browser Compatibility', () => {
78
- it('handles browsers without Intl support', () => {
79
- const originalIntl = global.Intl
80
-
81
- // Mock missing Intl support
82
- Object.defineProperty(global, 'Intl', {
83
- value: undefined,
84
- writable: true
85
- })
86
-
87
- render(<CCalendar locale="en-US" />)
88
- expect(screen.getByRole('application')).toBeInTheDocument()
89
-
90
- // Restore Intl
91
- global.Intl = originalIntl
92
- })
93
-
94
- it('handles browsers with limited Date support', () => {
95
- // Mock limited Date parsing
96
- const originalDateParse = Date.parse
97
- Date.parse = jest.fn(() => NaN)
98
-
99
- render(<CCalendar calendarDate="2/16/2022" />)
100
- expect(screen.getByRole('application')).toBeInTheDocument()
101
-
102
- // Restore Date.parse
103
- Date.parse = originalDateParse
104
- })
105
-
106
- it('handles touch events', async () => {
107
- render(<CCalendar />)
108
-
109
- const calendar = screen.getByRole('application')
110
-
111
- // Simulate touch events
112
- fireEvent.touchStart(calendar, {
113
- touches: [{ clientX: 100, clientY: 100 }]
114
- })
115
-
116
- fireEvent.touchEnd(calendar, {
117
- changedTouches: [{ clientX: 100, clientY: 100 }]
118
- })
119
-
120
- expect(calendar).toBeInTheDocument()
121
- })
122
- })
123
-
124
- describe('Error Recovery', () => {
125
- it('recovers from invalid prop combinations', () => {
126
- // Start date after end date
127
- render(
128
- <CCalendar
129
- range
130
- startDate="2/20/2022"
131
- endDate="2/16/2022"
132
- />
133
- )
134
- expect(screen.getByRole('application')).toBeInTheDocument()
135
- })
136
-
137
- it('handles conflicting date constraints', () => {
138
- // Min date after max date
139
- render(
140
- <CCalendar
141
- minDate="2/20/2022"
142
- maxDate="2/16/2022"
143
- />
144
- )
145
- expect(screen.getByRole('application')).toBeInTheDocument()
146
- })
147
-
148
- it('handles disabled date that is also selected', () => {
149
- const selectedDate = new Date(2022, 1, 16)
150
- render(
151
- <CCalendar
152
- calendarDate={selectedDate}
153
- disabledDate={[selectedDate]}
154
- />
155
- )
156
- expect(screen.getByRole('application')).toBeInTheDocument()
157
- })
158
-
159
- it('recovers from callback errors', () => {
160
- const errorCallback = jest.fn(() => {
161
- throw new Error('Callback error')
162
- })
163
-
164
- // Component should still render despite callback errors
165
- expect(() => {
166
- render(<CCalendar onCalendarDateChange={errorCallback} />)
167
- }).not.toThrow()
168
-
169
- expect(screen.getByRole('application')).toBeInTheDocument()
170
- })
171
- })
172
-
173
- describe('Performance Edge Cases', () => {
174
- it('handles large number of disabled dates efficiently', () => {
175
- const startTime = performance.now()
176
-
177
- // Create array of 1000 disabled dates
178
- const disabledDates = Array.from({ length: 1000 }, (_, i) =>
179
- new Date(2022, 0, i + 1)
180
- )
181
-
182
- render(<CCalendar disabledDate={disabledDates} />)
183
-
184
- const endTime = performance.now()
185
- const renderTime = endTime - startTime
186
-
187
- expect(screen.getByRole('application')).toBeInTheDocument()
188
- // Should render in reasonable time (less than 1 second)
189
- expect(renderTime).toBeLessThan(1000)
190
- })
191
-
192
- it('handles complex disabled date functions efficiently', () => {
193
- const complexDisabledFn = (date: Date) => {
194
- // Complex calculation to determine if date is disabled
195
- const dayOfYear = Math.floor((date.getTime() - new Date(date.getFullYear(), 0, 0).getTime()) / 86400000)
196
- return dayOfYear % 7 === 0 || dayOfYear % 13 === 0
197
- }
198
-
199
- const startTime = performance.now()
200
- render(<CCalendar disabledDate={complexDisabledFn} />)
201
- const endTime = performance.now()
202
-
203
- expect(screen.getByRole('application')).toBeInTheDocument()
204
- expect(endTime - startTime).toBeLessThan(500)
205
- })
206
-
207
- it('handles rapid state updates', async () => {
208
- const TestComponent = () => {
209
- const [date, setDate] = React.useState<Date | null>(new Date(2022, 1, 16))
210
-
211
- React.useEffect(() => {
212
- // Rapid state updates
213
- const interval = setInterval(() => {
214
- setDate(prev => prev ? new Date(prev.getTime() + 86400000) : null)
215
- }, 10)
216
-
217
- setTimeout(() => clearInterval(interval), 100)
218
-
219
- return () => clearInterval(interval)
220
- }, [])
221
-
222
- return <CCalendar calendarDate={date} />
223
- }
224
-
225
- render(<TestComponent />)
226
-
227
- // Wait for rapid updates to complete
228
- await waitFor(() => {
229
- expect(screen.getByRole('application')).toBeInTheDocument()
230
- }, { timeout: 200 })
231
- })
232
- })
233
-
234
- describe('Accessibility Edge Cases', () => {
235
- it('maintains focus during dynamic updates', async () => {
236
- const { rerender } = render(<CCalendar />)
237
-
238
- const calendar = screen.getByRole('application')
239
- calendar.focus()
240
-
241
- expect(calendar).toHaveFocus()
242
-
243
- // Update props while focused
244
- rerender(<CCalendar calendarDate="2/16/2022" />)
245
-
246
- // Focus should be maintained (implementation dependent)
247
- expect(screen.getByRole('application')).toBeInTheDocument()
248
- })
249
-
250
- it('handles screen reader announcements', () => {
251
- const { rerender } = render(<CCalendar />)
252
-
253
- // Change to different date
254
- rerender(<CCalendar calendarDate="2/16/2022" />)
255
-
256
- // Verify aria-live regions are updated (implementation dependent)
257
- expect(screen.getByRole('application')).toBeInTheDocument()
258
- })
259
-
260
- it('handles high contrast mode', () => {
261
- // Mock high contrast media query
262
- Object.defineProperty(window, 'matchMedia', {
263
- writable: true,
264
- value: jest.fn().mockImplementation(query => ({
265
- matches: query.includes('prefers-contrast: high'),
266
- media: query,
267
- onchange: null,
268
- addListener: jest.fn(),
269
- removeListener: jest.fn(),
270
- addEventListener: jest.fn(),
271
- removeEventListener: jest.fn(),
272
- dispatchEvent: jest.fn(),
273
- })),
274
- })
275
-
276
- render(<CCalendar />)
277
- expect(screen.getByRole('application')).toBeInTheDocument()
278
- })
279
-
280
- it('handles reduced motion preference', () => {
281
- // Mock reduced motion preference
282
- Object.defineProperty(window, 'matchMedia', {
283
- writable: true,
284
- value: jest.fn().mockImplementation(query => ({
285
- matches: query.includes('prefers-reduced-motion: reduce'),
286
- media: query,
287
- onchange: null,
288
- addListener: jest.fn(),
289
- removeListener: jest.fn(),
290
- addEventListener: jest.fn(),
291
- removeEventListener: jest.fn(),
292
- dispatchEvent: jest.fn(),
293
- })),
294
- })
295
-
296
- render(<CCalendar />)
297
- expect(screen.getByRole('application')).toBeInTheDocument()
298
- })
299
- })
300
-
301
- describe('Timezone Edge Cases', () => {
302
- it('handles timezone changes during component lifecycle', () => {
303
- const { rerender } = render(<CCalendar calendarDate="2/16/2022" />)
304
-
305
- // Mock timezone change (this is tricky to test properly)
306
- const originalDateToString = Date.prototype.toString
307
- Date.prototype.toString = function() {
308
- return originalDateToString.call(this).replace(/GMT[+-]\d{4}/, 'GMT+0200')
309
- }
310
-
311
- rerender(<CCalendar calendarDate="2/16/2022" />)
312
- expect(screen.getByRole('application')).toBeInTheDocument()
313
-
314
- // Restore original method
315
- Date.prototype.toString = originalDateToString
316
- })
317
-
318
- it('handles daylight saving time boundaries', () => {
319
- // Test dates around DST transitions
320
- const dstDates = [
321
- '3/11/2023', // Spring forward (US)
322
- '3/12/2023',
323
- '3/13/2023',
324
- '11/4/2023', // Fall back (US)
325
- '11/5/2023',
326
- '11/6/2023'
327
- ]
328
-
329
- dstDates.forEach(dateString => {
330
- const { rerender } = render(<CCalendar calendarDate="1/1/2023" />)
331
- rerender(<CCalendar calendarDate={dateString} />)
332
- expect(screen.getByRole('application')).toBeInTheDocument()
333
- })
334
- })
335
-
336
- it('handles system clock changes', () => {
337
- // Mock system time change
338
- const originalNow = Date.now
339
- let mockTime = new Date('2022-02-16T12:00:00Z').getTime()
340
-
341
- Date.now = jest.fn(() => mockTime)
342
-
343
- render(<CCalendar />)
344
- expect(screen.getByRole('application')).toBeInTheDocument()
345
-
346
- // Simulate time jumping forward
347
- mockTime += 3600000 // +1 hour
348
-
349
- // Force re-render
350
- act(() => {
351
- // Component should handle time changes gracefully
352
- })
353
-
354
- expect(screen.getByRole('application')).toBeInTheDocument()
355
-
356
- // Restore original Date.now
357
- Date.now = originalNow
358
- })
359
- })
360
-
361
- describe('Concurrent Mode Compatibility', () => {
362
- it('handles interrupting updates gracefully', async () => {
363
- const SlowComponent = ({ date }: { date: string }) => {
364
- // Simulate slow rendering
365
- const start = performance.now()
366
- while (performance.now() - start < 5) {
367
- // Busy wait for 5ms
368
- }
369
- return <CCalendar calendarDate={date} />
370
- }
371
-
372
- const { rerender } = render(<SlowComponent date="1/1/2022" />)
373
-
374
- // Rapid updates that might be interrupted
375
- rerender(<SlowComponent date="1/2/2022" />)
376
- rerender(<SlowComponent date="1/3/2022" />)
377
- rerender(<SlowComponent date="1/4/2022" />)
378
-
379
- await waitFor(() => {
380
- expect(screen.getByRole('application')).toBeInTheDocument()
381
- })
382
- })
383
- })
384
-
385
- describe('Security Edge Cases', () => {
386
- it('handles XSS attempts in date strings', () => {
387
- const maliciousDate = '<script>alert("xss")</script>'
388
-
389
- expect(() => {
390
- render(<CCalendar calendarDate={maliciousDate} />)
391
- }).not.toThrow()
392
-
393
- expect(screen.getByRole('application')).toBeInTheDocument()
394
-
395
- // Verify no script tags were rendered
396
- expect(document.querySelector('script')).toBeNull()
397
- })
398
-
399
- it('sanitizes user input in callbacks', () => {
400
- const maliciousCallback = jest.fn((date) => {
401
- // Attempt to access global objects
402
- try {
403
- (window as any).maliciousCode = 'executed'
404
- } catch (e) {
405
- // Expected to be blocked
406
- }
407
- })
408
-
409
- render(<CCalendar onCalendarDateChange={maliciousCallback} />)
410
- expect(screen.getByRole('application')).toBeInTheDocument()
411
-
412
- // Verify malicious code wasn't executed
413
- expect((window as any).maliciousCode).toBeUndefined()
414
- })
415
- })
416
- })