import React from 'react'; import 'jest-styled-components'; import 'jest-axe/extend-expect'; import 'regenerator-runtime/runtime'; import '@testing-library/jest-dom'; import { axe } from 'jest-axe'; import { fireEvent, render, act, screen } from '@testing-library/react'; import { FormNextLink, FormPreviousLink } from 'grommet-icons'; import { Box, Button, Calendar, Grommet, Text, CalendarProps } from '../..'; const DATE = '2020-01-15T00:00:00-08:00'; const DATES = [ '2020-01-12T00:00:00-08:00', ['2020-01-08T00:00:00-08:00', '2020-01-10T00:00:00-08:00'], ]; describe('Calendar', () => { test('Calendar should have no accessibility violations', async () => { const { container } = render( , ); const results = await axe(container); expect(results).toHaveNoViolations(); }); test('date', () => { // need to set the date to avoid snapshot drift over time const { container } = render( , ); expect(container.firstChild).toMatchSnapshot(); }); test('date without time specified', () => { // correct date displayed if time is not specified in ISOstring const { getByLabelText } = render( , ); expect( getByLabelText('January 2020; Currently selected January 15, 2020;'), ).not.toBeUndefined(); }); test('disabled', () => { const disabledDate = new Date(DATE); disabledDate.setDate(disabledDate.getDate() + 1); const { asFragment } = render( , ); expect(asFragment()).toMatchSnapshot(); }); test('dates', () => { const { container } = render( , ); expect(container.firstChild).toMatchSnapshot(); }); test('daysOfWeek', () => { const { container } = render( , ); expect(container.firstChild).toMatchSnapshot(); }); test('size', () => { const { container } = render( , ); expect(container.firstChild).toMatchSnapshot(); }); test('fill', () => { const { container } = render( , ); expect(container.firstChild).toMatchSnapshot(); }); test('firstDayOfWeek', () => { const { container } = render( , ); expect(container.firstChild).toMatchSnapshot(); }); test('reference', () => { const { container } = render( , ); expect(container.firstChild).toMatchSnapshot(); }); test('showAdjacentDays', () => { const { container } = render( , ); expect(container.firstChild).toMatchSnapshot(); }); test('header', () => { const { container } = render( {}} size="small" bounds={['2020-09-08', '2020-12-13']} header={({ date, locale, onPreviousMonth, onNextMonth, previousInBound, nextInBound, }) => ( {date.toLocaleDateString(locale, { month: 'long', year: 'numeric', })} )} animate={false} /> , ); expect(container.firstChild).toMatchSnapshot(); }); test('children', () => { const { container } = render( {({ day }) => {day}} , ); expect(container.firstChild).toMatchSnapshot(); }); test('select date', () => { const onSelect = jest.fn(); const { getByText, container } = render( , ); expect(container.firstChild).toMatchSnapshot(); fireEvent.click(getByText('17')); expect(onSelect).toBeCalledWith(expect.stringMatching(/^2020-01-17T/)); expect(container.firstChild).toMatchSnapshot(); }); test('select dates', () => { const onSelect = jest.fn(); const { getByText, container } = render( , ); expect(container.firstChild).toMatchSnapshot(); fireEvent.click(getByText('17')); expect(onSelect).toBeCalledWith(expect.stringMatching(/^2020-01-17T/)); expect(container.firstChild).toMatchSnapshot(); }); test('first day sunday week monday', () => { // When the first day of the month is Sunday, // and the request of firstDayOfWeek // is Monday, we are verifying we are not missing a week, issue 3253. const { container } = render( , ); expect(container.firstChild).toMatchSnapshot(); }); test('change months', () => { jest.useFakeTimers(); const { container, getByLabelText } = render( , ); // Change the Calendar from January to December fireEvent.click(getByLabelText('Go to December 2019')); act(() => { jest.runAllTimers(); }); expect(container.firstChild).toMatchSnapshot(); // Change the Calendar back to January fireEvent.click(getByLabelText('Go to January 2020')); act(() => { jest.runAllTimers(); }); expect(container.firstChild).toMatchSnapshot(); }); test('select date with range', () => { const onSelect = jest.fn(); const { getByText } = render( , ); // expect to be selecting end date of range, because date serves // as start. since selected date is < date we should set it as start fireEvent.click(getByText('11')); expect(onSelect).toBeCalledWith(expect.stringMatching(/2020-01-11T/)); fireEvent.click(getByText('20')); expect(onSelect).toBeCalledWith([ [ expect.stringMatching(/^2020-01-11T/), expect.stringMatching(/^2020-01-20T/), ], ]); }); test('disabled previous month button when date is before bounds', () => { render( , ); const previousMonthButton = screen.getByRole('button', { name: 'Go to December 2018', }); const nextMonthButton = screen.getByRole('button', { name: 'Go to February 2019', }); expect(previousMonthButton).toBeDisabled(); expect(nextMonthButton).not.toBeDisabled(); }); test('disabled next month button when date is after bounds', () => { render( , ); const previousMonthButton = screen.getByRole('button', { name: 'Go to January 2020', }); const nextMonthButton = screen.getByRole('button', { name: 'Go to March 2020', }); expect(previousMonthButton).not.toBeDisabled(); expect(nextMonthButton).toBeDisabled(); }); test('change to next month when date is before bounds', () => { const onReference = jest.fn(); render( , ); const nextMonthButton = screen.getByRole('button', { name: 'Go to February 2019', }); fireEvent.click(nextMonthButton); expect(onReference).toBeCalledWith(expect.stringContaining('2019-02-01')); }); test('change to next month when date is after bounds', () => { const onReference = jest.fn(); render( , ); const previousMonthButton = screen.getByRole('button', { name: 'Go to December 2020', }); fireEvent.click(previousMonthButton); expect(onReference).toBeCalledWith(expect.stringContaining('2020-12-31')); }); test('select date with range no date set', () => { const onSelect = jest.fn(); const { getByText } = render( , ); fireEvent.click(getByText('17')); fireEvent.click(getByText('20')); expect(onSelect).toBeCalledWith([ [ expect.stringMatching(/^2020-07-17T/), expect.stringMatching(/^2020-07-20T/), ], ]); }); test('select date greater and less than', () => { const onSelect = jest.fn(); const { getByLabelText } = render( , ); // select date greater than January 1st fireEvent.click(getByLabelText('Fri Jan 03 2020')); expect(onSelect).toBeCalledWith([ [ expect.stringMatching(/^2020-01-03T/), expect.stringMatching(/^2020-01-05T/), ], ]); // select date less than January 3rd // activeDate is end, since this is before the start // date we should update the date fireEvent.click(getByLabelText('Wed Jan 01 2020')); expect(onSelect).toBeCalledWith(expect.stringMatching(/2020-01-01T/)); }); test('select date with same start date', () => { const onSelect = jest.fn(); const { getByLabelText } = render( , ); // selecting same starting day fireEvent.click(getByLabelText('Wed Jan 01 2020')); expect(onSelect).toBeCalledWith(expect.stringMatching(/^2020-01-03T/)); }); test('select date with same date twice', () => { const onSelect = jest.fn(); const { getByLabelText } = render( , ); fireEvent.click(getByLabelText('Fri Jan 03 2020')); expect(onSelect).toBeCalledWith(expect.stringMatching(/^2020-01-03T/)); fireEvent.click(getByLabelText('Fri Jan 03 2020')); expect(onSelect).toBeCalledWith(undefined); }); test('select date with same end date', () => { const onSelect = jest.fn(); const { getByLabelText } = render( , ); // selecting same ending day fireEvent.click(getByLabelText('Fri Jan 03 2020')); expect(onSelect).toBeCalledWith(expect.stringMatching(/^2020-01-01T/)); }); test('range as array', () => { const onSelect = jest.fn(); const { getByLabelText } = render( , ); // select date greater than January 1st // activeDate by default is start fireEvent.click(getByLabelText('Fri Jan 03 2020')); expect(onSelect).toBeCalledWith([ [ expect.stringMatching(/^2020-01-03T/), expect.stringMatching(/^2020-01-05T/), ], ]); // select date less than January 3rd // activeDate is end, since this is before the start // date we should update the date fireEvent.click(getByLabelText('Wed Jan 01 2020')); expect(onSelect).toBeCalledWith([ [expect.stringMatching(/^2020-01-01T/), undefined], ]); // should select end date again fireEvent.click(getByLabelText('Fri Jan 03 2020')); expect(onSelect).toBeCalledWith([ [ expect.stringMatching(/^2020-01-01T/), expect.stringMatching(/^2020-01-03T/), ], ]); // should select start date, if great than end date, clear end date fireEvent.click(getByLabelText('Sun Jan 05 2020')); expect(onSelect).toBeCalledWith([ [expect.stringMatching(/^2020-01-05T/), undefined], ]); }); test('range as array with date', () => { const onSelect = jest.fn(); const { getByLabelText } = render( , ); // select date greater than January 1st // activeDate by default is start fireEvent.click(getByLabelText('Fri Jan 03 2020')); expect(onSelect).toBeCalledWith([ [ expect.stringMatching(/^2020-01-03T/), expect.stringMatching(/^2020-01-05T/), ], ]); // select date less than January 3rd // activeDate is end, since this is before the start // date we should update the date fireEvent.click(getByLabelText('Wed Jan 01 2020')); expect(onSelect).toBeCalledWith([ [expect.stringMatching(/^2020-01-01T/), undefined], ]); // should select end date again fireEvent.click(getByLabelText('Fri Jan 03 2020')); expect(onSelect).toBeCalledWith([ [ expect.stringMatching(/^2020-01-01T/), expect.stringMatching(/^2020-01-03T/), ], ]); // should select start date, if great than end date, clear end date fireEvent.click(getByLabelText('Sun Jan 05 2020')); expect(onSelect).toBeCalledWith([ [expect.stringMatching(/^2020-01-05T/), undefined], ]); }); test('activeDate start', () => { const onSelect = jest.fn(); const { getByLabelText } = render( , ); fireEvent.click(getByLabelText('Fri Jan 03 2020')); expect(onSelect).toBeCalledWith([ [ expect.stringMatching(/^2020-01-03T/), expect.stringMatching(/^2020-01-05T/), ], ]); }); test('activeDate end', () => { const onSelect = jest.fn(); const { getByLabelText } = render( , ); fireEvent.click(getByLabelText('Fri Jan 03 2020')); expect(onSelect).toBeCalledWith([ [ expect.stringMatching(/^2020-01-01T/), expect.stringMatching(/^2020-01-03T/), ], ]); }); test('daylight savings', () => { const onSelect = jest.fn(); const { getByLabelText } = render( , ); fireEvent.click(getByLabelText('Fri Jul 15 2022')); expect(onSelect).toBeCalledWith( expect.stringMatching(/^2022-07-15T08:00:00.000Z/), ); // Change the Calendar from July to March fireEvent.click(getByLabelText('Go to June 2022')); fireEvent.click(getByLabelText('Go to May 2022')); fireEvent.click(getByLabelText('Go to April 2022')); fireEvent.click(getByLabelText('Go to March 2022')); fireEvent.click(getByLabelText('Wed Mar 02 2022')); const date = new Date(); const january = new Date(date.getFullYear(), 0, 1).getTimezoneOffset(); const july = new Date(date.getFullYear(), 6, 1).getTimezoneOffset(); const hasDaylightSavings = january !== july; expect(onSelect).toBeCalledWith( // expecting one hour diff bc of daylight savings shift, otherwise no shift expect.stringMatching( `2022-03-02T0${hasDaylightSavings ? 9 : 8}:00:00.000Z`, ), ); }); }); describe('Calendar Keyboard events', () => { let onSelect: CalendarProps['onSelect']; let App: React.FC; beforeEach(() => { onSelect = jest.fn(); App = () => ( ); }); test('onEnter', async () => { const { getByText } = render(); fireEvent.mouseOver(getByText('15')); fireEvent.click(getByText('15')); fireEvent.keyDown(getByText('15'), { key: 'Enter', keyCode: 13, which: 13, }); fireEvent.mouseOut(getByText('15')); // Jan 15th is set to active expect(onSelect).toBeCalledWith(expect.stringMatching(/^2020-01-15T/)); }); test('onKeyUp', () => { const { getByText } = render(); fireEvent.mouseOver(getByText('15')); fireEvent.click(getByText('15')); fireEvent.keyDown(getByText('15'), { key: 'ArrowUp', keyCode: 38, which: 38, }); // press enter to change date to active fireEvent.keyDown(getByText('15'), { key: 'Enter', keyCode: 13, which: 13, }); // Jan 8th is set to active expect(onSelect).toBeCalledWith(expect.stringMatching(/^2020-01-08T/)); }); test('onKeyDown', () => { const { getByText } = render(); fireEvent.mouseOver(getByText('15')); fireEvent.click(getByText('15')); fireEvent.keyDown(getByText('15'), { key: 'ArrowDown', keyCode: 40, which: 40, }); // press enter to change date to active fireEvent.keyDown(getByText('15'), { key: 'Enter', keyCode: 13, which: 13, }); // Jan 22th is set to active expect(onSelect).toBeCalledWith(expect.stringMatching(/^2020-01-22T/)); }); test('onKeyLeft', () => { const { getByText } = render(); fireEvent.mouseOver(getByText('15')); fireEvent.click(getByText('15')); fireEvent.keyDown(getByText('15'), { key: 'ArrowLeft', keyCode: 37, which: 37, }); // press enter to change date to active fireEvent.keyDown(getByText('15'), { key: 'Enter', keyCode: 13, which: 13, }); // Jan 14th is set to active expect(onSelect).toBeCalledWith(expect.stringMatching(/^2020-01-14T/)); }); test('onKeyRight', () => { const { getByText } = render(); fireEvent.mouseOver(getByText('15')); fireEvent.click(getByText('15')); fireEvent.keyDown(getByText('15'), { key: 'ArrowRight', keyCode: 39, which: 39, }); // press enter to change date to active fireEvent.keyDown(getByText('15'), { key: 'Enter', keyCode: 13, which: 13, }); // Jan 16th is set to active expect(onSelect).toBeCalledWith(expect.stringMatching(/^2020-01-16T/)); }); test('heading text font size', () => { const { asFragment } = render( , ); expect(asFragment()).toMatchSnapshot(); }); });