@@ -40,6 +40,7 @@ const generateDays = (count = Calendar.DAY_COUNT) => {
4040 key = { date . toISOString ( ) }
4141 date = { date . toISOString ( ) }
4242 label = { date . toISOString ( ) }
43+ selectedLabel = "Selected"
4344 isOutsideMonth = { date . getMonth ( ) !== 7 }
4445 >
4546 { date . getDate ( ) }
@@ -71,14 +72,14 @@ describe('<Calendar />', () => {
7172
7273 describe ( 'with minimal config' , ( ) => {
7374 it ( 'should render 44 buttons without config' , async ( ) => {
74- render ( < Calendar /> )
75+ render ( < Calendar selectedLabel = "Selected" /> )
7576 const buttons = document . getElementsByTagName ( 'button' )
7677
7778 expect ( buttons . length ) . toEqual ( 44 )
7879 } )
7980
8081 it ( 'should render proper week names by default' , async ( ) => {
81- const { container } = render ( < Calendar /> )
82+ const { container } = render ( < Calendar selectedLabel = "Selected" /> )
8283 const thead = container . querySelector ( 'thead' )
8384
8485 expect ( thead ) . toHaveTextContent (
@@ -87,7 +88,9 @@ describe('<Calendar />', () => {
8788 } )
8889
8990 it ( 'should render proper week names if locale is set' , async ( ) => {
90- const { container } = render ( < Calendar locale = "hu" /> )
91+ const { container } = render (
92+ < Calendar locale = "hu" selectedLabel = "Selected" />
93+ )
9194 const thead = container . querySelector ( 'thead' )
9295
9396 expect ( thead ) . toHaveTextContent (
@@ -100,6 +103,7 @@ describe('<Calendar />', () => {
100103 < Calendar
101104 currentDate = "2023-12-15"
102105 disabledDates = { [ '2023-12-22' , '2023-12-12' , '2023-12-11' ] }
106+ selectedLabel = "Selected"
103107 />
104108 )
105109 const buttons = container . querySelectorAll ( 'button[disabled]' )
@@ -115,23 +119,29 @@ describe('<Calendar />', () => {
115119 } )
116120
117121 it ( 'should indicate selected day' , async ( ) => {
118- render ( < Calendar currentDate = "2023-12-15" selectedDate = "2023-12-22" /> )
122+ render (
123+ < Calendar
124+ currentDate = "2023-12-15"
125+ selectedDate = "2023-12-22"
126+ selectedLabel = "Selected"
127+ />
128+ )
119129
120- const selectedDay =
121- screen . queryByText ( '22 December 2023' ) ?. parentElement ?. parentElement
130+ const selectedDay = screen . queryByText ( '22 December 2023, Selected' )
131+ ?. parentElement ?. parentElement
122132
123133 expect ( selectedDay ) . toBeDefined ( )
124- if ( selectedDay ) {
125- expect ( window . getComputedStyle ( selectedDay ) ?. background ) . toBe (
126- 'rgb(3, 137, 61)'
127- )
128- }
134+ expect ( window . getComputedStyle ( selectedDay ! ) . background ) . toBe (
135+ 'rgb(3, 137, 61)'
136+ )
129137 } )
130138 } )
131139
132140 it ( 'should render children' , async ( ) => {
133141 const { container } = render (
134- < Calendar renderWeekdayLabels = { weekdayLabels } > { generateDays ( ) } </ Calendar >
142+ < Calendar renderWeekdayLabels = { weekdayLabels } selectedLabel = "Selected" >
143+ { generateDays ( ) }
144+ </ Calendar >
135145 )
136146
137147 const calendarDays = container . querySelectorAll (
@@ -145,7 +155,7 @@ describe('<Calendar />', () => {
145155 const count = Calendar . DAY_COUNT - 1
146156
147157 render (
148- < Calendar renderWeekdayLabels = { weekdayLabels } >
158+ < Calendar renderWeekdayLabels = { weekdayLabels } selectedLabel = "Selected" >
149159 { generateDays ( count ) }
150160 </ Calendar >
151161 )
@@ -160,7 +170,9 @@ describe('<Calendar />', () => {
160170
161171 it ( 'should render weekday labels' , async ( ) => {
162172 const { container, rerender } = render (
163- < Calendar renderWeekdayLabels = { weekdayLabels } > { generateDays ( ) } </ Calendar >
173+ < Calendar renderWeekdayLabels = { weekdayLabels } selectedLabel = "Selected" >
174+ { generateDays ( ) }
175+ </ Calendar >
164176 )
165177
166178 const originalHeaders = container . querySelectorAll ( 'th' )
@@ -182,7 +194,10 @@ describe('<Calendar />', () => {
182194
183195 // Set prop: renderWeekdayLabels
184196 rerender (
185- < Calendar renderWeekdayLabels = { functionalWeekdayLabels } >
197+ < Calendar
198+ renderWeekdayLabels = { functionalWeekdayLabels }
199+ selectedLabel = "Selected"
200+ >
186201 { generateDays ( ) }
187202 </ Calendar >
188203 )
@@ -196,7 +211,11 @@ describe('<Calendar />', () => {
196211 } )
197212
198213 it ( 'should warn if 7 weekday labels are not provided' , async ( ) => {
199- render ( < Calendar renderWeekdayLabels = { [ ] } > { generateDays ( ) } </ Calendar > )
214+ render (
215+ < Calendar renderWeekdayLabels = { [ ] } selectedLabel = "Selected" >
216+ { generateDays ( ) }
217+ </ Calendar >
218+ )
200219
201220 const expectedErrorMessage =
202221 '`renderWeekdayLabels` should be an array with 7 labels (one for each weekday). 0 provided.'
@@ -209,7 +228,9 @@ describe('<Calendar />', () => {
209228
210229 it ( 'should format the weekday labels and days correctly' , async ( ) => {
211230 const { container } = render (
212- < Calendar renderWeekdayLabels = { weekdayLabels } > { generateDays ( ) } </ Calendar >
231+ < Calendar renderWeekdayLabels = { weekdayLabels } selectedLabel = "Selected" >
232+ { generateDays ( ) }
233+ </ Calendar >
213234 )
214235
215236 const headerRow = container . querySelectorAll ( 'thead > tr' )
@@ -239,6 +260,7 @@ describe('<Calendar />', () => {
239260 < Calendar
240261 renderWeekdayLabels = { weekdayLabels }
241262 renderNavigationLabel = { navLabel }
263+ selectedLabel = "Selected"
242264 >
243265 { generateDays ( ) }
244266 </ Calendar >
@@ -254,6 +276,7 @@ describe('<Calendar />', () => {
254276 < Calendar
255277 renderWeekdayLabels = { weekdayLabels }
256278 renderNavigationLabel = { ( ) => navLabel }
279+ selectedLabel = "Selected"
257280 >
258281 { generateDays ( ) }
259282 </ Calendar >
@@ -267,7 +290,9 @@ describe('<Calendar />', () => {
267290
268291 it ( 'should render next and prev buttons' , async ( ) => {
269292 const { rerender } = render (
270- < Calendar renderWeekdayLabels = { weekdayLabels } > { generateDays ( ) } </ Calendar >
293+ < Calendar renderWeekdayLabels = { weekdayLabels } selectedLabel = "Selected" >
294+ { generateDays ( ) }
295+ </ Calendar >
271296 )
272297 const defaultPrevButton = screen . getByText ( 'Previous month' )
273298 const defaultNextButton = screen . getByText ( 'Next month' )
@@ -280,6 +305,7 @@ describe('<Calendar />', () => {
280305 renderWeekdayLabels = { weekdayLabels }
281306 renderPrevMonthButton = { < button > test-prev</ button > }
282307 renderNextMonthButton = { < button > test-next</ button > }
308+ selectedLabel = "Selected"
283309 >
284310 { generateDays ( ) }
285311 </ Calendar >
@@ -295,6 +321,7 @@ describe('<Calendar />', () => {
295321 renderWeekdayLabels = { weekdayLabels }
296322 renderPrevMonthButton = { ( ) => < button > func-test-prev</ button > }
297323 renderNextMonthButton = { ( ) => < button > func-test-next</ button > }
324+ selectedLabel = "Selected"
298325 >
299326 { generateDays ( ) }
300327 </ Calendar >
@@ -317,6 +344,7 @@ describe('<Calendar />', () => {
317344 renderNextMonthButton = { < button > next month</ button > }
318345 onRequestRenderPrevMonth = { onRequestRenderPrevMonth }
319346 onRequestRenderNextMonth = { onRequestRenderNextMonth }
347+ selectedLabel = "Selected"
320348 >
321349 { generateDays ( ) }
322350 </ Calendar >
@@ -340,7 +368,11 @@ describe('<Calendar />', () => {
340368 describe ( 'when role="listbox"' , ( ) => {
341369 it ( 'should set role="listbox" on table root and role="presentation" on the correct elements' , async ( ) => {
342370 const { container } = render (
343- < Calendar renderWeekdayLabels = { weekdayLabels } role = "listbox" >
371+ < Calendar
372+ renderWeekdayLabels = { weekdayLabels }
373+ role = "listbox"
374+ selectedLabel = "Selected"
375+ >
344376 { generateDays ( ) }
345377 </ Calendar >
346378 )
@@ -361,7 +393,11 @@ describe('<Calendar />', () => {
361393
362394 it ( "should link each day with it's weekday header via `aria-describedby`" , async ( ) => {
363395 const { container } = render (
364- < Calendar renderWeekdayLabels = { weekdayLabels } role = "listbox" >
396+ < Calendar
397+ renderWeekdayLabels = { weekdayLabels }
398+ role = "listbox"
399+ selectedLabel = "Selected"
400+ >
365401 { generateDays ( ) }
366402 </ Calendar >
367403 )
@@ -379,11 +415,119 @@ describe('<Calendar />', () => {
379415 )
380416 } )
381417 } )
418+
419+ it ( 'should set role="option" and aria-selected on each day' , async ( ) => {
420+ const { container } = render (
421+ < Calendar
422+ renderWeekdayLabels = { weekdayLabels }
423+ role = "listbox"
424+ currentDate = "2019-08-01"
425+ selectedDate = "2019-08-02"
426+ selectedLabel = "Selected"
427+ >
428+ { generateDays ( ) }
429+ </ Calendar >
430+ )
431+
432+ const days = container . querySelectorAll ( 'tbody [data-cid="Calendar.Day"]' )
433+ expect ( days . length ) . toBe ( Calendar . DAY_COUNT )
434+ days . forEach ( ( day ) => {
435+ expect ( day ) . toHaveAttribute ( 'role' , 'option' )
436+ expect ( day ) . toHaveAttribute ( 'aria-selected' )
437+ } )
438+ } )
439+
440+ it ( 'should announce selected state via accessible label when selectedLabel is provided' , async ( ) => {
441+ const { container } = render (
442+ < Calendar
443+ renderWeekdayLabels = { weekdayLabels }
444+ role = "listbox"
445+ currentDate = "2019-08-01"
446+ selectedDate = "2019-08-02"
447+ selectedLabel = "selected"
448+ />
449+ )
450+
451+ const days = container . querySelectorAll ( 'tbody [data-cid="Calendar.Day"]' )
452+
453+ // Check that the selected day's accessible label includes "selected"
454+ const selectedDay = Array . from ( days ) . find ( ( day ) => {
455+ const screenReaderContent = day . querySelector (
456+ '[class*="-screenReaderContent"]'
457+ )
458+ return screenReaderContent ?. textContent ?. includes ( 'selected' )
459+ } )
460+ expect ( selectedDay ) . toBeDefined ( )
461+
462+ // Unselected days should not have "selected" in their label
463+ const unselectedDays = Array . from ( days ) . filter ( ( day ) => {
464+ const screenReaderContent = day . querySelector (
465+ '[class*="-screenReaderContent"]'
466+ )
467+ return ! screenReaderContent ?. textContent ?. includes ( 'selected' )
468+ } )
469+ expect ( unselectedDays . length ) . toBe ( Calendar . DAY_COUNT - 1 )
470+ } )
471+ } )
472+
473+ describe ( 'when role="table" (default)' , ( ) => {
474+ it ( 'should set role="button" on each day and not set aria-selected' , async ( ) => {
475+ const { container } = render (
476+ < Calendar
477+ renderWeekdayLabels = { weekdayLabels }
478+ currentDate = "2019-08-01"
479+ selectedDate = "2019-08-02"
480+ selectedLabel = "Selected"
481+ />
482+ )
483+
484+ const days = container . querySelectorAll ( 'tbody [data-cid="Calendar.Day"]' )
485+ expect ( days . length ) . toBe ( Calendar . DAY_COUNT )
486+ days . forEach ( ( day ) => {
487+ expect ( day ) . toHaveAttribute ( 'role' , 'button' )
488+ expect ( day ) . not . toHaveAttribute ( 'aria-selected' )
489+ } )
490+ } )
491+
492+ it ( 'should announce selected state via accessible label when selectedLabel is provided' , async ( ) => {
493+ const { container } = render (
494+ < Calendar
495+ renderWeekdayLabels = { weekdayLabels }
496+ currentDate = "2019-08-01"
497+ selectedDate = "2019-08-02"
498+ selectedLabel = "selected"
499+ />
500+ )
501+
502+ const days = container . querySelectorAll ( 'tbody [data-cid="Calendar.Day"]' )
503+
504+ // Check that the selected day's accessible label includes "selected"
505+ const selectedDay = Array . from ( days ) . find ( ( day ) => {
506+ const screenReaderContent = day . querySelector (
507+ '[class*="-screenReaderContent"]'
508+ )
509+ return screenReaderContent ?. textContent ?. includes ( 'selected' )
510+ } )
511+ expect ( selectedDay ) . toBeDefined ( )
512+
513+ // Unselected days should not have "selected" in their label
514+ const unselectedDays = Array . from ( days ) . filter ( ( day ) => {
515+ const screenReaderContent = day . querySelector (
516+ '[class*="-screenReaderContent"]'
517+ )
518+ return ! screenReaderContent ?. textContent ?. includes ( 'selected' )
519+ } )
520+ expect ( unselectedDays . length ) . toBe ( Calendar . DAY_COUNT - 1 )
521+ } )
382522 } )
383523
384524 it ( 'should render root as designated by the `as` prop' , async ( ) => {
385525 render (
386- < Calendar renderWeekdayLabels = { weekdayLabels } as = "ul" >
526+ < Calendar
527+ renderWeekdayLabels = { weekdayLabels }
528+ as = "ul"
529+ selectedLabel = "Selected"
530+ >
387531 { generateDays ( ) }
388532 </ Calendar >
389533 )
0 commit comments