Skip to content
Open
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
112 changes: 65 additions & 47 deletions cypress/component/DateTimeInput.cy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,11 @@ describe('<DateInput/>', () => {
cy.mount(
<DateTimeInput
description="date time description"
prevMonthLabel="Previous month"
nextMonthLabel="Next month"
screenReaderLabels={{
calendarIcon: 'Choose date',
prevMonthButton: 'Previous month',
nextMonthButton: 'Next month'
}}
dateRenderLabel="date-input label"
timeRenderLabel="time-input label"
invalidDateTimeMessage="whoops"
Expand All @@ -56,43 +59,40 @@ describe('<DateInput/>', () => {
cy.contains('time-input label')
cy.contains('Thursday, January 18, 2018 1:30 PM')

cy.get('input[id^="Selectable_"]').as('dateInput')
cy.get('input[id^="TextInput_"]').as('dateInput')
cy.get('input[id^="Select_"]').as('timeInput')

cy.get('@dateInput').should('have.value', 'January 18, 2018')
cy.get('@dateInput').should('have.value', '1/18/2018')
cy.get('@timeInput').should('have.value', '1:30 PM')

cy.get('@dateInput').clear().blur()

cy.get('@timeInput').should('have.value', '')
cy.wrap(onChange).should('have.been.called')

cy.get('@dateInput').realClick().wait(100)
cy.contains('button', 'Choose date').realClick().wait(100)

cy.contains('button', '22').realClick().wait(100)

cy.contains('button', '22')
.realClick()
.wait(100)
.then(($btn) => {
const selectedDateId = $btn.attr('id')!
const selectedDateValue = DateTime.parse(
selectedDateId,
cy.wrap(onChange)
.should('have.been.called')
.then((spy) => {
const selectedDateId: string = spy.lastCall.args[1]
Copy link
Copy Markdown
Contributor Author

@ToMESSKa ToMESSKa Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In DateInput v2 no id is set on day buttons, so I get the ISO date from the onChange spy.

const selectedDateValue = new Date(selectedDateId).toLocaleDateString(
'en-US',
'US/Eastern'
).format('LL')
{
timeZone: 'US/Eastern',
calendar: 'gregory',
numberingSystem: 'latn'
}
)

cy.get('@dateInput').should('have.value', selectedDateValue)
cy.get('@timeInput').should('have.value', '4:16 PM')

cy.wrap(onChange)
.should('have.been.called')
.then((spy) => {
const lastCallFirstArg = spy.lastCall.args[1]

const lastCallDatePart = lastCallFirstArg.split('T')[0]
const expectedDatePart = selectedDateId.split('T')[0]
const lastCallDatePart = selectedDateId.split('T')[0]

expect(lastCallDatePart).to.equal(expectedDatePart)
})
expect(lastCallDatePart).to.include('-22')
})
})

Expand All @@ -103,16 +103,19 @@ describe('<DateInput/>', () => {
<DateTimeInput
description="date_time"
dateRenderLabel="date-input"
prevMonthLabel="Previous month"
nextMonthLabel="Next month"
screenReaderLabels={{
calendarIcon: 'Open calendar',
prevMonthButton: 'Previous month',
nextMonthButton: 'Next month'
}}
timeRenderLabel="time-input"
invalidDateTimeMessage="whoops"
locale="en-US"
timezone="US/Eastern"
onChange={onChange}
/>
)
cy.get('input[id^="Selectable_"]').as('dateInput')
cy.get('input[id^="TextInput_"]').as('dateInput')
cy.get('@dateInput').realClick().wait(100)
cy.get('@dateInput').type('Not a date{enter}')
cy.get('@dateInput').blur()
Expand All @@ -128,8 +131,11 @@ describe('<DateInput/>', () => {
cy.mount(
<DateTimeInput
description="date_time"
prevMonthLabel="Previous month"
nextMonthLabel="Next month"
screenReaderLabels={{
calendarIcon: 'Open calendar',
prevMonthButton: 'Previous month',
nextMonthButton: 'Next month'
}}
dateRenderLabel="date-input"
timeRenderLabel="time-input"
invalidDateTimeMessage="whoops"
Expand All @@ -140,9 +146,9 @@ describe('<DateInput/>', () => {
disabledDateTimeMessage={errorMsg}
/>
)
cy.get('input[id^="Selectable_"]').as('dateInput')
cy.get('input[id^="TextInput_"]').as('dateInput')
cy.get('body').should('contain', errorMsg)
cy.get('@dateInput').clear().type(`05/18/2017{enter}`)
cy.get('@dateInput').clear().type(`05/18/2017`).blur()
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DateInput v1 had an Enter key handler. In v2 there's no such handler, so the .blur() is used.


cy.get('body').should('not.contain', errorMsg)
})
Expand All @@ -160,8 +166,11 @@ describe('<DateInput/>', () => {
cy.mount(
<DateTimeInput
description="date_time"
prevMonthLabel="Previous month"
nextMonthLabel="Next month"
screenReaderLabels={{
calendarIcon: 'Open calendar',
prevMonthButton: 'Previous month',
nextMonthButton: 'Next month'
}}
dateRenderLabel="date-input"
timeRenderLabel="time-input"
invalidDateTimeMessage="whoops"
Expand All @@ -172,9 +181,9 @@ describe('<DateInput/>', () => {
disabledDateTimeMessage={errorMsg}
/>
)
cy.get('input[id^="Selectable_"]').as('dateInput')
cy.get('input[id^="TextInput_"]').as('dateInput')
cy.get('body').should('contain', errorMsgText)
cy.get('@dateInput').clear().type(`May 18, 2022{enter}`)
cy.get('@dateInput').clear().type(`May 18, 2022`).blur()

cy.get('body').should('not.contain', errorMsgText)
})
Expand All @@ -187,8 +196,11 @@ describe('<DateInput/>', () => {
const props = {
description: 'date_time',
dateRenderLabel: 'date-input',
prevMonthLabel: 'Previous month',
nextMonthLabel: 'Next month',
screenReaderLabels: {
calendarIcon: 'Open calendar',
prevMonthButton: 'Previous month',
nextMonthButton: 'Next month'
},
timeRenderLabel: 'time-input',
invalidDateTimeMessage: 'whoops',
locale,
Expand All @@ -197,10 +209,10 @@ describe('<DateInput/>', () => {

cy.mount(<DateTimeInput {...props} value={dateTime.toISOString()} />)

cy.get('input[id^="Selectable_"]').as('dateInput')
cy.get('input[id^="TextInput_"]').as('dateInput')
cy.get('input[id^="Select_"]').as('timeInput')

cy.get('@dateInput').should('have.value', 'May 1, 2017')
cy.get('@dateInput').should('have.value', '5/1/2017')
cy.get('@timeInput').should('have.value', '1:30 PM')
cy.get('body').should('contain', 'May 1, 2017 1:30 PM')

Expand All @@ -215,11 +227,11 @@ describe('<DateInput/>', () => {
const newDateStr = '2022-03-29T19:00Z'
cy.mount(<DateTimeInput {...props} value={newDateStr} />)

cy.get('@dateInput').should('have.value', 'March 29, 2022')
cy.get('@dateInput').should('have.value', '3/29/2022')
cy.get('@timeInput').should('have.value', '3:00 PM')
cy.get('body').should('contain', 'March 29, 2022 3:00 PM')

cy.get('@dateInput').clear().type('{esc}')
cy.get('@dateInput').clear().blur()

cy.get('@dateInput').should('have.value', '')
cy.get('@timeInput').should('have.value', '')
Expand All @@ -234,8 +246,11 @@ describe('<DateInput/>', () => {
<DateTimeInput
description="date_time"
dateRenderLabel="date-input"
prevMonthLabel="Previous month"
nextMonthLabel="Next month"
screenReaderLabels={{
calendarIcon: 'Open calendar',
prevMonthButton: 'Previous month',
nextMonthButton: 'Next month'
}}
timeRenderLabel="time-input"
invalidDateTimeMessage="whoops"
locale="en-US"
Expand All @@ -244,12 +259,12 @@ describe('<DateInput/>', () => {
allowNonStepInput={true}
/>
)
cy.get('input[id^="Selectable_"]').as('dateInput')
cy.get('input[id^="TextInput_"]').as('dateInput')
cy.get('input[id^="Select_"]').as('timeInput')

cy.get('@timeInput').clear().type(`7:34 PM`)

cy.get('@dateInput').clear().type(`May 1, 2017{enter}`)
cy.get('@dateInput').clear().type(`May 1, 2017`).blur()

cy.wrap(onChange)
.should('have.been.called')
Expand All @@ -268,16 +283,19 @@ describe('<DateInput/>', () => {
<DateTimeInput
description="date_time"
dateRenderLabel="date-input"
prevMonthLabel="Previous month"
nextMonthLabel="Next month"
screenReaderLabels={{
calendarIcon: 'Open calendar',
prevMonthButton: 'Previous month',
nextMonthButton: 'Next month'
}}
timeRenderLabel="time-input"
invalidDateTimeMessage="whoops"
locale={locale}
timezone={timezone}
initialTimeForNewDate="05:05"
/>
)
cy.get('input[id^="Selectable_"]').as('dateInput')
cy.get('input[id^="TextInput_"]').as('dateInput')
cy.get('input[id^="Select_"]').as('timeInput')

cy.get('@dateInput').clear().type(`May 1, 2017{enter}`)
Expand Down
48 changes: 48 additions & 0 deletions docs/guides/upgrade-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,54 @@ Now that InstUI supports component versioning, we no longer need the separate `D
- **[DateInput v1](/v11_6/DateInput)** (up to v11.6) — the original component. **Deprecated.** Does not support the new theming system.
- **[DateInput2 v1](/v11_6/DateInput2)** — **Deprecated.** Will not get a v2 and does not support the new theming system. If you're using `DateInput2`, switch your import to `DateInput` (from v11.7) — the API is identical, no other code changes needed.

### DateTimeInput

<!-- TODO: add a codemod for the removed/renamed props (prevMonthLabel, nextMonthLabel → screenReaderLabels) -->

**Removed props:**

| Removed prop | Replacement |
| --------------------- | ------------------------------------ |
| `renderWeekdayLabels` | Built in — no replacement needed |
| `prevMonthLabel` | `screenReaderLabels.prevMonthButton` |
| `nextMonthLabel` | `screenReaderLabels.nextMonthButton` |

**Changed props:**

| Prop | old API | new API |
| ------------ | ------------------------------------- | --------------------------------------------------------- |
| `dateFormat` | Moment.js format string (e.g. `'LL'`) | Locale string (e.g. `'en-US'`) or `{ parser, formatter }` |

If you were passing a Moment format string like `dateFormat="LL"`, replace it with a locale string or a custom `{ parser, formatter }` object. If you were relying on the default `'LL'` format, note that v2 now uses the locale's default date format (e.g. `1/18/2018` in `en-US`) instead of the long format (e.g. `January 18, 2018`). To preserve the long format, pass a custom `{ parser, formatter }` object.

**New props:**

| New prop | Description |
| -------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| `screenReaderLabels` | **Required.** Object containing accessible labels: `calendarIcon`, `prevMonthButton`, `nextMonthButton`, `datePickerDialog?`. |
| `withYearPicker` | Optional. Enables a year dropdown in the calendar. |

```js
---
type: code
---
// old API
<DateTimeInput
prevMonthLabel="Previous month"
nextMonthLabel="Next month"
/>

// new API
<DateTimeInput
screenReaderLabels={{
calendarIcon: 'Open calendar',
prevMonthButton: 'Previous month',
nextMonthButton: 'Next month',
datePickerDialog: 'Date picker' // optional
}}
/>
```

### DataPermissionLevels

```js
Expand Down
20 changes: 10 additions & 10 deletions packages/ui-date-time-input/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,18 +72,18 @@
"default": "./es/exports/a.js"
},
"./v11_7": {
"src": "./src/exports/a.ts",
"types": "./types/exports/a.d.ts",
"import": "./es/exports/a.js",
"require": "./lib/exports/a.js",
"default": "./es/exports/a.js"
"src": "./src/exports/b.ts",
"types": "./types/exports/b.d.ts",
"import": "./es/exports/b.js",
"require": "./lib/exports/b.js",
"default": "./es/exports/b.js"
},
"./latest": {
"src": "./src/exports/a.ts",
"types": "./types/exports/a.d.ts",
"import": "./es/exports/a.js",
"require": "./lib/exports/a.js",
"default": "./es/exports/a.js"
"src": "./src/exports/b.ts",
"types": "./types/exports/b.d.ts",
"import": "./es/exports/b.js",
"require": "./lib/exports/b.js",
"default": "./es/exports/b.js"
}
}
}
Loading
Loading