Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(DatePicker): Migrate to react-day-picker v8 #3001

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ import { describe, cy, it, before } from 'local-cypress'
import { addDays, startOfMonth, format } from 'date-fns'
import { ColorNeutral200 } from '@defencedigital/design-tokens'

import { formatDatesForInput } from '../../../src/components/DatePicker/utils'
import { DATE_FORMAT } from '../../../src/constants'
import { hexToRgb } from '../../helpers'
import selectors from '../../selectors'
import { formatDatesForInput } from '../../../src/components/DatePicker/utils/formatDatesForInput'

describe('DatePicker', () => {
describe('when a day is selected', () => {
Expand All @@ -23,9 +23,7 @@ describe('DatePicker', () => {

describe('and the first day is clicked', () => {
before(() => {
cy.get(selectors.datePicker.day.inside)
.contains('1')
.click({ force: true })
cy.get(selectors.datePicker.day).contains('1').click({ force: true })
})

it('should set the value of the input to the date', () => {
Expand All @@ -47,7 +45,7 @@ describe('DatePicker', () => {

describe('when a range is selected', () => {
before(() => {
cy.visit('/iframe.html?id=date-picker--range&viewMode=story')
cy.visit('/iframe.html?id=date-picker-experimental--range&viewMode=story')

cy.get(selectors.datePicker.input).click()
})
Expand All @@ -58,7 +56,7 @@ describe('DatePicker', () => {

describe('and the `from` day is clicked', () => {
before(() => {
cy.get(selectors.datePicker.day.inside).contains('1').click()
cy.get(selectors.datePicker.day).contains('1').click()
})

it('should set the value of the input to the date', () => {
Expand All @@ -72,7 +70,7 @@ describe('DatePicker', () => {

describe('and the `to` day is clicked', () => {
before(() => {
cy.get(selectors.datePicker.day.inside).contains('10').click()
cy.get(selectors.datePicker.day).contains('10').click()
})

it('should set the value of the input to the range', () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
export default {
button: '[data-testid="datepicker-input-button"]',
day: {
inside: '.DayPicker-Day:not(.DayPicker-Day--outside)',
},
day: '.rdp_day',
floatingBox: '[data-testid="floating-box"]',
input: '[data-testid="datepicker-input"]',
outerWrapper: '[data-testid="datepicker-outer-wrapper"]',
Expand Down
2 changes: 1 addition & 1 deletion packages/react-component-library/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@
"lodash": "^4.17.21",
"polished": "^4.0.3",
"react-compound-slider": "^3.3.1",
"react-day-picker": "^7.4.8",
"react-day-picker": "^8.0.4",
"react-merge-refs": "^1.1.0",
"react-popper": "^2.2.5",
"react-select": "^4.1.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ const NOW = '2019-12-05T11:00:00.000Z'
const ERROR_BOX_SHADOW = `0 0 0 ${
BORDER_WIDTH[COMPONENT_SIZE.FORMS]
} ${ColorDanger800.toUpperCase()}`
const PREVIOUS_MONTH_BUTTON_LABEL = 'Go to previous month'
const NEXT_MONTH_BUTTON_LABEL = 'Go to next month'

function formatDate(date: Date | null) {
return date && isValid(date) ? format(date, 'dd/MM/yyyy') : ''
Expand All @@ -32,7 +34,6 @@ describe('DatePicker', () => {
let initialStartDate: Date
let label: string
let onBlur: (e: React.FormEvent) => void
let onCalendarFocus: jest.Mock<void, [React.SyntheticEvent]>
let days: string[]
let onSubmitSpy: (e: React.FormEvent) => void
const onChange = jest.fn<void, [DatePickerOnChangeData]>()
Expand Down Expand Up @@ -75,15 +76,13 @@ describe('DatePicker', () => {
beforeEach(() => {
initialStartDate = new Date(2019, 11, 1)
onBlur = jest.fn()
onCalendarFocus = jest.fn<void, [React.SyntheticEvent]>()

wrapper = render(
<>
<DatePicker
initialStartDate={initialStartDate}
onChange={onChange}
onBlur={onBlur}
onCalendarFocus={onCalendarFocus}
/>
<div data-testid="datepicker-outside" />
</>
Expand Down Expand Up @@ -166,7 +165,9 @@ describe('DatePicker', () => {

it('colours the current date', () => {
return waitFor(() => {
expect(wrapper.getByText(/^5$/)).toHaveStyle({
expect(
wrapper.getByRole('button', { name: '5th December (Thursday)' })
).toHaveStyle({
color: ColorWarning800,
})
})
Expand Down Expand Up @@ -296,13 +297,13 @@ describe('DatePicker', () => {

describe('and the tab key is pressed again', () => {
beforeEach(() => {
onCalendarFocus.mockClear()
return user.tab()
})

it('focuses the picker container', () => {
expect(onCalendarFocus).toHaveBeenCalledTimes(1)
// NOTE: `react-day-picker` internals from here on down
it('focuses the previous month button', () => {
expect(
wrapper.getByLabelText(PREVIOUS_MONTH_BUTTON_LABEL)
).toHaveFocus()
})
})

Expand Down Expand Up @@ -611,6 +612,22 @@ describe('DatePicker', () => {
})
})

describe('when a single date picker with a value is rendered and the picker is opened', () => {
beforeEach(() => {
wrapper = render(
<DatePicker startDate={new Date('2022-01-18T00:00:00Z')} />
)

return user.click(wrapper.getByTestId('datepicker-input-button'))
})

it('focuses the current date', () => {
expect(
wrapper.getByRole('button', { name: '18th January (Tuesday)' })
).toHaveFocus()
})
})

describe('when a single date picker is rendered and the picker is opened', () => {
beforeEach(() => {
wrapper = render(<DatePicker />)
Expand All @@ -622,20 +639,21 @@ describe('DatePicker', () => {
expect(wrapper.getByText('December 2019')).toBeInTheDocument()
})

it('focuses the previous month button', () => {
return waitFor(() =>
expect(wrapper.getByLabelText('Previous Month')).toHaveFocus()
)
it('focuses the current date', () => {
expect(
wrapper.getByRole('button', { name: '5th December (Thursday)' })
).toHaveFocus()
})

describe('when Shift-Tab is pressed twice', () => {
describe('when Shift-Tab is pressed once', () => {
beforeEach(async () => {
await user.tab({ shift: true })
await user.tab({ shift: true })
})

it('traps the focus within the picker', () => {
expect(wrapper.getByText('1')).toHaveFocus()
expect(
wrapper.getByLabelText(PREVIOUS_MONTH_BUTTON_LABEL)
).toHaveFocus()
})

describe('and Tab is then pressed once', () => {
Expand All @@ -644,26 +662,22 @@ describe('DatePicker', () => {
})

it('still traps the focus within the picker', () => {
const dayPicker =
wrapper.container.querySelectorAll('.DayPicker-wrapper')[0]
expect(dayPicker).toHaveFocus()
expect(
wrapper.getByRole('button', { name: '5th December (Thursday)' })
).toHaveFocus()
})
})
})

describe.each([
{
name: 'day picker container',
selector: () =>
wrapper.container.querySelectorAll('.DayPicker-wrapper')[0],
},
{
name: 'previous month button',
selector: () => wrapper.getByLabelText('Previous Month'),
selector: () => wrapper.getByLabelText(PREVIOUS_MONTH_BUTTON_LABEL),
},
{
name: 'day picker day',
selector: () => wrapper.getByText(10),
selector: () =>
wrapper.getByRole('button', { name: '10th December (Tuesday)' }),
},
])('when the escape key is pressed in $name', ({ selector }) => {
beforeEach(() => {
Expand All @@ -685,7 +699,7 @@ describe('DatePicker', () => {

describe('when the next month button is clicked', () => {
beforeEach(() => {
return user.click(wrapper.getByLabelText('Next Month'))
return user.click(wrapper.getByLabelText(NEXT_MONTH_BUTTON_LABEL))
})

it('displays the next month', () => {
Expand Down Expand Up @@ -782,15 +796,16 @@ describe('DatePicker', () => {
it('shades the date range', () => {
expect(
wrapper.getAllByText(/^10|11|12|13$/, {
selector: '.DayPicker-Day--selected',
selector: '.rdp-day_selected span',
ignore: '[class=rdp-vhidden]',
})
).toHaveLength(4)
})

it("doesn't shade dates outside the range", () => {
expect(
wrapper.queryAllByText(/^(?!(10|11|12|13))\d\d$/, {
selector: '.DayPicker-Day--selected',
selector: '.rdp-day_selected span',
})
).toHaveLength(0)
})
Expand All @@ -816,18 +831,32 @@ describe('DatePicker', () => {
it('shades the date range', () => {
expect(
wrapper.getAllByText(/^10|11|12|13$/, {
selector: '.DayPicker-Day--selected',
selector: '.rdp-day_selected span',
ignore: '[class=rdp-vhidden]',
})
).toHaveLength(4)
})

it("doesn't shade dates outside the range", () => {
expect(
wrapper.queryAllByText(/^(?!(10|11|12|13))\d\d$/, {
selector: '.DayPicker-Day--selected',
selector: '.rdp-day_selected span',
})
).toHaveLength(0)
})

describe('and then presses the tab key', () => {
beforeEach(() => {
userEvent.tab()
})

it('clears the range and removes the shading', () => {
// The start date still has the modifier
expect(
wrapper.container.querySelectorAll('.rdp-day_selected')
).toHaveLength(1)
})
})
})

describe('and clicks on a second date', () => {
Expand Down Expand Up @@ -977,13 +1006,17 @@ describe('DatePicker', () => {
})

it('colours the override date', () => {
expect(wrapper.getByText(/^15$/)).toHaveStyle({
expect(
wrapper.getByRole('button', { name: '15th December (Sunday)' })
).toHaveStyle({
color: ColorWarning800,
})
})

it('does not colour the actual current date', () => {
expect(wrapper.getByText(/^5$/)).not.toHaveStyle({
expect(
wrapper.getByRole('button', { name: '5th December (Thursday)' })
).not.toHaveStyle({
color: ColorWarning800,
})
})
Expand Down Expand Up @@ -1035,12 +1068,17 @@ describe('DatePicker', () => {
})

it('applies the disabled modifier class to the correct days', () => {
expect(wrapper.getByText('12')).toHaveClass('DayPicker-Day--disabled')
expect(
wrapper.getByRole('button', { name: '12th April (Sunday)' })
).toHaveClass('rdp-day_disabled')
})

describe('and a disabled day is clicked', () => {
beforeEach(() => {
return userEvent.click(wrapper.getByText('12'), {
const button = wrapper.getByRole('button', {
name: '12th April (Sunday)',
})
return userEvent.click(button, {
pointerEventsCheck: PointerEventsCheckLevel.Never,
advanceTimers: jest.advanceTimersByTime,
})
Expand Down
Loading