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
142 changes: 142 additions & 0 deletions packages/@adobe/react-spectrum/test/datepicker/DateField.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -764,6 +764,104 @@ describe('DateField', function () {
await user.tab();
expect(getDescription()).not.toContain('Constraints not satisfied');
Comment thread
AKnassa marked this conversation as resolved.
});

it('should signal valueMissing when a complete date is made partial by clearing a segment (Bug #9624)', async () => {
// Regression (per devongovett's direction in #9624): a partially-filled required
// DateField should be marked invalid on blur. onChange(null) is deliberately NOT
// fired for partial values; getValidationResult compensates by surfacing the
// localized "Please enter a value." message via builtinValidation.
let {getByRole} = render(
<Provider theme={theme}>
<Form data-testid="form">
<DateField label="Date" name="date" isRequired validationBehavior="native" />
</Form>
</Provider>
);

let group = getByRole('group');
let input = document.querySelector('input[name=date]');

// Fill a complete valid date: 4/28/2026
await user.tab();
await user.keyboard('4');
await user.keyboard('28');
await user.keyboard('2026');
expect(input.validity.valid).toBe(true);

// Refocus the month and clear it
let segments = within(group).getAllByRole('spinbutton');
act(() => {
segments[0].focus();
});
await user.keyboard('{Backspace}');
expect(segments[0]).toHaveAttribute('aria-valuetext', 'Empty');

// Tab forward past day and year to exit the group
await user.tab();
await user.tab();
await user.tab();

// The hidden input should reflect missing value and validation should surface
expect(input.validity.valid).toBe(false);
let getDescription = () =>
(group.getAttribute('aria-describedby') || '')
.split(' ')
.map(d => document.getElementById(d)?.textContent || '')
.join(' ');
expect(getDescription()).toContain('Please enter a value.');

// Re-focus month and complete the date with a different valid value
act(() => {
segments[0].focus();
});
await user.keyboard('5');
await user.tab();
await user.tab();
await user.tab();

expect(input.validity.valid).toBe(true);
expect(getDescription()).not.toContain('Please enter a value.');
});

it('should signal validation for partial values regardless of isRequired (Bug #9958)', async () => {
// partial values are flagged invalid even without isRequired so that
// min/max/unavailable/validate configurations also block submission.
let {getByRole} = render(
<Provider theme={theme}>
<Form>
<DateField
label="Date"
name="date"
minValue={new CalendarDate(2020, 1, 1)}
defaultValue={new CalendarDate(2026, 4, 28)}
validationBehavior="native"
/>
</Form>
</Provider>
);

let group = getByRole('group');
let input = document.querySelector('input[name=date]');
let segments = within(group).getAllByRole('spinbutton');

act(() => {
segments[0].focus();
});
await user.keyboard('{Backspace}');
await user.keyboard('{Backspace}');
expect(segments[0]).toHaveAttribute('aria-valuetext', 'Empty');

await user.tab();
await user.tab();
await user.tab();

expect(input.validity.valid).toBe(false);
let description = (group.getAttribute('aria-describedby') || '')
.split(' ')
.map(d => document.getElementById(d)?.textContent || '')
.join(' ');
expect(description).toContain('Please enter a value.');
});
});

describe('validationBehavior=aria', () => {
Expand Down Expand Up @@ -850,6 +948,50 @@ describe('DateField', function () {
await user.keyboard('[Tab][ArrowRight][ArrowRight]2024[Tab]');
expect(getDescription()).not.toContain('Invalid value');
});

it('should clear the hidden input value when partial in aria mode (Bug #9624)', async () => {
// Aria-mode counterpart to the native-mode #9624 regression: the hidden input must
// reflect the partial display state regardless of validationBehavior so any consumer
// (e.g. FormData) sees the missing value.
let {getByRole} = render(
<Provider theme={theme}>
<Form>
<DateField
label="Date"
name="date"
isRequired
validationBehavior="aria"
defaultValue={new CalendarDate(2026, 4, 28)}
/>
</Form>
</Provider>
);

let group = getByRole('group');
let input = document.querySelector('input[name=date]');
expect(input).toHaveValue('2026-04-28');

let segments = within(group).getAllByRole('spinbutton');
act(() => {
segments[0].focus();
});
await user.keyboard('{Backspace}');
expect(segments[0]).toHaveAttribute('aria-valuetext', 'Empty');

expect(input).toHaveValue('');
let description = (group.getAttribute('aria-describedby') || '')
.split(' ')
.map(d => document.getElementById(d)?.textContent || '')
.join(' ');
expect(description).toContain('Please enter a value.');

await user.keyboard('5');
await user.tab();
await user.tab();
await user.tab();
expect(input).toHaveValue('2026-05-28');
expect(description).not.toContain('Please enter a value.');
});
});
});
});
Expand Down
Loading