chore: enhance execution on empty api
This commit is contained in:
parent
4cc72b1251
commit
e16de38cd6
5 changed files with 21 additions and 47 deletions
|
|
@ -2,4 +2,4 @@
|
||||||
'@lion/ui': patch
|
'@lion/ui': patch
|
||||||
---
|
---
|
||||||
|
|
||||||
feat: allow Required validator on Fieldset and Form; `static executesOnEmpty` flag on Validators
|
feat: allow Required validator on Fieldset and Form;
|
||||||
|
|
|
||||||
|
|
@ -589,12 +589,7 @@ const FormGroupMixinImplementation = superclass =>
|
||||||
* @override FormControlMixin
|
* @override FormControlMixin
|
||||||
*/
|
*/
|
||||||
_isEmpty() {
|
_isEmpty() {
|
||||||
for (const el of this.formElements) {
|
return this.formElements.every(el => el._isEmpty?.());
|
||||||
if (!el._isEmpty?.()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -432,22 +432,30 @@ export const ValidateMixinImplementation = superclass =>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const isEmpty = this.__isEmpty(value);
|
const isEmpty = this.__isEmpty(value);
|
||||||
|
|
||||||
this.__syncValidationResult = [];
|
this.__syncValidationResult = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* So we can have the following scenarios:
|
||||||
|
* - we're empty
|
||||||
|
* - we have a single value (we are an 'endpoint') => we want to halt execution, because validation only makes sense when we have a value
|
||||||
|
* - 1. we have Required => we fill .__syncValidationResult and finish validation, because we have a value to validate
|
||||||
|
* - 2. we don't have Required => we stop validation
|
||||||
|
* - we have a group of values (object/array) => we want to continue execution, because the constellation of the object (even though the individual endpoints are empty) might be interesting for validation.
|
||||||
|
* - 3. we have Required => we fill .__syncValidationResult and continue validation (so we can add more to .__syncValidationResult)
|
||||||
|
* - 4. we don't have Required => we continue validation
|
||||||
|
* - we're not empty
|
||||||
|
* - we have a single value or group of values
|
||||||
|
* - 5. we may have Required, but if we have it will not be 'active' => we continue execution, because we have a value to validate
|
||||||
|
*/
|
||||||
|
|
||||||
if (isEmpty) {
|
if (isEmpty) {
|
||||||
|
const hasSingleValue = !(/** @type {* & ValidateHost} */ (this)._isFormOrFieldset);
|
||||||
const requiredValidator = this._allValidators.find(v => v instanceof Required);
|
const requiredValidator = this._allValidators.find(v => v instanceof Required);
|
||||||
if (requiredValidator) {
|
if (requiredValidator) {
|
||||||
this.__syncValidationResult = [{ validator: requiredValidator, outcome: true }];
|
this.__syncValidationResult = [{ validator: requiredValidator, outcome: true }];
|
||||||
}
|
}
|
||||||
// TODO: get rid of _isFormOrFieldset in a breaking future update.
|
|
||||||
// For now, We should keep forms and fieldsets backwards compatible...
|
|
||||||
const validatorsThatShouldRunOnEmpty = this._allValidators.filter(
|
|
||||||
v => v.constructor.executesOnEmpty,
|
|
||||||
);
|
|
||||||
const shouldHaltValidationOnEmpty =
|
|
||||||
!validatorsThatShouldRunOnEmpty.length && !this._isFormOrFieldset;
|
|
||||||
|
|
||||||
if (shouldHaltValidationOnEmpty) {
|
if (hasSingleValue) {
|
||||||
this.__finishValidationPass({
|
this.__finishValidationPass({
|
||||||
syncValidationResult: this.__syncValidationResult,
|
syncValidationResult: this.__syncValidationResult,
|
||||||
});
|
});
|
||||||
|
|
@ -463,7 +471,6 @@ export const ValidateMixinImplementation = superclass =>
|
||||||
if (v instanceof MetaValidator) {
|
if (v instanceof MetaValidator) {
|
||||||
metaValidators.push(v);
|
metaValidators.push(v);
|
||||||
} else if (v instanceof Required) {
|
} else if (v instanceof Required) {
|
||||||
// syncValidators.unshift(v);
|
|
||||||
// Required validator was already handled
|
// Required validator was already handled
|
||||||
} else if (/** @type {typeof Validator} */ (v.constructor).async) {
|
} else if (/** @type {typeof Validator} */ (v.constructor).async) {
|
||||||
asyncValidators.push(v);
|
asyncValidators.push(v);
|
||||||
|
|
|
||||||
|
|
@ -855,34 +855,6 @@ export function runValidateMixinSuite(customConfig) {
|
||||||
expect(alwaysInvalidSpy.callCount).to.equal(1); // __isRequired returned true (valid)
|
expect(alwaysInvalidSpy.callCount).to.equal(1); // __isRequired returned true (valid)
|
||||||
});
|
});
|
||||||
|
|
||||||
it('does not prevent other Validators from being called when input is empty, but at least one Validator has "executesOnEmpty"', async () => {
|
|
||||||
class AlwaysInvalidExecutingOnEmpty extends Validator {
|
|
||||||
static validatorName = 'AlwaysInvalidExecutingOnEmpty';
|
|
||||||
|
|
||||||
static executesOnEmpty = true;
|
|
||||||
|
|
||||||
execute() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const alwaysInvalidExecutingOnEmpty = new AlwaysInvalidExecutingOnEmpty();
|
|
||||||
const aalwaysInvalidExecutingOnEmptySpy = sinon.spy(
|
|
||||||
alwaysInvalidExecutingOnEmpty,
|
|
||||||
'execute',
|
|
||||||
);
|
|
||||||
const el = /** @type {ValidateElement} */ (
|
|
||||||
await fixture(html`
|
|
||||||
<${tag}
|
|
||||||
.validators=${[new Required(), alwaysInvalidExecutingOnEmpty]}
|
|
||||||
.modelValue=${''}
|
|
||||||
>${lightDom}</${tag}>
|
|
||||||
`)
|
|
||||||
);
|
|
||||||
expect(aalwaysInvalidExecutingOnEmptySpy.callCount).to.equal(1);
|
|
||||||
el.modelValue = 'foo';
|
|
||||||
expect(aalwaysInvalidExecutingOnEmptySpy.callCount).to.equal(2);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('adds [aria-required="true"] to "._inputNode"', async () => {
|
it('adds [aria-required="true"] to "._inputNode"', async () => {
|
||||||
const el = /** @type {ValidateElement} */ (
|
const el = /** @type {ValidateElement} */ (
|
||||||
await fixture(html`
|
await fixture(html`
|
||||||
|
|
|
||||||
|
|
@ -589,9 +589,9 @@ export function runFormGroupMixinSuite(cfg = {}) {
|
||||||
// initially the group is invalid
|
// initially the group is invalid
|
||||||
expect(el.validationStates.error.Required).to.be.true;
|
expect(el.validationStates.error.Required).to.be.true;
|
||||||
el.formElements.fieldA.modelValue = 'foo';
|
el.formElements.fieldA.modelValue = 'foo';
|
||||||
// If at least one child is filled, the group is valid
|
// if at least one child is filled, the group is valid
|
||||||
expect(el.validationStates.error.Required).to.be.undefined;
|
expect(el.validationStates.error.Required).to.be.undefined;
|
||||||
// // initially the group is invalid
|
// make Required trigger error state again
|
||||||
el.formElements.fieldA.modelValue = '';
|
el.formElements.fieldA.modelValue = '';
|
||||||
expect(el.validationStates.error.Required).to.be.true;
|
expect(el.validationStates.error.Required).to.be.true;
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue