1313 * limitations under the License.
1414 */
1515
16- import { beforeAll , describe , expect , it , vi } from 'vitest' ;
16+ import { beforeEach , describe , expect , it , vi , type Mock } from 'vitest' ;
1717import { createRef } from 'react' ;
1818import MockDate from 'mockdate' ;
1919
2020import { render , screen , axe , userEvent } from '../../util/test-utils.js' ;
21+ import { useMedia } from '../../hooks/useMedia/useMedia.js' ;
2122
2223import { DateInput } from './DateInput.js' ;
2324
25+ vi . mock ( '../../hooks/useMedia/useMedia.js' ) ;
26+
2427describe ( 'DateInput' , ( ) => {
2528 const props = {
2629 onChange : vi . fn ( ) ,
@@ -36,8 +39,9 @@ describe('DateInput', () => {
3639 clearDateButtonLabel : 'Clear date' ,
3740 } ;
3841
39- beforeAll ( ( ) => {
42+ beforeEach ( ( ) => {
4043 MockDate . set ( '2000-01-01' ) ;
44+ ( useMedia as Mock ) . mockReturnValue ( false ) ;
4145 } ) ;
4246
4347 it ( 'should forward a ref' , ( ) => {
@@ -182,32 +186,38 @@ describe('DateInput', () => {
182186 ) ;
183187 } ) ;
184188
185- it . skip ( 'should mark the year input as readonly when the minimum and maximum dates have the same year' , ( ) => {
186- render ( < DateInput { ...props } min = "2000-04-29" max = "2000-06-15" /> ) ;
187- expect ( screen . getByLabelText ( / y e a r / i) ) . toHaveAttribute ( 'readonly' ) ;
188- expect ( screen . getByLabelText ( / m o n t h / i) ) . toHaveAttribute (
189- 'aria-valuemin' ,
190- '4' ,
191- ) ;
192- expect ( screen . getByLabelText ( / m o n t h / i) ) . toHaveAttribute (
193- 'aria-valuemax' ,
194- '6' ,
195- ) ;
196- } ) ;
189+ it . todo (
190+ 'should mark the year input as readonly when the minimum and maximum dates have the same year' ,
191+ ( ) => {
192+ render ( < DateInput { ...props } min = "2000-04-29" max = "2000-06-15" /> ) ;
193+ expect ( screen . getByLabelText ( / y e a r / i) ) . toHaveAttribute ( 'readonly' ) ;
194+ expect ( screen . getByLabelText ( / m o n t h / i) ) . toHaveAttribute (
195+ 'aria-valuemin' ,
196+ '4' ,
197+ ) ;
198+ expect ( screen . getByLabelText ( / m o n t h / i) ) . toHaveAttribute (
199+ 'aria-valuemax' ,
200+ '6' ,
201+ ) ;
202+ } ,
203+ ) ;
197204
198- it . skip ( 'should mark the year and month inputs as readonly when the minimum and maximum dates have the same year and month' , ( ) => {
199- render ( < DateInput { ...props } min = "2000-04-09" max = "2000-04-27" /> ) ;
200- expect ( screen . getByLabelText ( / y e a r / i) ) . toHaveAttribute ( 'readonly' ) ;
201- expect ( screen . getByLabelText ( / m o n t h / i) ) . toHaveAttribute ( 'readonly' ) ;
202- expect ( screen . getByLabelText ( / d a y / i) ) . toHaveAttribute (
203- 'aria-valuemin' ,
204- '9' ,
205- ) ;
206- expect ( screen . getByLabelText ( / d a y / i) ) . toHaveAttribute (
207- 'aria-valuemax' ,
208- '27' ,
209- ) ;
210- } ) ;
205+ it . todo (
206+ 'should mark the year and month inputs as readonly when the minimum and maximum dates have the same year and month' ,
207+ ( ) => {
208+ render ( < DateInput { ...props } min = "2000-04-09" max = "2000-04-27" /> ) ;
209+ expect ( screen . getByLabelText ( / y e a r / i) ) . toHaveAttribute ( 'readonly' ) ;
210+ expect ( screen . getByLabelText ( / m o n t h / i) ) . toHaveAttribute ( 'readonly' ) ;
211+ expect ( screen . getByLabelText ( / d a y / i) ) . toHaveAttribute (
212+ 'aria-valuemin' ,
213+ '9' ,
214+ ) ;
215+ expect ( screen . getByLabelText ( / d a y / i) ) . toHaveAttribute (
216+ 'aria-valuemax' ,
217+ '27' ,
218+ ) ;
219+ } ,
220+ ) ;
211221 } ) ;
212222
213223 describe ( 'state' , ( ) => {
@@ -227,6 +237,14 @@ describe('DateInput', () => {
227237 expect ( screen . getByLabelText ( / y e a r / i) ) . toHaveValue ( '2000' ) ;
228238 } ) ;
229239
240+ it ( 'should ignore an invalid value' , ( ) => {
241+ render ( < DateInput { ...props } value = "2000-13-54" /> ) ;
242+
243+ expect ( screen . getByLabelText ( / d a y / i) ) . toHaveValue ( '' ) ;
244+ expect ( screen . getByLabelText ( / m o n t h / i) ) . toHaveValue ( '' ) ;
245+ expect ( screen . getByLabelText ( / y e a r / i) ) . toHaveValue ( '' ) ;
246+ } ) ;
247+
230248 it ( 'should update the displayed value' , ( ) => {
231249 const { rerender } = render ( < DateInput { ...props } value = "2000-01-12" /> ) ;
232250
@@ -341,6 +359,88 @@ describe('DateInput', () => {
341359
342360 expect ( onChange ) . toHaveBeenCalledWith ( '' ) ;
343361 } ) ;
362+
363+ describe ( 'on narrow viewports' , ( ) => {
364+ beforeEach ( ( ) => {
365+ ( useMedia as Mock ) . mockReturnValue ( true ) ;
366+ } ) ;
367+
368+ it ( 'should allow users to select a date on a calendar' , async ( ) => {
369+ ( useMedia as Mock ) . mockReturnValue ( true ) ;
370+ const onChange = vi . fn ( ) ;
371+
372+ render ( < DateInput { ...props } onChange = { onChange } /> ) ;
373+
374+ const openCalendarButton = screen . getByRole ( 'button' , {
375+ name : / c h a n g e d a t e / i,
376+ } ) ;
377+ await userEvent . click ( openCalendarButton ) ;
378+
379+ const calendarDialog = screen . getByRole ( 'dialog' ) ;
380+ expect ( calendarDialog ) . toBeVisible ( ) ;
381+
382+ const dateButton = screen . getByRole ( 'button' , { name : / 1 2 / i } ) ;
383+ await userEvent . click ( dateButton ) ;
384+
385+ expect ( onChange ) . not . toHaveBeenCalled ( ) ;
386+
387+ const applyButton = screen . getByRole ( 'button' , { name : / a p p l y / i } ) ;
388+ await userEvent . click ( applyButton ) ;
389+
390+ expect ( onChange ) . toHaveBeenCalledWith ( '2000-01-12' ) ;
391+ } ) ;
392+
393+ it ( 'should allow users to clear the date' , async ( ) => {
394+ const onChange = vi . fn ( ) ;
395+
396+ render (
397+ < DateInput
398+ { ...props }
399+ defaultValue = "2000-01-12"
400+ onChange = { onChange }
401+ /> ,
402+ ) ;
403+
404+ const openCalendarButton = screen . getByRole ( 'button' , {
405+ name : / c h a n g e d a t e / i,
406+ } ) ;
407+ await userEvent . click ( openCalendarButton ) ;
408+
409+ const calendarDialog = screen . getByRole ( 'dialog' ) ;
410+ expect ( calendarDialog ) . toBeVisible ( ) ;
411+
412+ const clearButton = screen . getByRole ( 'button' , { name : / c l e a r d a t e / i } ) ;
413+ await userEvent . click ( clearButton ) ;
414+
415+ expect ( onChange ) . toHaveBeenCalledWith ( '' ) ;
416+ } ) ;
417+
418+ it ( 'should allow users to close the calendar dialog without selecting a date' , async ( ) => {
419+ const onChange = vi . fn ( ) ;
420+
421+ render (
422+ < DateInput
423+ { ...props }
424+ defaultValue = "2000-01-12"
425+ onChange = { onChange }
426+ /> ,
427+ ) ;
428+
429+ const openCalendarButton = screen . getByRole ( 'button' , {
430+ name : / c h a n g e d a t e / i,
431+ } ) ;
432+ await userEvent . click ( openCalendarButton ) ;
433+
434+ const calendarDialog = screen . getByRole ( 'dialog' ) ;
435+ expect ( calendarDialog ) . toBeVisible ( ) ;
436+
437+ const closeButton = screen . getByRole ( 'button' , { name : / c l o s e / i } ) ;
438+ await userEvent . click ( closeButton ) ;
439+
440+ expect ( calendarDialog ) . not . toBeVisible ( ) ;
441+ expect ( onChange ) . not . toHaveBeenCalled ( ) ;
442+ } ) ;
443+ } ) ;
344444 } ) ;
345445
346446 describe ( 'status messages' , ( ) => {
0 commit comments