Merge 770623cc926f7350287f1fd11934abc15a8c2421 into 555b0add40685ad2d799e4bccfc4c69812abe207

This commit is contained in:
christophe geiser 2026-01-08 14:07:16 +00:00 committed by GitHub
commit e3314556f7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 71 additions and 1 deletions

View File

@ -235,7 +235,7 @@ export function mixinConstraintValidation<
const {validity, validationMessage: nonCustomValidationMessage} =
this[privateValidator].getValidity();
const customError = !!this[privateCustomValidationMessage];
const customError = !!this[privateCustomValidationMessage] || validity.customError;
const validationMessage =
this[privateCustomValidationMessage] || nonCustomValidationMessage;

View File

@ -17,6 +17,8 @@ import {
import {mixinElementInternals} from './element-internals.js';
import {getFormValue, mixinFormAssociated} from './form-associated.js';
import {CheckboxValidator} from './validators/checkbox-validator.js';
import {Validator} from './validators/validator.js';
import {SelectState} from './validators/select-validator.js';
describe('mixinConstraintValidation()', () => {
const baseClass = mixinConstraintValidation(
@ -45,6 +47,52 @@ describe('mixinConstraintValidation()', () => {
}
}
/**
* A validator that set customError flag to true
*/
class CustomErrorValidator extends Validator<SelectState> {
private control?: HTMLInputElement;
protected override computeValidity(state: SelectState) {
if (!this.control) {
this.control = document.createElement('input');
}
this.control.setCustomValidity('validator custom error');
return {
validity: this.control.validity,
validationMessage: this.control.validationMessage,
};
}
protected override equals(prev: SelectState, next: SelectState) {
return prev.value === next.value
}
protected override copy({ value, required }: SelectState) {
return { value, required };
}
}
@customElement('test-custom-error-constraint-validation')
class TestCustomErrorConstraintValidation extends baseClass {
@property() value = '';
@property({ type: Boolean }) required = false;
override render() {
return html`<div id="root"></div>`;
}
[createValidator]() {
return new CustomErrorValidator(() => this);
}
[getValidityAnchor]() {
return this.shadowRoot?.querySelector<HTMLElement>('#root') ?? null;
}
[getFormValue]() {
return String(this.value);
}
}
describe('validity', () => {
it('should return a ValidityState value', () => {
const control = new TestConstraintValidation();
@ -174,4 +222,26 @@ describe('mixinConstraintValidation()', () => {
.toBe('Error');
});
});
describe('customError', () => {
it('should set customError to true when validator has customError', () => {
const control = new TestCustomErrorConstraintValidation();
expect(control.validity.customError)
.withContext('validity.customError')
.toBeTrue();
});
it('should dispatch invalid event when validator has customError', () => {
const control = new TestCustomErrorConstraintValidation();
const invalidListener = jasmine.createSpy('invalidListener');
control.addEventListener('invalid', invalidListener);
control.reportValidity();
expect(invalidListener).toHaveBeenCalledWith(jasmine.any(Event));
});
it('should report custom validation message over other validation messages', () => {
const control = new TestCustomErrorConstraintValidation();
expect(control.validationMessage)
.withContext('validationMessage')
.toBe('validator custom error');
});
})
});