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

fix: Reannounce validation error in date range picker on apply #3210

Merged
merged 2 commits into from
Feb 4, 2025
Merged
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
59 changes: 58 additions & 1 deletion src/date-range-picker/__tests__/date-range-picker.test.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import * as React from 'react';
import { render } from '@testing-library/react';
import { render, waitFor } from '@testing-library/react';
import Mockdate from 'mockdate';

import { warnOnce } from '@cloudscape-design/component-toolkit/internal';
Expand Down Expand Up @@ -313,6 +313,63 @@ describe('Date range picker', () => {
changeMode(wrapper, 'relative');
expect(wrapper.findDropdown()!.findValidationError()).toBeNull();
});

test('reannounces error text when apply is clicked', async () => {
Mockdate.set(new Date('2020-01-01T12:30:20'));
({ wrapper } = renderDateRangePicker({
...defaultProps,
isValidRange: value => {
if (value === null) {
return {
valid: false,
errorMessage: 'No range selected',
};
}
if (value.type === 'relative' && value.amount === 10) {
return { valid: false, errorMessage: '10 is not allowed.' };
}
if (value.type === 'absolute') {
const [endDateWithoutTime] = value.endDate.split('T');

if (!endDateWithoutTime) {
return {
valid: false,
errorMessage: 'You must provide an end date',
};
}

if (value.startDate < '2020-01-01T00:00:00') {
return {
valid: false,
errorMessage: 'The range cannot start before 2020',
};
}
}
return { valid: true };
},
}));
wrapper.openDropdown();
changeMode(wrapper, 'absolute');
wrapper.findDropdown()?.findDateAt('left', 1, 1).click();
wrapper.findDropdown()!.findApplyButton().click();

const liveRegion = document.querySelectorAll('[aria-live=polite]')![3];

// announces first validation error
await waitFor(() => expect(liveRegion).toHaveTextContent('You must provide an end date'));

wrapper.findDropdown()?.findDateAt('left', 1, 3).click();

// announces different validation error
await waitFor(() => expect(liveRegion).toHaveTextContent('The range cannot start before 2020'));

wrapper.findDropdown()!.findApplyButton().click();

// reannounces second validation error
await waitFor(() => expect(liveRegion).toHaveTextContent('The range cannot start before 2020.'));

Mockdate.reset();
});
});

describe('change event', () => {
Expand Down
6 changes: 4 additions & 2 deletions src/date-range-picker/dropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { ButtonProps } from '../button/interfaces';
import { InternalButton } from '../button/internal';
import { useInternalI18n } from '../i18n/context';
import FocusLock from '../internal/components/focus-lock';
import InternalLiveRegion from '../live-region/internal';
import InternalLiveRegion, { InternalLiveRegionRef } from '../live-region/internal';
import InternalSpaceBetween from '../space-between/internal';
import Calendar from './calendar';
import { DateRangePickerProps } from './interfaces';
Expand Down Expand Up @@ -84,6 +84,7 @@ export function DateRangePickerDropdown({
const i18n = useInternalI18n('date-range-picker');
const isMonthPicker = granularity === 'month';
const hideTime = dateOnly || isMonthPicker;
const liveRegionRef = useRef<InternalLiveRegionRef>(null);

const [rangeSelectionMode, setRangeSelectionMode] = useState<'absolute' | 'relative'>(
getDefaultMode(value, relativeOptions, rangeSelectorMode)
Expand Down Expand Up @@ -123,6 +124,7 @@ export function DateRangePickerDropdown({
if (newValidationResult.valid === false) {
setApplyClicked(true);
setValidationResult(newValidationResult);
liveRegionRef.current?.reannounce();
} else {
setApplyClicked(false);
closeDropdown();
Expand Down Expand Up @@ -230,7 +232,7 @@ export function DateRangePickerDropdown({
>
<span className={testutilStyles['validation-error']}>{validationResult.errorMessage}</span>
</InternalAlert>
<InternalLiveRegion hidden={true} tagName="span">
<InternalLiveRegion hidden={true} tagName="span" ref={liveRegionRef}>
{validationResult.errorMessage}
</InternalLiveRegion>
</>
Expand Down
Loading