13
13
import { act , fireEvent , pointerMap , render , within } from '@react-spectrum/test-utils-internal' ;
14
14
import { Button , CalendarCell , CalendarGrid , CalendarGridBody , CalendarGridHeader , CalendarHeaderCell , Heading , RangeCalendar , RangeCalendarContext } from 'react-aria-components' ;
15
15
import { CalendarDate , getLocalTimeZone , startOfMonth , startOfWeek , today } from '@internationalized/date' ;
16
+ import { DateValue } from '@react-types/calendar' ;
17
+ import { RangeValue } from '@react-types/shared' ;
16
18
import React from 'react' ;
17
19
import userEvent from '@testing-library/user-event' ;
18
20
19
- let TestCalendar = ( { calendarProps, gridProps, cellProps} ) => (
21
+ let TestCalendar = ( { calendarProps = { } , gridProps = { } , cellProps = { } } ) => (
20
22
< RangeCalendar aria-label = "Trip dates" { ...calendarProps } >
21
23
< header >
22
24
< Button slot = "previous" > ◀</ Button >
@@ -29,7 +31,7 @@ let TestCalendar = ({calendarProps, gridProps, cellProps}) => (
29
31
</ RangeCalendar >
30
32
) ;
31
33
32
- let renderCalendar = ( calendarProps , gridProps , cellProps ) => render ( < TestCalendar { ...{ calendarProps, gridProps, cellProps} } /> ) ;
34
+ let renderCalendar = ( calendarProps = { } , gridProps = { } , cellProps = { } ) => render ( < TestCalendar { ...{ calendarProps, gridProps, cellProps} } /> ) ;
33
35
34
36
describe ( 'RangeCalendar' , ( ) => {
35
37
let user ;
@@ -282,6 +284,72 @@ describe('RangeCalendar', () => {
282
284
expect ( cells [ 8 ] ) . not . toHaveClass ( 'end' ) ;
283
285
} ) ;
284
286
287
+ it ( 'should support controlled selected range states' , async ( ) => {
288
+ function ControlledCalendar ( ) {
289
+ let [ value , setValue ] = React . useState < RangeValue < DateValue > | null > ( null ) ;
290
+
291
+ return (
292
+ < >
293
+ < RangeCalendar aria-label = "Trip dates" value = { value } onChange = { setValue } >
294
+ < header >
295
+ < Button slot = "previous" > ◀</ Button >
296
+ < Heading />
297
+ < Button slot = "next" > ▶</ Button >
298
+ </ header >
299
+ < CalendarGrid >
300
+ { ( date ) => < CalendarCell date = { date } className = { ( { isSelectionStart, isSelectionEnd} ) => `${ isSelectionStart ? 'start' : '' } ${ isSelectionEnd ? 'end' : '' } ` } /> }
301
+ </ CalendarGrid >
302
+ </ RangeCalendar >
303
+ < Button onPress = { ( ) => setValue ( null ) } > Reset</ Button >
304
+ </ >
305
+ ) ;
306
+ }
307
+ let { getByRole} = render (
308
+ < ControlledCalendar />
309
+ ) ;
310
+
311
+ let resetBtn = getByRole ( 'button' , { name : 'Reset' } ) ;
312
+ let grid = getByRole ( 'grid' ) ;
313
+ let cells = within ( grid ) . getAllByRole ( 'button' ) ;
314
+
315
+ expect ( cells [ 7 ] ) . not . toHaveAttribute ( 'data-selection-start' ) ;
316
+ expect ( cells [ 7 ] ) . not . toHaveClass ( 'start' ) ;
317
+ expect ( cells [ 7 ] ) . not . toHaveClass ( 'end' ) ;
318
+
319
+ await user . click ( cells [ 7 ] ) ;
320
+ expect ( cells [ 7 ] ) . toHaveAttribute ( 'data-selection-start' , 'true' ) ;
321
+ expect ( cells [ 7 ] ) . toHaveClass ( 'start' ) ;
322
+ expect ( cells [ 7 ] ) . toHaveAttribute ( 'data-selection-end' , 'true' ) ;
323
+ expect ( cells [ 7 ] ) . toHaveClass ( 'end' ) ;
324
+
325
+ expect ( cells [ 8 ] ) . not . toHaveAttribute ( 'data-selection-start' , 'true' ) ;
326
+ expect ( cells [ 8 ] ) . not . toHaveClass ( 'start' ) ;
327
+ expect ( cells [ 8 ] ) . not . toHaveAttribute ( 'data-selection-end' , 'true' ) ;
328
+ expect ( cells [ 8 ] ) . not . toHaveClass ( 'end' ) ;
329
+
330
+ await user . click ( cells [ 10 ] ) ;
331
+ expect ( cells [ 7 ] ) . toHaveAttribute ( 'data-selection-start' , 'true' ) ;
332
+ expect ( cells [ 7 ] ) . toHaveClass ( 'start' ) ;
333
+ expect ( cells [ 7 ] ) . not . toHaveAttribute ( 'data-selection-end' , 'true' ) ;
334
+ expect ( cells [ 7 ] ) . not . toHaveClass ( 'end' ) ;
335
+ expect ( cells [ 10 ] ) . toHaveAttribute ( 'data-selection-end' , 'true' ) ;
336
+ expect ( cells [ 10 ] ) . toHaveClass ( 'end' ) ;
337
+
338
+ expect ( cells [ 8 ] ) . not . toHaveAttribute ( 'data-selection-start' , 'true' ) ;
339
+ expect ( cells [ 8 ] ) . not . toHaveClass ( 'start' ) ;
340
+ expect ( cells [ 8 ] ) . not . toHaveAttribute ( 'data-selection-end' , 'true' ) ;
341
+ expect ( cells [ 8 ] ) . not . toHaveClass ( 'end' ) ;
342
+
343
+ await user . click ( resetBtn ) ;
344
+
345
+ expect ( cells [ 7 ] ) . not . toHaveAttribute ( 'data-selection-start' ) ;
346
+ expect ( cells [ 7 ] ) . not . toHaveClass ( 'start' ) ;
347
+ expect ( cells [ 7 ] ) . not . toHaveClass ( 'end' ) ;
348
+ expect ( cells [ 10 ] ) . not . toHaveAttribute ( 'data-selection-end' ) ;
349
+ expect ( cells [ 10 ] ) . not . toHaveClass ( 'end' ) ;
350
+
351
+ } ) ;
352
+
285
353
it ( 'should support unavailable state' , ( ) => {
286
354
let { getByRole} = renderCalendar ( { isDateUnavailable : ( ) => true } , { } , { className : ( { isUnavailable} ) => isUnavailable ? 'unavailable' : '' } ) ;
287
355
let grid = getByRole ( 'grid' ) ;
0 commit comments