grommet/grommet

View on GitHub
src/js/components/DateInput/__tests__/DateInput-test.tsx

Summary

Maintainability
F
2 wks
Test Coverage
import React from 'react';
import 'jest-styled-components';
import { fireEvent, render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { axe } from 'jest-axe';
import 'jest-axe/extend-expect';
import 'regenerator-runtime/runtime';
import '@testing-library/jest-dom';
import { Calendar as CalendarIcon, Clock as ClockIcon } from 'grommet-icons';

import { createPortal, expectPortal } from '../../../utils/portal';
import { Grommet } from '../../Grommet';
import { Button } from '../../Button';
import { DateInput } from '..';
import { Form } from '../../Form';
import { FormField } from '../../FormField';

const DATE = '2020-07-02T00:00:00-08:00';
const DATE_FIRST = '2020-07-01T00:00:00-08:00';
const DATES = ['2020-07-02T00:00:00-08:00', '2020-07-07T00:00:00-08:00'];
const DATE_NOTZ = '2020-07-02';
const DATES_NOTZ = ['2020-07-02', '2020-07-07'];

describe('DateInput', () => {
  beforeEach(createPortal);

  test('should reset date if passed empty string', async () => {
    const Test = () => {
      const [value, setValue] = React.useState(DATE);
      return (
        <Grommet>
          <DateInput
            id="item"
            name="item"
            format="mm/dd/yyyy"
            value={value}
            inline
          />
          <Button label="Reset Date" onClick={() => setValue('')} />
        </Grommet>
      );
    };
    const { container, getByText } = render(<Test />);
    let dateInputValue = (container.querySelector('#item') as HTMLInputElement)
      .value;

    expect(dateInputValue).not.toEqual('');
    fireEvent.click(getByText('Reset Date'));
    dateInputValue = (container.querySelector('#item') as HTMLInputElement)
      .value;
    expect(dateInputValue).toEqual('');
  });

  test('should reset date if passed an []', async () => {
    const Test = () => {
      const [value, setValue] = React.useState(DATES);
      return (
        <Grommet>
          <DateInput
            id="item"
            name="item"
            format="mm/dd/yyyy"
            value={value}
            inline
          />
          <Button label="Reset Date" onClick={() => setValue([])} />
        </Grommet>
      );
    };
    const { container, getByText } = render(<Test />);
    let dateInputValue = (container.querySelector('#item') as HTMLInputElement)
      .value;

    expect(dateInputValue).not.toEqual('');
    fireEvent.click(getByText('Reset Date'));
    dateInputValue = (container.querySelector('#item') as HTMLInputElement)
      .value;
    expect(dateInputValue).toEqual('');
  });

  test('should have no accessibility violations', async () => {
    const { container } = render(
      <Grommet>
        <DateInput format="mm/dd/yyyy" />
      </Grommet>,
    );
    const results = await axe(container);
    expect(results).toHaveNoViolations();
  });

  test('should handle typing date and clicking date simultaneously', async () => {
    const user = userEvent.setup();

    const TestComponent = () => {
      const [value, setValue] = React.useState([]);
      return (
        <Grommet>
          <DateInput
            id="item"
            name="item"
            format="mm/dd/yyyy-mm/dd/yyyy"
            onChange={(event) => {
              setValue(event.value as any);
            }}
            inline
            value={value}
          />
        </Grommet>
      );
    };

    render(<TestComponent />);

    const input = screen.getByRole('textbox');

    await user.type(input, '01/01/2022');
    expect(input).toHaveValue('01/01/2022');
    const button = screen.queryAllByText('1');

    await user.click(button[0]);
    expect(input).toHaveValue('');
  });

  test('basic', () => {
    const { container } = render(
      <Grommet>
        <DateInput id="item" name="item" value={DATE} />
      </Grommet>,
    );
    expect(container.firstChild).toMatchSnapshot();
  });

  test('format', () => {
    const { container } = render(
      <Grommet>
        <DateInput id="item" name="item" format="mm/dd/yyyy" value={DATE} />
      </Grommet>,
    );
    expect(container.firstChild).toMatchSnapshot();
  });

  test('format with date bounds', async () => {
    const user = userEvent.setup();

    render(
      <Grommet>
        <DateInput
          id="item"
          name="item"
          format="mm/dd/yyyy"
          calendarProps={{
            bounds: ['2022-11-10', '2022-11-20'],
          }}
        />
      </Grommet>,
    );

    const input = screen.getByRole('textbox');

    await user.type(input, '09/09/2022');
    expect(input).not.toHaveValue();

    await user.clear(input);
    await user.type(input, '11/15/2022');
    expect(input).toHaveValue('11/15/2022');
  });

  test('reverse calendar icon', () => {
    const { container } = render(
      <Grommet>
        <DateInput
          id="item"
          name="item"
          format="dd/mm/yyyy"
          reverse
          value={DATES}
        />
      </Grommet>,
    );
    expect(container.firstChild).toMatchSnapshot();
  });

  test('input props reverse as false', () => {
    const { container } = render(
      <Grommet>
        <DateInput
          id="item"
          name="item"
          format="dd/mm/yyyy"
          inputProps={{ reverse: false }}
          value={DATES}
        />
      </Grommet>,
    );
    expect(container.firstChild).toMatchSnapshot();
  });

  test('input props reverse as true', () => {
    const { container } = render(
      <Grommet>
        <DateInput
          id="item"
          name="item"
          format="dd/mm/yyyy"
          inputProps={{ reverse: true }}
          value={DATES}
        />
      </Grommet>,
    );
    expect(container.firstChild).toMatchSnapshot();
  });

  test('input props reverse as false with icon', () => {
    const { container } = render(
      <Grommet>
        <DateInput
          id="item"
          name="item"
          format="dd/mm/yyyy"
          icon={<ClockIcon />}
          inputProps={{ reverse: false }}
          value={DATES}
        />
      </Grommet>,
    );
    expect(container.firstChild).toMatchSnapshot();
  });

  test('input props reverse as true with icon', () => {
    const { container } = render(
      <Grommet>
        <DateInput
          id="item"
          name="item"
          format="dd/mm/yyyy"
          icon={<ClockIcon />}
          inputProps={{ reverse: true }}
          value={DATES}
        />
      </Grommet>,
    );
    expect(container.firstChild).toMatchSnapshot();
  });

  test('inline', () => {
    const { container } = render(
      <Grommet>
        <DateInput id="item" name="item" inline value={DATE} />
      </Grommet>,
    );
    expect(container.firstChild).toMatchSnapshot();
  });

  test('format inline', () => {
    const { container } = render(
      <Grommet>
        <DateInput
          id="item"
          name="item"
          format="mm/dd/yyyy"
          inline
          value={DATE}
        />
      </Grommet>,
    );
    expect(container.firstChild).toMatchSnapshot();
  });

  test('format disabled', () => {
    const { container } = render(
      <Grommet>
        <DateInput
          id="item"
          name="item"
          format="mm/dd/yyyy"
          disabled
          value={DATE}
        />
      </Grommet>,
    );
    expect(container.firstChild).toMatchSnapshot();
  });

  test('range', () => {
    const { container } = render(
      <Grommet>
        <DateInput id="item" name="item" value={DATES} />
      </Grommet>,
    );
    expect(container.firstChild).toMatchSnapshot();
  });

  test('range inline', () => {
    const { container } = render(
      <Grommet>
        <DateInput id="item" name="item" value={DATES} inline />
      </Grommet>,
    );
    expect(container.firstChild).toMatchSnapshot();
  });

  test('range format', () => {
    const { container } = render(
      <Grommet>
        <DateInput
          id="item"
          name="item"
          format="mm/dd/yyyy-mm/dd/yyyy"
          value={DATES}
        />
      </Grommet>,
    );
    expect(container.firstChild).toMatchSnapshot();
  });

  test('range format no value', () => {
    render(
      <Grommet>
        <DateInput id="item" name="item" format="mm/dd/yyyy-mm/dd/yyyy" />
      </Grommet>,
    );

    expect(screen.queryByRole('button', { name: /Calendar/ })).not.toBeNull();
  });

  test('range format inline', () => {
    const { container } = render(
      <Grommet>
        <DateInput
          id="item"
          name="item"
          format="mm/dd/yyyy-mm/dd/yyyy"
          value={DATES}
          inline
        />
      </Grommet>,
    );
    expect(container.firstChild).toMatchSnapshot();
  });

  test('range format with date bounds', async () => {
    const user = userEvent.setup();

    render(
      <Grommet>
        <DateInput
          id="item"
          name="item"
          format="mm/dd/yyyy-mm/dd/yyyy"
          calendarProps={{
            bounds: ['2022-11-10', '2022-11-20'],
          }}
        />
      </Grommet>,
    );

    const input = screen.getByRole('textbox');

    await user.type(input, '09/09/2022-09/09/2022');
    expect(input).not.toHaveValue();

    await user.clear(input);
    await user.type(input, '11/15/2022-11/15/2022');
    expect(input).toHaveValue('11/15/2022-11/15/2022');
  });

  test('dates initialized with empty array', async () => {
    const user = userEvent.setup();

    const onChange = jest.fn((event) => event.value);

    const { getByText } = render(
      <Grommet>
        <DateInput
          id="item"
          name="item"
          defaultValue={[]}
          inline
          onChange={onChange}
          calendarProps={{
            reference: DATE,
          }}
        />
      </Grommet>,
    );
    await user.click(getByText('20'));
    expect(onChange).toHaveBeenCalled();
    expect(onChange).toHaveReturnedWith([
      `2020-07-20T08:00:00.000Z`,
      `2020-07-20T08:00:00.000Z`,
    ]);
  });

  test('focus', () => {
    const onFocus = jest.fn();
    const { container, getByPlaceholderText } = render(
      <Grommet>
        <DateInput
          id="item"
          name="item"
          format="mm/dd/yyyy"
          value={DATE}
          onFocus={onFocus}
        />
      </Grommet>,
    );

    expect(container.firstChild).toMatchSnapshot();
    fireEvent.focus(getByPlaceholderText('mm/dd/yyyy'));
    expect(onFocus).toHaveBeenCalled();

    fireEvent.keyDown(getByPlaceholderText('mm/dd/yyyy'), {
      key: 'Space',
      keyCode: 32,
      which: 32,
    });
    expect(document.getElementById('item__drop')).not.toBeNull();
  });

  test('click', async () => {
    const user = userEvent.setup();

    const { getByPlaceholderText } = render(
      <Grommet>
        <DateInput
          id="item"
          name="item"
          format="mm/dd/yyyy"
          value={DATE}
          onFocus={() => {}}
        />
      </Grommet>,
    );

    await user.click(getByPlaceholderText('mm/dd/yyyy'));
    expect(document.getElementById('item__drop')).toBeNull();
  });

  test('select inline', () => {
    const onChange = jest.fn((event) => event.value);
    const { container, getByText } = render(
      <Grommet>
        <DateInput
          id="item"
          name="item"
          defaultValue={DATE}
          inline
          onChange={onChange}
        />
      </Grommet>,
    );
    expect(container.firstChild).toMatchSnapshot();

    fireEvent.click(getByText('20'));
    expect(onChange).toHaveBeenCalled();
    expect(onChange).toHaveReturnedWith('2020-07-20T08:00:00.000Z');
  });

  test('select inline without timezone', () => {
    const onChange = jest.fn((event) => event.value);
    const { container, getByText } = render(
      <Grommet>
        <DateInput
          id="item"
          name="item"
          defaultValue={DATE_NOTZ}
          inline
          onChange={onChange}
        />
      </Grommet>,
    );
    expect(container.firstChild).toMatchSnapshot();

    fireEvent.click(getByText('20'));
    expect(onChange).toHaveBeenCalled();
    expect(onChange).toHaveReturnedWith('2020-07-20');
  });

  test('select format inline', () => {
    const onChange = jest.fn((event) => event.value);
    const { container, getByText } = render(
      <Grommet>
        <DateInput
          id="item"
          name="item"
          format="mm/dd/yyyy"
          defaultValue={DATE}
          inline
          onChange={onChange}
        />
      </Grommet>,
    );
    expect(container.firstChild).toMatchSnapshot();

    fireEvent.click(getByText('20'));
    expect(onChange).toHaveBeenCalled();
    expect(onChange).toHaveReturnedWith('2020-07-20T08:00:00.000Z');
    expect(container.firstChild).toMatchSnapshot();
  });

  test('select format inline', () => {
    const onChange = jest.fn((event) => event.value);
    const { asFragment, getByText } = render(
      <Grommet>
        <DateInput
          id="item"
          name="item"
          format="mm/dd/yyyy"
          defaultValue={DATE_NOTZ}
          inline
          onChange={onChange}
        />
      </Grommet>,
    );
    expect(asFragment()).toMatchSnapshot();

    fireEvent.click(getByText('20'));
    expect(onChange).toHaveBeenCalled();
    expect(onChange).toHaveReturnedWith('2020-07-20');
    expect(asFragment()).toMatchSnapshot();
  });

  test('select format', () => {
    const onChange = jest.fn((event) => event.value);
    const { container, getByPlaceholderText, getByText } = render(
      <Grommet>
        <DateInput
          id="item"
          name="item"
          format="mm/dd/yyyy"
          defaultValue={DATE}
          onChange={onChange}
        />
      </Grommet>,
    );
    expect(container.firstChild).toMatchSnapshot();

    fireEvent.focus(getByPlaceholderText('mm/dd/yyyy'));
    expect(container.firstChild).toMatchSnapshot();
    fireEvent.keyDown(getByPlaceholderText('mm/dd/yyyy'), {
      key: 'Space',
      keyCode: 32,
      which: 32,
    });
    expectPortal('item__drop').toMatchSnapshot();

    fireEvent.click(getByText('20'));
    expect(onChange).toHaveBeenCalled();
    expect(onChange).toHaveReturnedWith('2020-07-20T08:00:00.000Z');
    expect(document.getElementById('item__drop')).toBeNull();
  });

  test('select format no timezone', () => {
    const onChange = jest.fn((event) => event.value);
    const { asFragment, getByPlaceholderText, getByText } = render(
      <Grommet>
        <DateInput
          id="item"
          name="item"
          format="mm/dd/yyyy"
          defaultValue={DATE_NOTZ}
          onChange={onChange}
        />
      </Grommet>,
    );
    expect(asFragment()).toMatchSnapshot();

    fireEvent.focus(getByPlaceholderText('mm/dd/yyyy'));
    expect(asFragment()).toMatchSnapshot();
    fireEvent.keyDown(getByPlaceholderText('mm/dd/yyyy'), {
      key: 'Space',
      keyCode: 32,
      which: 32,
    });
    expectPortal('item__drop').toMatchSnapshot();

    fireEvent.click(getByText('20'));
    expect(onChange).toHaveBeenCalled();
    expect(onChange).toHaveReturnedWith('2020-07-20');
    expect(document.getElementById('item__drop')).toBeNull();
  });

  test('type format inline', () => {
    const onChange = jest.fn((event) => event.value);
    const { container, getByPlaceholderText } = render(
      <Grommet>
        <DateInput
          id="item"
          name="item"
          format="mm/dd/yyyy"
          defaultValue={DATE}
          inline
          onChange={onChange}
        />
      </Grommet>,
    );
    expect(container.firstChild).toMatchSnapshot();

    fireEvent.change(getByPlaceholderText('mm/dd/yyyy'), {
      target: { value: '07/21/2020' },
    });
    expect(onChange).toHaveBeenCalled();
    expect(onChange).toHaveReturnedWith('2020-07-21T08:00:00.000Z');
    expect(container.firstChild).toMatchSnapshot();
  });

  test('type format inline without timezone', () => {
    const onChange = jest.fn((event) => event.value);
    const { asFragment, getByPlaceholderText } = render(
      <Grommet>
        <DateInput
          id="item"
          name="item"
          format="mm/dd/yyyy"
          defaultValue={DATE_NOTZ}
          inline
          onChange={onChange}
        />
      </Grommet>,
    );
    expect(asFragment()).toMatchSnapshot();

    fireEvent.change(getByPlaceholderText('mm/dd/yyyy'), {
      target: { value: '07/21/2020' },
    });
    expect(onChange).toHaveBeenCalled();
    expect(onChange).toHaveReturnedWith('2020-07-21');
    expect(asFragment()).toMatchSnapshot();
  });

  test('type format inline short', () => {
    const onChange = jest.fn((event) => event.value);
    const { container, getByPlaceholderText } = render(
      <Grommet>
        <DateInput
          id="item"
          name="item"
          format="m/d/yy"
          defaultValue={DATE}
          inline
          onChange={onChange}
        />
      </Grommet>,
    );
    expect(container.firstChild).toMatchSnapshot();

    fireEvent.change(getByPlaceholderText('m/d/yy'), {
      target: { value: '7/21/20' },
    });

    expect(onChange).toHaveBeenCalled();
    expect(onChange).toHaveReturnedWith('2020-07-21T08:00:00.000Z');
    expect(container.firstChild).toMatchSnapshot();
  });

  test('type format inline short without timezone', () => {
    const onChange = jest.fn((event) => event.value);
    const { asFragment, getByPlaceholderText } = render(
      <Grommet>
        <DateInput
          id="item"
          name="item"
          format="m/d/yy"
          defaultValue={DATE_NOTZ}
          inline
          onChange={onChange}
        />
      </Grommet>,
    );
    expect(asFragment()).toMatchSnapshot();

    fireEvent.change(getByPlaceholderText('m/d/yy'), {
      target: { value: '7/21/20' },
    });

    expect(onChange).toHaveBeenCalled();
    expect(onChange).toHaveReturnedWith('2020-07-21');
    expect(asFragment()).toMatchSnapshot();
  });

  test('type format inline partial', () => {
    const onChange = jest.fn((event) => event.value);
    const { container, getByPlaceholderText } = render(
      <Grommet>
        <DateInput
          id="item"
          name="item"
          format="mm/dd/yyyy"
          defaultValue={DATE}
          inline
          onChange={onChange}
        />
      </Grommet>,
    );
    expect(container.firstChild).toMatchSnapshot();

    fireEvent.change(getByPlaceholderText('mm/dd/yyyy'), {
      target: { value: '07/21/202' },
    });
    expect(onChange).toHaveBeenCalled();
    expect(onChange).toHaveReturnedWith(undefined);
    // cannot check snapshot here as it will be relative to the current date
  });

  test('type format inline partial without timezone', () => {
    const onChange = jest.fn((event) => event.value);
    const { asFragment, getByPlaceholderText } = render(
      <Grommet>
        <DateInput
          id="item"
          name="item"
          format="mm/dd/yyyy"
          defaultValue={DATE_NOTZ}
          inline
          onChange={onChange}
        />
      </Grommet>,
    );
    expect(asFragment()).toMatchSnapshot();

    fireEvent.change(getByPlaceholderText('mm/dd/yyyy'), {
      target: { value: '07/21/202' },
    });
    expect(onChange).toHaveBeenCalled();
    expect(onChange).toHaveReturnedWith(undefined);
    // cannot check snapshot here as it will be relative to the current date
  });

  test('select format inline range', () => {
    const onChange = jest.fn((event) => event.value);
    const { container, getByText } = render(
      <Grommet>
        <DateInput
          id="item"
          name="item"
          format="mm/dd/yyyy-mm/dd/yyyy"
          defaultValue={DATES}
          inline
          onChange={onChange}
        />
      </Grommet>,
    );
    expect(container.firstChild).toMatchSnapshot();

    // new calendar logic adjust start date by default
    fireEvent.click(getByText('10'));
    expect(onChange).toHaveBeenCalled();
    expect(onChange).toHaveReturnedWith([
      '2020-07-10T08:00:00.000Z',
      '2020-07-10T08:00:00.000Z',
    ]);
    expect(container.firstChild).toMatchSnapshot();
  });

  test('select format inline range without timezone', () => {
    const onChange = jest.fn((event) => event.value);
    const { asFragment, getByText } = render(
      <Grommet>
        <DateInput
          id="item"
          name="item"
          format="mm/dd/yyyy-mm/dd/yyyy"
          defaultValue={DATES_NOTZ}
          inline
          onChange={onChange}
        />
      </Grommet>,
    );
    expect(asFragment()).toMatchSnapshot();

    // new calendar logic adjust start date by default
    fireEvent.click(getByText('10'));
    expect(onChange).toHaveBeenCalled();
    expect(onChange).toHaveReturnedWith(['2020-07-10', '2020-07-10']);
    expect(asFragment()).toMatchSnapshot();
  });

  test('type format inline range', () => {
    const onChange = jest.fn((event) => event.value);
    const { container, getByPlaceholderText } = render(
      <Grommet>
        <DateInput
          id="item"
          name="item"
          format="mm/dd/yyyy-mm/dd/yyyy"
          defaultValue={DATES}
          inline
          onChange={onChange}
        />
      </Grommet>,
    );
    expect(container.firstChild).toMatchSnapshot();

    fireEvent.change(getByPlaceholderText('mm/dd/yyyy-mm/dd/yyyy'), {
      target: { value: '07/21/2020-07/23/2020' },
    });
    expect(onChange).toHaveBeenCalled();
    expect(onChange).toHaveReturnedWith([
      '2020-07-21T08:00:00.000Z',
      '2020-07-23T08:00:00.000Z',
    ]);
    expect(container.firstChild).toMatchSnapshot();
  });

  test('type format inline range without timezone', () => {
    const onChange = jest.fn((event) => event.value);
    const { asFragment, getByPlaceholderText } = render(
      <Grommet>
        <DateInput
          id="item"
          name="item"
          format="mm/dd/yyyy-mm/dd/yyyy"
          defaultValue={DATES_NOTZ}
          inline
          onChange={onChange}
        />
      </Grommet>,
    );
    expect(asFragment()).toMatchSnapshot();

    fireEvent.change(getByPlaceholderText('mm/dd/yyyy-mm/dd/yyyy'), {
      target: { value: '07/21/2020-07/23/2020' },
    });
    expect(onChange).toHaveBeenCalled();
    expect(onChange).toHaveReturnedWith(['2020-07-21', '2020-07-23']);
    expect(asFragment()).toMatchSnapshot();
  });

  test('type format inline range partial', () => {
    const onChange = jest.fn((event) => event.value);
    const { container, getByPlaceholderText } = render(
      <Grommet>
        <DateInput
          id="item"
          name="item"
          format="mm/dd/yyyy-mm/dd/yyyy"
          defaultValue={DATES}
          inline
          onChange={onChange}
        />
      </Grommet>,
    );
    expect(container.firstChild).toMatchSnapshot();

    fireEvent.change(getByPlaceholderText('mm/dd/yyyy-mm/dd/yyyy'), {
      target: { value: '07/21/2020-07' },
    });
    expect(onChange).toHaveNthReturnedWith(1, ['2020-07-21T08:00:00.000Z']);
    expect(container.firstChild).toMatchSnapshot();

    fireEvent.change(getByPlaceholderText('mm/dd/yyyy-mm/dd/yyyy'), {
      target: { value: '07/21/2020-' },
    });
    expect(onChange).toHaveNthReturnedWith(2, ['2020-07-21T08:00:00.000Z']);
    expect(container.firstChild).toMatchSnapshot();

    fireEvent.change(getByPlaceholderText('mm/dd/yyyy-mm/dd/yyyy'), {
      target: { value: '07//2020-07/27/2021' },
    });
    // cannot check snapshot here as it will be relative to the current date

    expect(onChange).toHaveBeenCalledTimes(2);
  });

  test('type format inline range partial without timezone', () => {
    const onChange = jest.fn((event) => event.value);
    const { asFragment, getByPlaceholderText } = render(
      <Grommet>
        <DateInput
          id="item"
          name="item"
          format="mm/dd/yyyy-mm/dd/yyyy"
          defaultValue={DATES_NOTZ}
          inline
          onChange={onChange}
        />
      </Grommet>,
    );
    expect(asFragment()).toMatchSnapshot();

    fireEvent.change(getByPlaceholderText('mm/dd/yyyy-mm/dd/yyyy'), {
      target: { value: '07/21/2020-07' },
    });
    expect(onChange).toHaveNthReturnedWith(1, ['2020-07-21']);
    expect(asFragment()).toMatchSnapshot();

    fireEvent.change(getByPlaceholderText('mm/dd/yyyy-mm/dd/yyyy'), {
      target: { value: '07/21/2020-' },
    });
    expect(onChange).toHaveNthReturnedWith(2, ['2020-07-21']);
    expect(asFragment()).toMatchSnapshot();

    fireEvent.change(getByPlaceholderText('mm/dd/yyyy-mm/dd/yyyy'), {
      target: { value: '07//2020-07/27/2021' },
    });
    // cannot check snapshot here as it will be relative to the current date

    expect(onChange).toHaveBeenCalledTimes(2);
  });

  test('controlled format inline', () => {
    const onChange = jest.fn((event) => event.value);
    const Test = () => {
      const [value, setValue] = React.useState(DATE);
      return (
        <Grommet>
          <DateInput
            id="item"
            name="item"
            format="mm/dd/yyyy"
            value={value}
            inline
            onChange={onChange}
          />
          <Button label="first" onClick={() => setValue(DATE_FIRST)} />
        </Grommet>
      );
    };
    const { container, getByDisplayValue, getByText } = render(<Test />);
    expect(container.firstChild).toMatchSnapshot();

    fireEvent.click(getByText('first'));
    expect(getByDisplayValue('07/01/2020')).not.toBeNull();
    expect(container.firstChild).toMatchSnapshot();
    expect(onChange).not.toHaveBeenCalled();
  });

  test('controlled format inline without timezone', () => {
    const onChange = jest.fn((event) => event.value);
    const Test = () => {
      const [value, setValue] = React.useState(DATE_NOTZ);
      return (
        <Grommet>
          <DateInput
            id="item"
            name="item"
            format="mm/dd/yyyy"
            value={value}
            inline
            onChange={onChange}
          />
          <Button label="first" onClick={() => setValue(DATE_FIRST)} />
        </Grommet>
      );
    };
    const { asFragment, getByDisplayValue, getByText } = render(<Test />);
    expect(asFragment()).toMatchSnapshot();

    fireEvent.click(getByText('first'));
    expect(getByDisplayValue('07/01/2020')).not.toBeNull();
    expect(asFragment()).toMatchSnapshot();
    expect(onChange).not.toHaveBeenCalled();
  });

  test('should be displayed when value is controlled', async () => {
    const Test = () => {
      const [value, setValue] = React.useState<string[] | []>([]);
      return (
        <Grommet>
          <DateInput
            id="item"
            name="item"
            format="mm/dd/yyyy-mm/dd/yyyy"
            value={value}
            inline
          />
          <Button label="Set Date" onClick={() => setValue(DATES)} />
        </Grommet>
      );
    };
    const { container, getByText } = render(<Test />);
    let dateInputValue = (container.querySelector('#item') as HTMLInputElement)
      .value;

    expect(dateInputValue).toEqual('');
    fireEvent.click(getByText('Set Date'));
    dateInputValue = (container.querySelector('#item') as HTMLInputElement)
      .value;
    expect(dateInputValue).toEqual('07/02/2020-07/07/2020');
  });

  test('should be displayed when value is controlled without timezone', async () => {
    const Test = () => {
      const [value, setValue] = React.useState<string[] | []>([]);
      return (
        <Grommet>
          <DateInput
            id="item"
            name="item"
            format="mm/dd/yyyy-mm/dd/yyyy"
            value={value}
            inline
          />
          <Button label="Set Date" onClick={() => setValue(DATES_NOTZ)} />
        </Grommet>
      );
    };
    const { container, getByText } = render(<Test />);
    let dateInputValue = (container.querySelector('#item') as HTMLInputElement)
      .value;

    expect(dateInputValue).toEqual('');
    fireEvent.click(getByText('Set Date'));
    dateInputValue = (container.querySelector('#item') as HTMLInputElement)
      .value;
    expect(dateInputValue).toEqual('07/02/2020-07/07/2020');
  });

  test(`dropProps should pass props to Drop
  when not inline`, () => {
    const { container } = render(
      <Grommet>
        <DateInput
          dropProps={{
            plain: true,
          }}
          format="mm/dd/yyyy"
        />
      </Grommet>,
    );
    expect(container.firstChild).toMatchSnapshot();
  });

  test(`buttonProps should pass props to Button
  when not inline and no format`, () => {
    window.scrollTo = jest.fn();
    const { container } = render(
      <Grommet>
        <DateInput
          buttonProps={{
            disabled: true,
          }}
        />
      </Grommet>,
    );
    expect(container.firstChild).toMatchSnapshot();
  });

  test('disabled', () => {
    const { container } = render(
      <Grommet>
        <DateInput disabled />
      </Grommet>,
    );
    expect(container.firstChild).toMatchSnapshot();
  });

  test('renders size', () => {
    const { container } = render(
      <Grommet>
        <DateInput size="xsmall" />
        <DateInput size="small" />
        <DateInput size="medium" />
        <DateInput size="large" />
        <DateInput size="xlarge" />
        <DateInput size="xxlarge" />
        <DateInput size="2xl" />
        <DateInput size="3xl" />
        <DateInput size="4xl" />
        <DateInput size="5xl" />
        <DateInput size="6xl" />
        <DateInput size="16px" />
        <DateInput size="1rem" />
        <DateInput size="100%" />
      </Grommet>,
    );
    expect(container.children).toMatchSnapshot();
  });

  test('clicking calendar icon should open drop', async () => {
    const user = userEvent.setup();

    render(
      <Grommet>
        <DateInput format="m/d/yy" defaultValue="2021-01-01" />
      </Grommet>,
    );
    expect(
      screen.queryByRole('heading', { name: /January 2021/i }),
    ).not.toBeInTheDocument();
    await user.click(screen.getByRole('button', { name: /Calendar/i }));
    expect(
      screen.getByRole('heading', { name: /January 2021/i }),
    ).toBeInTheDocument();
  });

  test('handle focus in FormField', async () => {
    const user = userEvent.setup();

    const onFocus = jest.fn();
    const { asFragment } = render(
      <Grommet>
        <Form>
          <FormField>
            <DateInput format="mm/dd/yyyy" onFocus={onFocus} />
          </FormField>
        </Form>
      </Grommet>,
    );
    await user.tab();
    expect(asFragment()).toMatchSnapshot();
    await user.tab();
    expect(asFragment()).toMatchSnapshot();
    expect(onFocus).toHaveBeenCalledTimes(1);
  });

  test('icon', () => {
    const { container } = render(
      <DateInput icon={<CalendarIcon color="red" />} name="item" />,
    );
    expect(container.firstChild).toMatchSnapshot();
  });

  test('custom theme', () => {
    const customTheme = {
      dateInput: {
        container: {
          round: 'xsmall',
        },
      },
    };
    const { asFragment } = render(
      <Grommet theme={customTheme}>
        <DateInput format="mm/dd/yyyy" />
      </Grommet>,
    );
    expect(asFragment()).toMatchSnapshot();
  });

  test('matches icon size to size prop when theme.icon.matchSize is true', () => {
    const theme = {
      icon: {
        matchSize: true,
      },
    };

    const { asFragment } = render(
      <Grommet theme={theme}>
        <DateInput size="small" format="mm/dd/yyyy" />
        <DateInput format="mm/dd/yyyy" />
        <DateInput size="large" format="mm/dd/yyyy" />
      </Grommet>,
    );
    expect(asFragment()).toMatchSnapshot();
  });

  test('reseting uncontrolled form should reset text value', async () => {
    const user = userEvent.setup();

    render(
      // onReset e.stopPropagation() is testing to ensure
      // the event won't be lost if caller adds custom reset
      <Form onReset={(e) => e.stopPropagation()}>
        <DateInput format="mm/dd/yyyy" name="date" />
        <Button label="Reset" type="reset" />
      </Form>,
    );
    const input = screen.getByRole('textbox');
    await user.type(input, '09/09/2022');

    expect(input).toHaveValue('09/09/2022');

    await user.click(screen.getByRole('button', { name: 'Reset' }));

    expect(input).toHaveValue('');
  });

  test('read only', () => {
    const { asFragment } = render(
      <Grommet>
        <DateInput
          format="mm/dd/yyyy"
          value="01/01/2024"
          readOnly
          aria-readonly
        />
      </Grommet>,
    );
    expect(asFragment()).toMatchSnapshot();
  });

  test('read only copy', async () => {
    const user = userEvent.setup();

    const { asFragment } = render(
      <Grommet>
        <DateInput
          format="mm/dd/yyyy"
          value="01/01/2024"
          readOnly
          readOnlyCopy
          aria-readonly
        />
      </Grommet>,
    );

    await user.click(screen.getByRole('button'));

    const clipboardText = await navigator.clipboard.readText();
    expect(clipboardText).toBe('01/01/2024');

    expect(asFragment()).toMatchSnapshot();
  });
});