Skip to content

Commit d19e809

Browse files
committed
fix(validator): validator report customError. Fix #5302
1 parent 839667d commit d19e809

File tree

2 files changed

+78
-8
lines changed

2 files changed

+78
-8
lines changed

labs/behaviors/constraint-validation.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ export function mixinConstraintValidation<
235235
const {validity, validationMessage: nonCustomValidationMessage} =
236236
this[privateValidator].getValidity();
237237

238-
const customError = !!this[privateCustomValidationMessage];
238+
const customError = !!this[privateCustomValidationMessage] || validity.customError;
239239
const validationMessage =
240240
this[privateCustomValidationMessage] || nonCustomValidationMessage;
241241

labs/behaviors/constraint-validation_test.ts

Lines changed: 77 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,19 @@
66

77
// import 'jasmine'; (google3-only)
88

9-
import {LitElement, html} from 'lit';
10-
import {customElement, property} from 'lit/decorators.js';
9+
import { LitElement, html } from 'lit';
10+
import { customElement, property } from 'lit/decorators.js';
1111

1212
import {
1313
createValidator,
1414
getValidityAnchor,
1515
mixinConstraintValidation,
1616
} from './constraint-validation.js';
17-
import {mixinElementInternals} from './element-internals.js';
18-
import {getFormValue, mixinFormAssociated} from './form-associated.js';
19-
import {CheckboxValidator} from './validators/checkbox-validator.js';
17+
import { mixinElementInternals } from './element-internals.js';
18+
import { getFormValue, mixinFormAssociated } from './form-associated.js';
19+
import { CheckboxValidator } from './validators/checkbox-validator.js';
20+
import { Validator } from './validators/validator.js';
21+
import { SelectState } from './validators/select-validator.js';
2022

2123
describe('mixinConstraintValidation()', () => {
2224
const baseClass = mixinConstraintValidation(
@@ -25,8 +27,8 @@ describe('mixinConstraintValidation()', () => {
2527

2628
@customElement('test-constraint-validation')
2729
class TestConstraintValidation extends baseClass {
28-
@property({type: Boolean}) checked = false;
29-
@property({type: Boolean}) required = false;
30+
@property({ type: Boolean }) checked = false;
31+
@property({ type: Boolean }) required = false;
3032

3133
override render() {
3234
return html`<div id="root"></div>`;
@@ -45,6 +47,52 @@ describe('mixinConstraintValidation()', () => {
4547
}
4648
}
4749

50+
/**
51+
* A validator that set customError flag to true
52+
*/
53+
class CustomErrorValidator extends Validator<SelectState> {
54+
private control?: HTMLInputElement;
55+
56+
protected override computeValidity(state: SelectState) {
57+
if (!this.control) {
58+
this.control = document.createElement('input');
59+
}
60+
this.control.setCustomValidity('validator custom error');
61+
return {
62+
validity: this.control.validity,
63+
validationMessage: this.control.validationMessage,
64+
};
65+
}
66+
67+
protected override equals(prev: SelectState, next: SelectState) {
68+
return prev.value === next.value
69+
}
70+
71+
protected override copy({ value, required }: SelectState) {
72+
return { value, required };
73+
}
74+
}
75+
76+
@customElement('test-custom-error-constraint-validation')
77+
class TestCustomErrorConstraintValidation extends baseClass {
78+
@property() value = '';
79+
@property({ type: Boolean }) required = false;
80+
override render() {
81+
return html`<div id="root"></div>`;
82+
}
83+
[createValidator]() {
84+
return new CustomErrorValidator(() => this);
85+
}
86+
87+
[getValidityAnchor]() {
88+
return this.shadowRoot?.querySelector<HTMLElement>('#root') ?? null;
89+
}
90+
91+
[getFormValue]() {
92+
return String(this.value);
93+
}
94+
}
95+
4896
describe('validity', () => {
4997
it('should return a ValidityState value', () => {
5098
const control = new TestConstraintValidation();
@@ -174,4 +222,26 @@ describe('mixinConstraintValidation()', () => {
174222
.toBe('Error');
175223
});
176224
});
225+
226+
describe('customError', () => {
227+
it('should set customError to true when validator has customError', () => {
228+
const control = new TestCustomErrorConstraintValidation();
229+
expect(control.validity.customError)
230+
.withContext('validity.customError')
231+
.toBeTrue();
232+
});
233+
it('should dispatch invalid event when validator has customError', () => {
234+
const control = new TestCustomErrorConstraintValidation();
235+
const invalidListener = jasmine.createSpy('invalidListener');
236+
control.addEventListener('invalid', invalidListener);
237+
control.reportValidity();
238+
expect(invalidListener).toHaveBeenCalledWith(jasmine.any(Event));
239+
});
240+
it('should report custom validation message over other validation messages', () => {
241+
const control = new TestCustomErrorConstraintValidation();
242+
expect(control.validationMessage)
243+
.withContext('validationMessage')
244+
.toBe('validator custom error');
245+
});
246+
})
177247
});

0 commit comments

Comments
 (0)