Skip to content
1 change: 1 addition & 0 deletions packages/eui/changelogs/upcoming/9042.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Added `data-test-subj` support to `EuiDatePicker` and `EuiDatePickerRange` for improved testability. Propagates to main component wrappers, inputs, clear buttons, calendar navigation, and popover panels.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
exports[`EuiDatePicker localization accepts the locale prop 1`] = `
<span
class="euiDatePicker testClass1 testClass2 emotion-euiDatePicker-inline-shadow-euiTestCss"
data-test-subj="test subject string"
>
<div
class="euiFormControlLayout emotion-euiFormControlLayout-group"
Expand All @@ -19,6 +20,7 @@ exports[`EuiDatePicker localization accepts the locale prop 1`] = `
<button
aria-label="Previous Month"
class="euiButtonIcon react-datepicker__navigation react-datepicker__navigation--previous emotion-euiButtonIcon-s-empty-text"
data-test-subj="test subject string-calendar-prev-month"
title="Previous Month"
type="button"
>
Expand All @@ -32,6 +34,7 @@ exports[`EuiDatePicker localization accepts the locale prop 1`] = `
<button
aria-label="Next month"
class="euiButtonIcon react-datepicker__navigation react-datepicker__navigation--next emotion-euiButtonIcon-s-empty-text"
data-test-subj="test subject string-calendar-next-month"
title="Next month"
type="button"
>
Expand Down Expand Up @@ -482,6 +485,7 @@ exports[`EuiDatePicker localization accepts the locale prop 1`] = `
exports[`EuiDatePicker localization inherits locale from context 1`] = `
<span
class="euiDatePicker testClass1 testClass2 emotion-euiDatePicker-inline-shadow-euiTestCss"
data-test-subj="test subject string"
>
<div
class="euiFormControlLayout emotion-euiFormControlLayout-group"
Expand All @@ -498,6 +502,7 @@ exports[`EuiDatePicker localization inherits locale from context 1`] = `
<button
aria-label="Previous Month"
class="euiButtonIcon react-datepicker__navigation react-datepicker__navigation--previous emotion-euiButtonIcon-s-empty-text"
data-test-subj="test subject string-calendar-prev-month"
title="Previous Month"
type="button"
>
Expand All @@ -511,6 +516,7 @@ exports[`EuiDatePicker localization inherits locale from context 1`] = `
<button
aria-label="Next month"
class="euiButtonIcon react-datepicker__navigation react-datepicker__navigation--next emotion-euiButtonIcon-s-empty-text"
data-test-subj="test subject string-calendar-next-month"
title="Next month"
type="button"
>
Expand Down Expand Up @@ -961,6 +967,7 @@ exports[`EuiDatePicker localization inherits locale from context 1`] = `
exports[`EuiDatePicker renders 1`] = `
<span
class="euiDatePicker testClass1 testClass2 emotion-euiDatePicker-euiTestCss"
data-test-subj="test subject string"
>
<div
class="euiFormControlLayout emotion-euiFormControlLayout"
Expand All @@ -987,10 +994,12 @@ exports[`EuiDatePicker renders 1`] = `
>
<div
class="react-datepicker__input-container"
data-test-subj="test subject string-input-container"
>
<input
aria-label="Press the down key to open a popover containing a calendar."
class="euiFieldText euiDatePicker testClass1 testClass2 emotion-euiFieldText-controlOnly-euiTestCss"
data-test-subj="test subject string-input"
type="text"
value=""
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ exports[`EuiDatePickerRange is rendered 1`] = `
>
<div
class="euiFormControlLayout__childrenWrapper emotion-euiFormControlLayout__childrenWrapper-inGroup-prependOnly-appendOnly-delimited"
data-test-subj="test subject string-range-wrapper"
>
<div
class="euiFormControlLayoutIcons emotion-euiFormControlLayoutIcons-static"
Expand All @@ -30,10 +31,12 @@ exports[`EuiDatePickerRange is rendered 1`] = `
>
<div
class="react-datepicker__input-container"
data-test-subj="test subject string-start-date-input-container"
>
<input
aria-label="Press the down key to open a popover containing a calendar."
class="euiFieldText euiDatePicker euiDatePickerRange__start euiFormControlLayoutDelimited__input emotion-euiFieldText-controlOnly-euiFormControlLayoutDelimited__input"
data-test-subj="test subject string-start-date-input"
type="text"
value=""
/>
Expand All @@ -53,10 +56,12 @@ exports[`EuiDatePickerRange is rendered 1`] = `
>
<div
class="react-datepicker__input-container"
data-test-subj="test subject string-end-date-input-container"
>
<input
aria-label="Press the down key to open a popover containing a calendar."
class="euiFieldText euiDatePicker euiDatePickerRange__end euiFormControlLayoutDelimited__input emotion-euiFieldText-controlOnly-euiFormControlLayoutDelimited__input"
data-test-subj="test subject string-end-date-input"
type="text"
value=""
/>
Expand Down Expand Up @@ -1549,6 +1554,7 @@ exports[`EuiDatePickerRange uses individual EuiDatePicker props 1`] = `
>
<div
class="euiFormControlLayout__childrenWrapper emotion-euiFormControlLayout__childrenWrapper-inGroup-prependOnly-appendOnly-delimited"
data-test-subj="test subject string-range-wrapper"
>
<div
class="euiFormControlLayoutIcons emotion-euiFormControlLayoutIcons-static"
Expand All @@ -1568,10 +1574,12 @@ exports[`EuiDatePickerRange uses individual EuiDatePicker props 1`] = `
>
<div
class="react-datepicker__input-container"
data-test-subj="test subject string-start-date-input-container"
>
<input
aria-label="Press the down key to open a popover containing a calendar."
class="euiFieldText euiDatePicker euiDatePickerRange__start hello euiFormControlLayoutDelimited__input emotion-euiFieldText-controlOnly-euiFormControlLayoutDelimited__input"
data-test-subj="test subject string-start-date-input"
type="text"
value=""
/>
Expand All @@ -1591,10 +1599,12 @@ exports[`EuiDatePickerRange uses individual EuiDatePicker props 1`] = `
>
<div
class="react-datepicker__input-container"
data-test-subj="test subject string-end-date-input-container"
>
<input
aria-label="Press the down key to open a popover containing a calendar."
class="euiFieldText euiDatePicker euiDatePickerRange__end world euiFormControlLayoutDelimited__input emotion-euiFieldText-controlOnly-euiFormControlLayoutDelimited__input"
data-test-subj="test subject string-end-date-input"
type="text"
value=""
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ const meta: Meta<EuiDatePickerProps> = {
readOnly: false,
selected: null,
utcOffset: undefined,
'data-test-subj': 'my-date-picker',
},
// Open the datepicker automatically for Loki VRT
play: async ({ canvasElement, step }) => {
Expand Down
22 changes: 22 additions & 0 deletions packages/eui/src/components/date_picker/date_picker.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,28 @@ describe('EuiDatePicker', () => {
expect(container.innerHTML).toContain('-compressed');
});

test('data-test-subj', () => {
const { getByTestSubject } = render(
<EuiDatePicker data-test-subj="date-picker-test" />
);

expect(getByTestSubject('date-picker-test')).toBeInTheDocument();
expect(getByTestSubject('date-picker-test-input')).toBeInTheDocument();
});

test('data-test-subj with clear button', () => {
const selected = moment();
const { getByTestSubject } = render(
<EuiDatePicker
data-test-subj="date-picker-test"
selected={selected}
onClear={() => {}}
/>
);

expect(getByTestSubject('date-picker-test-clear')).toBeInTheDocument();
});

test('append/prepend', () => {
const { container, rerender } = render(
<EuiDatePicker append="hello" prepend="world" />
Expand Down
13 changes: 11 additions & 2 deletions packages/eui/src/components/date_picker/date_picker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ export const EuiDatePicker: FunctionComponent<EuiDatePickerProps> = ({
compressed,
controlOnly,
customInput,
'data-test-subj': dataTestSubj,
dateFormat = euiDatePickerDefaultDateFormat,
dayClassName,
disabled,
Expand Down Expand Up @@ -296,6 +297,7 @@ export const EuiDatePicker: FunctionComponent<EuiDatePickerProps> = ({
yearDropdownItemNumber={7}
accessibleMode={!(disabled || readOnly)}
popperPlacement={popoverPlacement}
data-test-subj={dataTestSubj}
{...rest}
/>
);
Expand All @@ -317,11 +319,18 @@ export const EuiDatePicker: FunctionComponent<EuiDatePickerProps> = ({
}

return (
<span css={cssStyles} className={classes}>
<span css={cssStyles} className={classes} data-test-subj={dataTestSubj}>
<EuiFormControlLayout
icon={optionalIcon}
clear={
selected && !disabled && onClear ? { onClick: onClear } : undefined
selected && !disabled && onClear
? {
onClick: onClear,
'data-test-subj': dataTestSubj
? `${dataTestSubj}-clear`
: undefined,
}
: undefined
}
isLoading={isLoading}
isInvalid={isInvalid}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ const meta: Meta<EuiDatePickerRangeProps> = {
disabled: false,
append: '',
prepend: '',
'data-test-subj': 'my-date-range-picker',
},
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,27 @@ describe('EuiDatePickerRange', () => {
});

describe('props', () => {
test('data-test-subj', () => {
const { getByTestSubject } = render(
<EuiDatePickerRange
data-test-subj="date-range-test"
startDateControl={<EuiDatePicker />}
endDateControl={<EuiDatePicker />}
/>
);

expect(getByTestSubject('date-range-test')).toBeInTheDocument();
expect(
getByTestSubject('date-range-test-range-wrapper')
).toBeInTheDocument();
expect(
getByTestSubject('date-range-test-start-date-input')
).toBeInTheDocument();
expect(
getByTestSubject('date-range-test-end-date-input')
).toBeInTheDocument();
});

test('fullWidth', () => {
const { container } = render(
<EuiDatePickerRange
Expand Down
17 changes: 16 additions & 1 deletion packages/eui/src/components/date_picker/date_picker_range.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ export type EuiDatePickerRangeProps = CommonProps &
export const EuiDatePickerRange: FunctionComponent<EuiDatePickerRangeProps> = ({
children,
className,
'data-test-subj': dataTestSubj,
startDateControl,
endDateControl,
iconType = true,
Expand Down Expand Up @@ -159,6 +160,9 @@ export const EuiDatePickerRange: FunctionComponent<EuiDatePickerRangeProps> = ({
'euiDatePickerRange__start',
startDateControl?.props.className
),
'data-test-subj': dataTestSubj
? `${dataTestSubj}-start-date`
: undefined,
onBlur: (event: FocusEvent<HTMLInputElement>) => {
startDateControl?.props?.onBlur?.(event);
onBlur?.(event);
Expand All @@ -185,6 +189,7 @@ export const EuiDatePickerRange: FunctionComponent<EuiDatePickerRangeProps> = ({
'euiDatePickerRange__end',
endDateControl?.props.className
),
'data-test-subj': dataTestSubj ? `${dataTestSubj}-end-date` : undefined,
onBlur: (event: FocusEvent<HTMLInputElement>) => {
endDateControl?.props?.onBlur?.(event);
onBlur?.(event);
Expand All @@ -204,7 +209,12 @@ export const EuiDatePickerRange: FunctionComponent<EuiDatePickerRangeProps> = ({
}, [iconType, inline]);

return (
<div className={classes} css={cssStyles} {...rest}>
<div
className={classes}
css={cssStyles}
data-test-subj={dataTestSubj}
{...rest}
>
<EuiFormControlLayoutDelimited
delimiter={delimiter}
icon={icon}
Expand All @@ -225,6 +235,11 @@ export const EuiDatePickerRange: FunctionComponent<EuiDatePickerRangeProps> = ({
? inlineStyles.formLayout.shadow
: inlineStyles.formLayout.noShadow)
}
wrapperProps={{
'data-test-subj': dataTestSubj
? `${dataTestSubj}-range-wrapper`
: undefined,
}}
/>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -367,9 +367,9 @@ export default class Calendar extends React.Component {
{/* we're using sr-only and aria-hidden here instead of aria-label as aria-label is
not generally applied/read by screen readers for non-semantic element like div */}
<span aria-hidden="true">{weekDayName}</span>
<EuiScreenReaderOnly>
<span>{weekDayNameLong}</span>
</EuiScreenReaderOnly>
<EuiScreenReaderOnly>
<span>{weekDayNameLong}</span>
</EuiScreenReaderOnly>
</div>
);
})
Expand Down Expand Up @@ -421,6 +421,8 @@ export default class Calendar extends React.Component {
clickHandler = null;
}

const dataTestSubj = this.props['data-test-subj'];

return (
<EuiButtonIcon
iconType="sortLeft"
Expand All @@ -431,6 +433,7 @@ export default class Calendar extends React.Component {
disabled={!this.props.accessibleMode}
aria-label={this.props.previousMonthButtonLabel}
title={this.props.previousMonthButtonLabel}
data-test-subj={dataTestSubj ? `${dataTestSubj}-prev-month` : undefined}
/>
);
};
Expand Down Expand Up @@ -473,6 +476,8 @@ export default class Calendar extends React.Component {
clickHandler = null;
}

const dataTestSubj = this.props['data-test-subj'];

return (
<EuiButtonIcon
iconType="sortRight"
Expand All @@ -483,6 +488,7 @@ export default class Calendar extends React.Component {
disabled={!this.props.accessibleMode}
aria-label={this.props.nextMonthButtonLabel}
title={this.props.nextMonthButtonLabel}
data-test-subj={dataTestSubj ? `${dataTestSubj}-next-month` : undefined}
/>
);
};
Expand Down Expand Up @@ -711,6 +717,7 @@ export default class Calendar extends React.Component {

render() {
const Container = this.props.container || CalendarContainer;
const dataTestSubj = this.props['data-test-subj'];

const classes = classnames("react-datepicker", this.props.className, {
"react-datepicker--time-only": this.props.showTimeSelectOnly,
Expand All @@ -724,7 +731,7 @@ export default class Calendar extends React.Component {

if (trapFocus) {
return (
<Container className={classes}>
<Container className={classes} data-test-subj={dataTestSubj}>
<EuiFocusTrap
disabled={this.state.pauseFocusTrap || !this.props.enableFocusTrap}
className="react-datepicker__focusTrap"
Expand All @@ -742,7 +749,7 @@ export default class Calendar extends React.Component {
);
} else {
return (
<Container className={classes}>
<Container className={classes} data-test-subj={dataTestSubj}>
{this.renderPreviousMonthButton()}
{this.renderNextMonthButton()}
{this.renderMonths()}
Expand Down
Loading