Skip to content

feat: datetimepicker validation improvements #8986

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

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

ugur-vaadin
Copy link
Contributor

@ugur-vaadin ugur-vaadin commented Apr 19, 2025

Description

  • Adds unparsable-change event for the web component.
  • Handles the case where one of the fields is still empty. Validates if
    • the new value in the edited field is unparsable
    • the edited field is date picker and the date is out of range set using min and/or max
  • improves validation consistency. Except for cases where the the edited field is valid after the edit and the DateTimePicker is still being edited, the validation behaves the same for Enter, outside click, and blur.
  • Adds tests that verify the validation logic and change events using combinations of initial states and field updates.

Based on the prototype implementation.

Part of #6697.

Type of change

  • Bugfix
  • Feature

Checklist

  • I have read the contribution guide: https://vaadin.com/docs/latest/contributing/pr
  • I have added a description following the guideline.
  • The issue is created in the corresponding repository and I have referenced it.
  • I have added tests to ensure my change is effective and works as intended.
  • New and existing tests are passing locally with my change.
  • I have performed self-review and corrected misspellings.
  • Enhancement / new feature was discussed in a corresponding GitHub issue and Acceptance Criteria were created.

};

export const individualPickerUpdateTestSetup = (individualPickerTest) => {
['date-picker', 'time-picker'].forEach((pickerType) => {
Copy link
Contributor

@vursen vursen Apr 25, 2025

Choose a reason for hiding this comment

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

Would it be possible to simplify or restructure these tests somehow to improve readability? The deep nesting is making it tricky to understand the test cases. Maybe it would be easier to follow if the tests were more explicit, even if it would lead to some duplication.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I started with that approach, but it seemed to bloat the tests by quite a lot. But I don't have a strong opinion, and if you think it is hard to read I can change it. Maybe we can keep ['date-picker', 'time-picker'].forEach(...) and explicitly add tests for different states&updates. What do you think?

Copy link
Contributor

@vursen vursen Apr 25, 2025

Choose a reason for hiding this comment

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

Maybe we can keep ['date-picker', 'time-picker'].forEach(...) and explicitly add tests for different states&updates

This might help! Let's give it a try. While this would increase bloat, it should simplify debugging in the future.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Separated the tests.

@ugur-vaadin ugur-vaadin requested a review from yuriy-fix April 25, 2025 07:15
@vursen
Copy link
Contributor

vursen commented Apr 29, 2025

Looks like this change and this change together break required validation on blur, which works in other components:

Screen.Recording.2025-04-29.at.14.36.43.mov

Comment on lines +103 to +110
* empty => parsable | change
* empty => unparsable | unparsable-change
* parsable => empty | change
* parsable => parsable | change
* parsable => unparsable | change
* unparsable => empty | unparsable-change
* unparsable => parsable | change
* unparsable => unparsable | unparsable-change
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd suggest including the incomplete scenario in this list separately.

* @fires {Event} change - Fired when the user commits a value change.
* @fires {Event} unparsable-change - Fired when the user commits an unparsable value change and there is no change event.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
* @fires {Event} unparsable-change - Fired when the user commits an unparsable value change and there is no change event.
* @fires {Event} unparsable-change - Fired when the user commits an unparsable or incomplete value change and there is no change event.

@@ -60,16 +60,395 @@ const fixtures = {
expect(dateTimePicker.invalid).to.equal(false);
});

it('should validate on date-picker blur', () => {
['date-picker', 'time-picker'].forEach((pickerType) => {
Copy link
Contributor

Choose a reason for hiding this comment

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

Let's create a value-commit.test.js file and move all new tests there. Validation and change events are both part of the value commit flow, so testing them together in one place would make sense. Example:

function expectNoValueCommit() {
expect(valueChangedSpy).to.be.not.called;
expect(validateSpy).to.be.not.called;
expect(changeSpy).to.be.not.called;
}
function expectValueCommit(value) {
expect(valueChangedSpy).to.be.calledOnce;
// TODO: Optimize the number of validation runs.
expect(validateSpy).to.be.called;
expect(validateSpy.firstCall).to.be.calledAfter(valueChangedSpy.firstCall);
expect(unparsableChangeSpy).to.be.not.called;
expect(changeSpy).to.be.calledOnce;
expect(changeSpy.firstCall).to.be.calledAfter(validateSpy.firstCall);
expect(datePicker.value).to.equal(value);
}
function expectUnparsableValueCommit() {
expect(valueChangedSpy).to.be.not.called;
// TODO: Optimize the number of validation runs.
expect(validateSpy).to.be.called;
expect(changeSpy).to.be.not.called;
expect(unparsableChangeSpy).to.be.calledOnce;
expect(unparsableChangeSpy).to.be.calledAfter(validateSpy);
}
function expectValidationOnly() {
expect(valueChangedSpy).to.be.not.called;
// TODO: Optimize the number of validation runs.
expect(validateSpy).to.be.called;
expect(changeSpy).to.be.not.called;
}

this.__committedUnparsableValue = this.__unparsableValue;
}

get __hasPendingValueChange() {
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
get __hasPendingValueChange() {
/** @private */
get __hasPendingValueChange() {

@@ -315,12 +316,37 @@ export const DateTimePickerMixin = (superClass) =>
return [this.__datePicker, this.__timePicker];
}

get __filledPickers() {
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
get __filledPickers() {
/** @private */
get __filledPickers() {

@ugur-vaadin
Copy link
Contributor Author

Looks like this change and this change together break required validation on blur, which works in other components:

Screen.Recording.2025-04-29.at.14.36.43.mov

I think that is my misunderstanding rather than an implementation error. My understanding was that the validation should not run when the component is blurred with no change to the input even if it is required.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants