import React from 'react' ; import { act } from 'react-dom/test-utils' ; import { render , screen } from '@testing-library/react' ; import userEvent from '@testing-library/user-event' ; import '@testing-library/jest-dom/extend-expect' ; import { axe } from 'jest-axe' ; import isWeekend from 'date-fns/isWeekend' ; import { DateInput } from './DateInput' ; describe ( '<DateInput /> spec' , ( ) => { const RealDate = Date ; const mockDate = ( isoDate ) => { ( global as any ) . Date = class extends RealDate { constructor ( ... theArgs ) { super ( ... theArgs ) ; if ( theArgs . length ) { return new RealDate ( ... theArgs ) ; } return new RealDate ( isoDate ) ; } static now ( ) { return new RealDate ( isoDate ) . getTime ( ) ; } } ; } ; beforeEach ( ( ) => { mockDate ( '2021-01-17T12:49:00' ) ; } ) ; afterEach ( ( ) => { global . Date = RealDate ; } ) ; it ( 'renders the component with default props' , ( ) => { const { asFragment } = render ( < DateInput id = "date" / > ) ; expect ( asFragment ( ) ) . toMatchSnapshot ( ) ; } ) ; it ( 'renders the component with additional props' , ( ) => { const { asFragment } = render ( < DateInput id = "date" label = "Foo" disableConfirmation / > ) ; expect ( asFragment ( ) ) . toMatchSnapshot ( ) ; } ) ; it ( 'renders the component with different languages' , ( ) => { const { asFragment } = render ( < > < DateInput id = "date" language = "en" / > < DateInput id = "date" language = "fi" / > < DateInput id = "date" language = "sv" / > < />); expect ( asFragment ( ) ) . toMatchSnapshot ( ) ; } ) ; it ( 'passes accessibility test' , async ( ) => { const { container } = render ( < DateInput id = "date" label = "Foo" / > ) ; const results = await axe ( container ) ; expect ( results ) . toHaveNoViolations ( ) ; } ) ; it ( 'opens and closes the date picker' , async ( ) => { render ( < DateInput id = "date" label = "Foo" / > ) ; expect ( screen . queryByRole ( 'dialog' ) ) . toBeNull ( ) ; await act ( async ( ) => { userEvent . click ( screen . getByLabelText ( 'Choose date' ) ) ; } ) ; expect ( screen . getByRole ( 'dialog' ) ) . toBeVisible ( ) ; userEvent . click ( screen . getByTestId ( 'closeButton' ) ) ; expect ( screen . queryByRole ( 'dialog' ) ) . toBeNull ( ) ; } ) ; it ( 'has current date selected by default' , async ( ) => { const { container } = render ( < DateInput id = "date" label = "Foo" / > ) ; await act ( async ( ) => { userEvent . click ( screen . getByLabelText ( 'Choose date' ) ) ; } ) ; expect ( screen . getByLabelText ( 'Month' ) ) . toHaveValue ( '0' ) ; expect ( screen . getByLabelText ( 'Year' ) ) . toHaveValue ( '2021' ) ; const cellElement = container . querySelector ( 'td[aria-current="date"]' ) ; expect ( cellElement . querySelectorAll ( 'button > span' ) [ 0 ] ) . toHaveTextContent ( '17' ) ; expect ( cellElement . querySelectorAll ( 'button > span' ) [ 1 ] ) . toHaveTextContent ( 'January 17' ) ; } ) ; it ( 'sets the correct attributes when date is selected' , async ( ) => { const { container } = render ( < DateInput id = "date" label = "Foo" / > ) ; await act ( async ( ) => { userEvent . click ( screen . getByLabelText ( 'Choose date' ) ) ; } ) ; userEvent . selectOptions ( screen . getByLabelText ( 'Month' ) , '1' ) ; userEvent . selectOptions ( screen . getByLabelText ( 'Year' ) , '2022' ) ; expect ( container . querySelector ( 'td[aria-current="date"]' ) ) . toBeNull ( ) ; userEvent . click ( container . querySelector ( 'button[data-date="2022-02-10"]' ) ) ; const currentDateButton = container . querySelector ( 'button[data-date="2022-02-10"]' ) ; expect ( currentDateButton ) . toHaveAttribute ( 'aria-pressed' , 'true' ) ; expect ( currentDateButton ) . toHaveClass ( 'hds-datepicker__day--selected' ) ; } ) ; it ( 'sets the correct input value with confirmation mode on' , async ( ) => { const { container } = render ( < DateInput id = "date" label = "Foo" / > ) ; await act ( async ( ) => { userEvent . click ( screen . getByLabelText ( 'Choose date' ) ) ; } ) ; userEvent . selectOptions ( screen . getByLabelText ( 'Month' ) , '1' ) ; userEvent . selectOptions ( screen . getByLabelText ( 'Year' ) , '2022' ) ; userEvent . click ( container . querySelector ( 'button[data-date="2022-02-10"]' ) ) ; userEvent . click ( screen . getByTestId ( 'selectButton' ) ) ; expect ( screen . queryByRole ( 'dialog' ) ) . toBeNull ( ) ; expect ( screen . getByRole ( 'textbox' ) ) . toHaveValue ( '10.2.2022' ) ; } ) ; it ( 'does not set the input value when close button is pressed' , async ( ) => { const { container } = render ( < DateInput id = "date" label = "Foo" / > ) ; await act ( async ( ) => { userEvent . click ( screen . getByLabelText ( 'Choose date' ) ) ; } ) ; userEvent . selectOptions ( screen . getByLabelText ( 'Month' ) , '1' ) ; userEvent . selectOptions ( screen . getByLabelText ( 'Year' ) , '2022' ) ; userEvent . click ( container . querySelector ( 'button[data-date="2022-02-10"]' ) ) ; userEvent . click ( screen . getByTestId ( 'closeButton' ) ) ; expect ( screen . queryByRole ( 'dialog' ) ) . toBeNull ( ) ; expect ( screen . getByRole ( 'textbox' ) ) . toHaveValue ( '' ) ; } ) ; it ( 'does not set the input value when clicked outside the modal' , async ( ) => { const { container } = render ( < DateInput id = "date" label = "Foo" / > ) ; await act ( async ( ) => { userEvent . click ( screen . getByLabelText ( 'Choose date' ) ) ; } ) ; userEvent . selectOptions ( screen . getByLabelText ( 'Month' ) , '1' ) ; userEvent . selectOptions ( screen . getByLabelText ( 'Year' ) , '2022' ) ; userEvent . click ( container . querySelector ( 'button[data-date="2022-02-10"]' ) ) ; await act ( async ( ) => { userEvent . click ( container ) ; } ) ; expect ( screen . queryByRole ( 'dialog' ) ) . toBeNull ( ) ; expect ( screen . getByRole ( 'textbox' ) ) . toHaveValue ( '' ) ; } ) ; it ( 'sets the correct input value with confirmation mode off' , async ( ) => { const { container } = render ( < DateInput id = "date" label = "Foo" disableConfirmation / > ) ; await act ( async ( ) => { userEvent . click ( screen . getByLabelText ( 'Choose date' ) ) ; } ) ; userEvent . selectOptions ( screen . getByLabelText ( 'Month' ) , '1' ) ; userEvent . selectOptions ( screen . getByLabelText ( 'Year' ) , '2022' ) ; userEvent . click ( container . querySelector ( 'button[data-date="2022-02-10"]' ) ) ; expect ( screen . queryByRole ( 'dialog' ) ) . toBeNull ( ) ; expect ( screen . getByRole ( 'textbox' ) ) . toHaveValue ( '10.2.2022' ) ; } ) ; it ( 'has correct date selected when defaultValue is provided' , async ( ) => { const { container } = render ( < DateInput id = "date" label = "Foo" defaultValue = "10.02.2022" / > ) ; expect ( screen . getByRole ( 'textbox' ) ) . toHaveValue ( '10.02.2022' ) ; await act ( async ( ) => { userEvent . click ( screen . getByLabelText ( 'Choose date' ) ) ; } ) ; expect ( screen . getByLabelText ( 'Month' ) ) . toHaveValue ( '1' ) ; expect ( screen . getByLabelText ( 'Year' ) ) . toHaveValue ( '2022' ) ; const currentDateButton = container . querySelector ( 'button[data-date="2022-02-10"]' ) ; expect ( currentDateButton ) . toHaveAttribute ( 'aria-pressed' , 'true' ) ; expect ( currentDateButton ) . toHaveClass ( 'hds-datepicker__day--selected' ) ; } ) ; it ( 'has correct date selected when value is provided' , async ( ) => { const { container } = render ( < DateInput id = "date" label = "Foo" value = "10.02.2022" / > ) ; expect ( screen . getByRole ( 'textbox' ) ) . toHaveValue ( '10.02.2022' ) ; await act ( async ( ) => { userEvent . click ( screen . getByLabelText ( 'Choose date' ) ) ; } ) ; expect ( screen . getByLabelText ( 'Month' ) ) . toHaveValue ( '1' ) ; expect ( screen . getByLabelText ( 'Year' ) ) . toHaveValue ( '2022' ) ; const currentDateButton = container . querySelector ( 'button[data-date="2022-02-10"]' ) ; expect ( currentDateButton ) . toHaveAttribute ( 'aria-pressed' , 'true' ) ; expect ( currentDateButton ) . toHaveClass ( 'hds-datepicker__day--selected' ) ; } ) ; it ( 'setting invalid date as the input value resets the selected date in calendar' , async ( ) => { const { container } = render ( < DateInput id = "date" label = "Foo" value = "10.02.2022" / > ) ; expect ( screen . getByRole ( 'textbox' ) ) . toHaveValue ( '10.02.2022' ) ; await act ( async ( ) => { userEvent . click ( screen . getByLabelText ( 'Choose date' ) ) ; } ) ; expect ( screen . getByLabelText ( 'Month' ) ) . toHaveValue ( '1' ) ; expect ( screen . getByLabelText ( 'Year' ) ) . toHaveValue ( '2022' ) ; const currentDateButton = container . querySelector ( 'button[data-date="2022-02-10"]' ) ; expect ( currentDateButton ) . toHaveAttribute ( 'aria-pressed' , 'true' ) ; expect ( currentDateButton ) . toHaveClass ( 'hds-datepicker__day--selected' ) ; await act ( async ( ) => { userEvent . type ( screen . getByRole ( 'textbox' ) , '20' ) ; } ) ; expect ( container . querySelector ( '[aria-pressed="true"]' ) ) . toBeNull ( ) ; } ) ; it ( 'should be able to clear the value' , async ( ) => { const { rerender } = render ( < DateInput id = "date" label = "Foo" value = "10.02.2022" / > ) ; expect ( screen . getByRole ( 'textbox' ) ) . toHaveValue ( '10.02.2022' ) ; expect ( screen . getByLabelText ( 'Month' ) ) . toHaveValue ( '1' ) ; expect ( screen . getByLabelText ( 'Year' ) ) . toHaveValue ( '2022' ) ; await act ( async ( ) => { rerender ( < DateInput id = "date" value = "" / > ) ; } ) ; expect ( screen . getByRole ( 'textbox' ) ) . toHaveValue ( '' ) ; expect ( screen . getByLabelText ( 'Month' ) ) . toHaveValue ( '0' ) ; expect ( screen . getByLabelText ( 'Year' ) ) . toHaveValue ( '2021' ) ; } ) ; it ( 'should be able to navigate dates with keyboard when minDate is set' , async ( ) => { const minDate = new Date ( ) ; const { container } = render ( < DateInput disableConfirmation helperText = "Assistive text" id = "date" minDate = { minDate } initialMonth = { new Date ( ) } label = "Choose a date" language = "en" / > ) ; await act ( async ( ) => { userEvent . click ( screen . getByLabelText ( 'Choose date' ) ) ; } ) ; await act ( async ( ) => { userEvent . tab ( ) ; userEvent . tab ( ) ; userEvent . tab ( ) ; userEvent . tab ( ) ; } ) ; const currentDateButton = container . querySelector ( 'button[data-date="2021-01-17"]' ) ; expect ( currentDateButton ) . toHaveFocus ( ) ; } ) ; it ( 'should skip weekend dates with keyboard navigation when weekend dates are disabled' , async ( ) => { const { container } = render ( < DateInput id = "date" initialMonth = { new Date ( ) } label = "Choose a date" language = "en" isDateDisabledBy = { isWeekend } / > ) ; await act ( async ( ) => { userEvent . click ( screen . getByLabelText ( 'Choose date' ) ) ; } ) ; await act ( async ( ) => { userEvent . tab ( ) ; userEvent . tab ( ) ; userEvent . tab ( ) ; userEvent . tab ( ) ; } ) ; const fridayButton = container . querySelector ( 'button[data-date="2021-01-01"]' ) ; expect ( fridayButton ) . toHaveFocus ( ) ; await act ( async ( ) => { userEvent . type ( fridayButton , '{arrowright}' ) ; } ) ; const nextMondayButton = container . querySelector ( 'button[data-date="2021-01-04"]' ) ; expect ( nextMondayButton ) . toHaveFocus ( ) ; } ) ; } ) ;