From 4d2c4895084511e4bacf82bca95e7ab37a948636 Mon Sep 17 00:00:00 2001 From: Wiktor Danielewski <63188869+wiktord2000@users.noreply.github.com> Date: Fri, 21 Jun 2024 08:50:55 +0200 Subject: [PATCH] AAE-23116 Dropdown should not display errors / call apis when it's in readOnly state [without refactor] (#9800) * AAE-23116 Add tests for dropdown widget * AAE-23116 Update form-field.model * AAE-23116 Final * AAE-23116 Restore formatting * AAE-23116 Align with comments * AAE-23116 Update * AAE-23116 Fix process-services-cloud unit tests * AAE-23116 Fix process services unit tests * AAE-23116 Fix for core unit tests --- .../widgets/core/form-field-validator.spec.ts | 326 +++++++++--------- .../widgets/core/form-field-validator.ts | 148 ++------ .../widgets/core/form-field.model.spec.ts | 55 ++- .../widgets/core/form-field.model.ts | 92 +++-- .../dropdown/dropdown-cloud.widget.spec.ts | 85 +++-- .../widgets/dropdown/dropdown-cloud.widget.ts | 18 +- .../src/lib/form/form.component.spec.ts | 15 +- 7 files changed, 395 insertions(+), 344 deletions(-) diff --git a/lib/core/src/lib/form/components/widgets/core/form-field-validator.spec.ts b/lib/core/src/lib/form/components/widgets/core/form-field-validator.spec.ts index 5e5d7baef4..f478af0b45 100644 --- a/lib/core/src/lib/form/components/widgets/core/form-field-validator.spec.ts +++ b/lib/core/src/lib/form/components/widgets/core/form-field-validator.spec.ts @@ -52,20 +52,20 @@ describe('FormFieldValidator', () => { }); field.required = false; - expect(validator.isSupported(field)).toBeFalsy(); - expect(validator.validate(field)).toBeTruthy(); + expect(validator.isSupported(field)).toBe(false); + expect(validator.validate(field)).toBe(true); field.required = true; - expect(validator.isSupported(field)).toBeTruthy(); - expect(validator.validate(field)).toBeTruthy(); + expect(validator.isSupported(field)).toBe(true); + expect(validator.validate(field)).toBe(true); }); it('should skip unsupported type', () => { const field = new FormFieldModel(new FormModel(), { type: 'wrong-type' }); - expect(validator.validate(field)).toBeTruthy(); + expect(validator.validate(field)).toBe(true); }); - it('should fail for dropdown with empty value', () => { + it('should fail (display error) for dropdown with empty value', () => { const field = new FormFieldModel(new FormModel(), { type: FormFieldTypes.DROPDOWN, value: '', @@ -75,29 +75,34 @@ describe('FormFieldValidator', () => { }); field.emptyOption = { id: '' } as FormFieldOption; - expect(validator.validate(field)).toBeFalsy(); + expect(validator.validate(field)).toBe(false); field.value = ''; - expect(validator.validate(field)).toBeTruthy(); + expect(validator.validate(field)).toBe(true); }); - it('should fail for dropdown with zero selection', () => { + it('should fail (display error) for multiple type dropdown with zero selection', () => { const field = new FormFieldModel(new FormModel(), { type: FormFieldTypes.DROPDOWN, - value: [], - hasEmptyValue: true, + value: [{ id: 'id_cat', name: 'Cat' }], required: true, - selectionType: 'multiple' + selectionType: 'multiple', + hasEmptyValue: false, + options: [ + { id: 'id_cat', name: 'Cat' }, + { id: 'id_dog', name: 'Dog' } + ] }); - field.emptyOption = { id: 'empty' } as FormFieldOption; - expect(validator.validate(field)).toBeFalsy(); - + const validateBeforeUnselect = validator.validate(field); field.value = []; - expect(validator.validate(field)).toBe(false); + const validateAfterUnselect = validator.validate(field); + + expect(validateBeforeUnselect).toBe(true); + expect(validateAfterUnselect).toBe(false); }); - it('should fail for dropdown with null value', () => { + it('should fail (display error) for dropdown with null value', () => { const field = new FormFieldModel(new FormModel(), { type: FormFieldTypes.DROPDOWN, value: null, @@ -109,7 +114,7 @@ describe('FormFieldValidator', () => { expect(validator.validate(field)).toBe(false); }); - it('should fail for dropdown with empty object', () => { + it('should fail (display error) for dropdown with empty object', () => { const field = new FormFieldModel(new FormModel(), { type: FormFieldTypes.DROPDOWN, value: {}, @@ -121,7 +126,7 @@ describe('FormFieldValidator', () => { expect(validator.validate(field)).toBe(false); }); - it('should fail for radio buttons', () => { + it('should fail (display error) for radio buttons', () => { const field = new FormFieldModel(new FormModel(), { type: FormFieldTypes.RADIO_BUTTONS, required: true, @@ -129,7 +134,7 @@ describe('FormFieldValidator', () => { }); field.value = 'one'; - expect(validator.validate(field)).toBeFalsy(); + expect(validator.validate(field)).toBe(false); }); it('should succeed for radio buttons', () => { @@ -140,10 +145,10 @@ describe('FormFieldValidator', () => { options: [{ id: 'two', name: 'two' }] }); - expect(validator.validate(field)).toBeTruthy(); + expect(validator.validate(field)).toBe(true); }); - it('should fail for upload', () => { + it('should fail (display error) for upload', () => { const field = new FormFieldModel(new FormModel(), { type: FormFieldTypes.UPLOAD, value: null, @@ -151,10 +156,10 @@ describe('FormFieldValidator', () => { }); field.value = null; - expect(validator.validate(field)).toBeFalsy(); + expect(validator.validate(field)).toBe(false); field.value = []; - expect(validator.validate(field)).toBeFalsy(); + expect(validator.validate(field)).toBe(false); }); it('should succeed for upload', () => { @@ -164,10 +169,10 @@ describe('FormFieldValidator', () => { required: true }); - expect(validator.validate(field)).toBeTruthy(); + expect(validator.validate(field)).toBe(true); }); - it('should fail for text', () => { + it('should fail (display error) for text', () => { const field = new FormFieldModel(new FormModel(), { type: FormFieldTypes.TEXT, value: null, @@ -175,10 +180,10 @@ describe('FormFieldValidator', () => { }); field.value = null; - expect(validator.validate(field)).toBeFalsy(); + expect(validator.validate(field)).toBe(false); field.value = ''; - expect(validator.validate(field)).toBeFalsy(); + expect(validator.validate(field)).toBe(false); }); it('should succeed for date', () => { @@ -188,10 +193,10 @@ describe('FormFieldValidator', () => { required: true }); - expect(validator.validate(field)).toBeTruthy(); + expect(validator.validate(field)).toBe(true); }); - it('should fail for date', () => { + it('should fail (display error) for date', () => { const field = new FormFieldModel(new FormModel(), { type: FormFieldTypes.DATE, value: null, @@ -199,10 +204,10 @@ describe('FormFieldValidator', () => { }); field.value = null; - expect(validator.validate(field)).toBeFalsy(); + expect(validator.validate(field)).toBe(false); field.value = ''; - expect(validator.validate(field)).toBeFalsy(); + expect(validator.validate(field)).toBe(false); }); it('should succeed for text', () => { @@ -212,7 +217,7 @@ describe('FormFieldValidator', () => { required: true }); - expect(validator.validate(field)).toBeTruthy(); + expect(validator.validate(field)).toBe(true); }); it('should succeed for check box', () => { @@ -223,10 +228,10 @@ describe('FormFieldValidator', () => { options: [{ id: 'two', name: 'two' }] }); - expect(validator.validate(field)).toBeTruthy(); + expect(validator.validate(field)).toBe(true); }); - it('should fail for check box', () => { + it('should fail (display error) for check box', () => { const field = new FormFieldModel(new FormModel(), { type: FormFieldTypes.BOOLEAN, required: true, @@ -235,7 +240,7 @@ describe('FormFieldValidator', () => { }); field.value = false; - expect(validator.validate(field)).toBeFalsy(); + expect(validator.validate(field)).toBe(false); }); }); @@ -247,20 +252,20 @@ describe('FormFieldValidator', () => { }); it('should verify number', () => { - expect(NumberFieldValidator.isNumber('1')).toBeTruthy(); - expect(NumberFieldValidator.isNumber('1.0')).toBeTruthy(); - expect(NumberFieldValidator.isNumber('-1')).toBeTruthy(); - expect(NumberFieldValidator.isNumber(1)).toBeTruthy(); - expect(NumberFieldValidator.isNumber(0)).toBeTruthy(); - expect(NumberFieldValidator.isNumber(-1)).toBeTruthy(); + expect(NumberFieldValidator.isNumber('1')).toBe(true); + expect(NumberFieldValidator.isNumber('1.0')).toBe(true); + expect(NumberFieldValidator.isNumber('-1')).toBe(true); + expect(NumberFieldValidator.isNumber(1)).toBe(true); + expect(NumberFieldValidator.isNumber(0)).toBe(true); + expect(NumberFieldValidator.isNumber(-1)).toBe(true); }); it('should not verify number', () => { - expect(NumberFieldValidator.isNumber(null)).toBeFalsy(); - expect(NumberFieldValidator.isNumber(undefined)).toBeFalsy(); - expect(NumberFieldValidator.isNumber('')).toBeFalsy(); - expect(NumberFieldValidator.isNumber('one')).toBeFalsy(); - expect(NumberFieldValidator.isNumber('1q')).toBeFalsy(); + expect(NumberFieldValidator.isNumber(null)).toBe(false); + expect(NumberFieldValidator.isNumber(undefined)).toBe(false); + expect(NumberFieldValidator.isNumber('')).toBe(false); + expect(NumberFieldValidator.isNumber('one')).toBe(false); + expect(NumberFieldValidator.isNumber('1q')).toBe(false); }); it('should allow empty number value', () => { @@ -269,7 +274,7 @@ describe('FormFieldValidator', () => { value: null }); - expect(validator.validate(field)).toBeTruthy(); + expect(validator.validate(field)).toBe(true); }); it('should allow number value', () => { @@ -278,7 +283,7 @@ describe('FormFieldValidator', () => { value: 44 }); - expect(validator.validate(field)).toBeTruthy(); + expect(validator.validate(field)).toBe(true); }); it('should allow zero number value', () => { @@ -287,17 +292,17 @@ describe('FormFieldValidator', () => { value: 0 }); - expect(validator.validate(field)).toBeTruthy(); + expect(validator.validate(field)).toBe(true); }); - it('should fail for wrong number value', () => { + it('should fail (display error) for wrong number value', () => { const field = new FormFieldModel(new FormModel(), { type: FormFieldTypes.NUMBER, value: '' }); field.validationSummary = new ErrorMessageModel(); - expect(validator.validate(field)).toBeFalsy(); + expect(validator.validate(field)).toBe(false); expect(field.validationSummary).not.toBeNull(); }); }); @@ -314,10 +319,10 @@ describe('FormFieldValidator', () => { type: FormFieldTypes.TEXT }); - expect(validator.isSupported(field)).toBeFalsy(); + expect(validator.isSupported(field)).toBe(false); field.minLength = 10; - expect(validator.isSupported(field)).toBeTruthy(); + expect(validator.isSupported(field)).toBe(true); }); it('should allow empty values', () => { @@ -327,7 +332,7 @@ describe('FormFieldValidator', () => { value: null }); - expect(validator.validate(field)).toBeTruthy(); + expect(validator.validate(field)).toBe(true); }); it('should succeed text validation', () => { @@ -337,10 +342,10 @@ describe('FormFieldValidator', () => { value: '1234' }); - expect(validator.validate(field)).toBeTruthy(); + expect(validator.validate(field)).toBe(true); }); - it('should fail text validation', () => { + it('should fail (display error) text validation', () => { const field = new FormFieldModel(new FormModel(), { type: FormFieldTypes.TEXT, minLength: 3, @@ -348,7 +353,7 @@ describe('FormFieldValidator', () => { }); field.validationSummary = new ErrorMessageModel(); - expect(validator.validate(field)).toBeFalsy(); + expect(validator.validate(field)).toBe(false); expect(field.validationSummary).not.toBeNull(); }); }); @@ -365,10 +370,10 @@ describe('FormFieldValidator', () => { type: FormFieldTypes.TEXT }); - expect(validator.isSupported(field)).toBeFalsy(); + expect(validator.isSupported(field)).toBe(false); field.maxLength = 10; - expect(validator.isSupported(field)).toBeTruthy(); + expect(validator.isSupported(field)).toBe(true); }); it('should allow empty values', () => { @@ -378,7 +383,7 @@ describe('FormFieldValidator', () => { value: null }); - expect(validator.validate(field)).toBeTruthy(); + expect(validator.validate(field)).toBe(true); }); it('should succeed text validation', () => { @@ -388,10 +393,10 @@ describe('FormFieldValidator', () => { value: '123' }); - expect(validator.validate(field)).toBeTruthy(); + expect(validator.validate(field)).toBe(true); }); - it('should fail text validation', () => { + it('should fail (display error) text validation', () => { const field = new FormFieldModel(new FormModel(), { type: FormFieldTypes.TEXT, maxLength: 3, @@ -399,7 +404,7 @@ describe('FormFieldValidator', () => { }); field.validationSummary = new ErrorMessageModel(); - expect(validator.validate(field)).toBeFalsy(); + expect(validator.validate(field)).toBe(false); expect(field.validationSummary).not.toBeNull(); }); }); @@ -415,10 +420,10 @@ describe('FormFieldValidator', () => { const field = new FormFieldModel(new FormModel(), { type: FormFieldTypes.NUMBER }); - expect(validator.isSupported(field)).toBeFalsy(); + expect(validator.isSupported(field)).toBe(false); field.minValue = '1'; - expect(validator.isSupported(field)).toBeTruthy(); + expect(validator.isSupported(field)).toBe(true); }); it('should support numeric widgets only', () => { @@ -427,10 +432,10 @@ describe('FormFieldValidator', () => { minValue: '1' }); - expect(validator.isSupported(field)).toBeTruthy(); + expect(validator.isSupported(field)).toBe(true); field.type = FormFieldTypes.TEXT; - expect(validator.isSupported(field)).toBeFalsy(); + expect(validator.isSupported(field)).toBe(false); }); it('should allow empty values', () => { @@ -440,7 +445,7 @@ describe('FormFieldValidator', () => { minValue: '1' }); - expect(validator.validate(field)).toBeTruthy(); + expect(validator.validate(field)).toBe(true); }); it('should succeed for unsupported types', () => { @@ -448,7 +453,7 @@ describe('FormFieldValidator', () => { type: FormFieldTypes.TEXT }); - expect(validator.validate(field)).toBeTruthy(); + expect(validator.validate(field)).toBe(true); }); it('should succeed validating value', () => { @@ -458,10 +463,10 @@ describe('FormFieldValidator', () => { minValue: '10' }); - expect(validator.validate(field)).toBeTruthy(); + expect(validator.validate(field)).toBe(true); }); - it('should fail validating value', () => { + it('should fail (display error) validating value', () => { const field = new FormFieldModel(new FormModel(), { type: FormFieldTypes.NUMBER, value: '9', @@ -469,7 +474,7 @@ describe('FormFieldValidator', () => { }); field.validationSummary = new ErrorMessageModel(); - expect(validator.validate(field)).toBeFalsy(); + expect(validator.validate(field)).toBe(false); expect(field.validationSummary).not.toBeNull(); }); }); @@ -485,10 +490,10 @@ describe('FormFieldValidator', () => { const field = new FormFieldModel(new FormModel(), { type: FormFieldTypes.NUMBER }); - expect(validator.isSupported(field)).toBeFalsy(); + expect(validator.isSupported(field)).toBe(false); field.maxValue = '1'; - expect(validator.isSupported(field)).toBeTruthy(); + expect(validator.isSupported(field)).toBe(true); }); it('should support numeric widgets only', () => { @@ -497,10 +502,10 @@ describe('FormFieldValidator', () => { maxValue: '1' }); - expect(validator.isSupported(field)).toBeTruthy(); + expect(validator.isSupported(field)).toBe(true); field.type = FormFieldTypes.TEXT; - expect(validator.isSupported(field)).toBeFalsy(); + expect(validator.isSupported(field)).toBe(false); }); it('should allow empty values', () => { @@ -510,7 +515,7 @@ describe('FormFieldValidator', () => { maxValue: '1' }); - expect(validator.validate(field)).toBeTruthy(); + expect(validator.validate(field)).toBe(true); }); it('should succeed for unsupported types', () => { @@ -518,7 +523,7 @@ describe('FormFieldValidator', () => { type: FormFieldTypes.TEXT }); - expect(validator.validate(field)).toBeTruthy(); + expect(validator.validate(field)).toBe(true); }); it('should succeed validating value', () => { @@ -528,10 +533,10 @@ describe('FormFieldValidator', () => { maxValue: '10' }); - expect(validator.validate(field)).toBeTruthy(); + expect(validator.validate(field)).toBe(true); }); - it('should fail validating value', () => { + it('should fail (display error) validating value', () => { const field = new FormFieldModel(new FormModel(), { type: FormFieldTypes.NUMBER, value: '11', @@ -539,7 +544,7 @@ describe('FormFieldValidator', () => { }); field.validationSummary = new ErrorMessageModel(); - expect(validator.validate(field)).toBeFalsy(); + expect(validator.validate(field)).toBe(false); expect(field.validationSummary).not.toBeNull(); }); }); @@ -555,10 +560,10 @@ describe('FormFieldValidator', () => { const field = new FormFieldModel(new FormModel(), { type: FormFieldTypes.TEXT }); - expect(validator.isSupported(field)).toBeFalsy(); + expect(validator.isSupported(field)).toBe(false); field.regexPattern = ''; - expect(validator.isSupported(field)).toBeTruthy(); + expect(validator.isSupported(field)).toBe(true); }); it('should allow empty values', () => { @@ -568,7 +573,7 @@ describe('FormFieldValidator', () => { regexPattern: 'pattern' }); - expect(validator.validate(field)).toBeTruthy(); + expect(validator.validate(field)).toBe(true); }); it('should allow empty string values', () => { @@ -578,7 +583,7 @@ describe('FormFieldValidator', () => { regexPattern: 'pattern' }); - expect(validator.validate(field)).toBeTruthy(); + expect(validator.validate(field)).toBe(true); }); it('should succeed validating regex', () => { @@ -588,17 +593,17 @@ describe('FormFieldValidator', () => { regexPattern: 'pattern' }); - expect(validator.validate(field)).toBeTruthy(); + expect(validator.validate(field)).toBe(true); }); - it('should fail validating regex', () => { + it('should fail (display error) validating regex', () => { const field = new FormFieldModel(new FormModel(), { type: FormFieldTypes.TEXT, value: 'some value', regexPattern: 'pattern' }); - expect(validator.validate(field)).toBeFalsy(); + expect(validator.validate(field)).toBe(false); }); }); @@ -613,13 +618,13 @@ describe('FormFieldValidator', () => { let field = new FormFieldModel(new FormModel(), { type: FormFieldTypes.TEXT }); - expect(validator.isSupported(field)).toBeFalsy(); + expect(validator.isSupported(field)).toBe(false); field = new FormFieldModel(new FormModel(), { type: FormFieldTypes.TYPEAHEAD }); - expect(validator.isSupported(field)).toBeTruthy(); + expect(validator.isSupported(field)).toBe(true); }); it('should allow empty values', () => { @@ -629,7 +634,7 @@ describe('FormFieldValidator', () => { regexPattern: 'pattern' }); - expect(validator.validate(field)).toBeTruthy(); + expect(validator.validate(field)).toBe(true); }); it('should succeed for a valid input value in options', () => { @@ -642,10 +647,10 @@ describe('FormFieldValidator', () => { ] }); - expect(validator.validate(field)).toBeTruthy(); + expect(validator.validate(field)).toBe(true); }); - it('should fail for an invalid input value in options', () => { + it('should fail (display error) for an invalid input value in options', () => { const field = new FormFieldModel(new FormModel(), { type: FormFieldTypes.TYPEAHEAD, value: 'Lean', @@ -655,7 +660,7 @@ describe('FormFieldValidator', () => { ] }); - expect(validator.validate(field)).toBeFalsy(); + expect(validator.validate(field)).toBe(false); }); }); @@ -670,10 +675,10 @@ describe('FormFieldValidator', () => { const field = new FormFieldModel(new FormModel(), { type: FormFieldTypes.DATETIME }); - expect(validator.isSupported(field)).toBeFalsy(); + expect(validator.isSupported(field)).toBe(false); field.maxValue = '9999-02-08 10:10 AM'; - expect(validator.isSupported(field)).toBeTruthy(); + expect(validator.isSupported(field)).toBe(true); }); it('should support date time widgets only', () => { @@ -682,10 +687,10 @@ describe('FormFieldValidator', () => { maxValue: '9999-02-08 10:10 AM' }); - expect(validator.isSupported(field)).toBeTruthy(); + expect(validator.isSupported(field)).toBe(true); field.type = FormFieldTypes.TEXT; - expect(validator.isSupported(field)).toBeFalsy(); + expect(validator.isSupported(field)).toBe(false); }); it('should allow empty values', () => { @@ -695,7 +700,7 @@ describe('FormFieldValidator', () => { maxValue: '9999-02-08 10:10 AM' }); - expect(validator.validate(field)).toBeTruthy(); + expect(validator.validate(field)).toBe(true); }); it('should succeed for unsupported types', () => { @@ -703,10 +708,10 @@ describe('FormFieldValidator', () => { type: FormFieldTypes.TEXT }); - expect(validator.validate(field)).toBeTruthy(); + expect(validator.validate(field)).toBe(true); }); - it('should take into account that max value is in UTC and NOT fail validating value checking the time', () => { + it('should take into account that max value is in UTC and NOT fail (display error) validating value checking the time', () => { const localValidValue = '2018-03-30T22:59:00.000Z'; const field = new FormFieldModel(new FormModel(), { @@ -715,10 +720,10 @@ describe('FormFieldValidator', () => { maxValue: '2018-03-31T23:00:00.000Z' }); - expect(validator.validate(field)).toBeTruthy(); + expect(validator.validate(field)).toBe(true); }); - it('should take into account that max value is in UTC and fail validating value checking the time', () => { + it('should take into account that max value is in UTC and fail (display error) validating value checking the time', () => { const localInvalidValue = '2018-03-30T23:01:00.000Z'; const field = new FormFieldModel(new FormModel(), { @@ -728,7 +733,7 @@ describe('FormFieldValidator', () => { }); field.validationSummary = new ErrorMessageModel(); - expect(validator.validate(field)).toBeFalsy(); + expect(validator.validate(field)).toBe(false); expect(field.validationSummary).not.toBeNull(); expect(field.validationSummary.message).toBe('FORM.FIELD.VALIDATOR.NOT_GREATER_THAN'); }); @@ -740,10 +745,10 @@ describe('FormFieldValidator', () => { maxValue: '9999-02-08T10:10:00.000Z' }); - expect(validator.validate(field)).toBeTruthy(); + expect(validator.validate(field)).toBe(true); }); - it('should fail validating value checking the time', () => { + it('should fail (display error) validating value checking the time', () => { const field = new FormFieldModel(new FormModel(), { type: FormFieldTypes.DATETIME, value: '9999-02-08T11:10:00.000Z', @@ -751,7 +756,7 @@ describe('FormFieldValidator', () => { }); field.validationSummary = new ErrorMessageModel(); - expect(validator.validate(field)).toBeFalsy(); + expect(validator.validate(field)).toBe(false); expect(field.validationSummary).not.toBeNull(); }); @@ -762,10 +767,10 @@ describe('FormFieldValidator', () => { maxValue: '9999-02-08T10:10:00.000Z' }); - expect(validator.validate(field)).toBeTruthy(); + expect(validator.validate(field)).toBe(true); }); - it('should fail validating value checking the date', () => { + it('should fail (display error) validating value checking the date', () => { const field = new FormFieldModel(new FormModel(), { type: FormFieldTypes.DATETIME, value: '08-02-9999 12:10 AM', @@ -773,7 +778,7 @@ describe('FormFieldValidator', () => { }); field.validationSummary = new ErrorMessageModel(); - expect(validator.validate(field)).toBeFalsy(); + expect(validator.validate(field)).toBe(false); expect(field.validationSummary).not.toBeNull(); }); }); @@ -789,10 +794,10 @@ describe('FormFieldValidator', () => { const field = new FormFieldModel(new FormModel(), { type: FormFieldTypes.DATETIME }); - expect(validator.isSupported(field)).toBeFalsy(); + expect(validator.isSupported(field)).toBe(false); field.minValue = '9999-02-08 09:10 AM'; - expect(validator.isSupported(field)).toBeTruthy(); + expect(validator.isSupported(field)).toBe(true); }); it('should support date time widgets only', () => { @@ -801,10 +806,10 @@ describe('FormFieldValidator', () => { minValue: '9999-02-08 09:10 AM' }); - expect(validator.isSupported(field)).toBeTruthy(); + expect(validator.isSupported(field)).toBe(true); field.type = FormFieldTypes.TEXT; - expect(validator.isSupported(field)).toBeFalsy(); + expect(validator.isSupported(field)).toBe(false); }); it('should allow empty values', () => { @@ -814,7 +819,7 @@ describe('FormFieldValidator', () => { minValue: '9999-02-08 09:10 AM' }); - expect(validator.validate(field)).toBeTruthy(); + expect(validator.validate(field)).toBe(true); }); it('should succeed for unsupported types', () => { @@ -822,10 +827,10 @@ describe('FormFieldValidator', () => { type: FormFieldTypes.TEXT }); - expect(validator.validate(field)).toBeTruthy(); + expect(validator.validate(field)).toBe(true); }); - it('should take into account that min value is in UTC and NOT fail validating value checking the time', () => { + it('should take into account that min value is in UTC and NOT fail (display error) validating value checking the time', () => { const localValidValue = '2018-03-02T06:01:00.000Z'; const field = new FormFieldModel(new FormModel(), { @@ -834,10 +839,10 @@ describe('FormFieldValidator', () => { minValue: '2018-03-02T06:00:00.000Z' }); - expect(validator.validate(field)).toBeTruthy(); + expect(validator.validate(field)).toBe(true); }); - it('should take into account that min value is in UTC and fail validating value checking the time', () => { + it('should take into account that min value is in UTC and fail (display error) validating value checking the time', () => { const localInvalidValue = '2018-3-02 05:59 AM'; const field = new FormFieldModel(new FormModel(), { @@ -847,7 +852,7 @@ describe('FormFieldValidator', () => { }); field.validationSummary = new ErrorMessageModel(); - expect(validator.validate(field)).toBeFalsy(); + expect(validator.validate(field)).toBe(false); expect(field.validationSummary).not.toBeNull(); expect(field.validationSummary.message).toBe('FORM.FIELD.VALIDATOR.NOT_LESS_THAN'); }); @@ -859,7 +864,7 @@ describe('FormFieldValidator', () => { minValue: '9999-02-08 09:00 AM' }); - expect(validator.validate(field)).toBeTruthy(); + expect(validator.validate(field)).toBe(true); }); it('should succeed validating value by date', () => { @@ -869,10 +874,10 @@ describe('FormFieldValidator', () => { minValue: '9999-02-08 09:10 AM' }); - expect(validator.validate(field)).toBeTruthy(); + expect(validator.validate(field)).toBe(true); }); - it('should fail validating value by time', () => { + it('should fail (display error) validating value by time', () => { const field = new FormFieldModel(new FormModel(), { type: FormFieldTypes.DATETIME, value: '9999-08-02T08:10:00.000Z', @@ -880,11 +885,11 @@ describe('FormFieldValidator', () => { }); field.validationSummary = new ErrorMessageModel(); - expect(validator.validate(field)).toBeFalsy(); + expect(validator.validate(field)).toBe(false); expect(field.validationSummary).not.toBeNull(); }); - it('should fail validating value by date', () => { + it('should fail (display error) validating value by date', () => { const field = new FormFieldModel(new FormModel(), { type: FormFieldTypes.DATETIME, value: '9999-02-07T09:10:00.000Z', @@ -892,7 +897,7 @@ describe('FormFieldValidator', () => { }); field.validationSummary = new ErrorMessageModel(); - expect(validator.validate(field)).toBeFalsy(); + expect(validator.validate(field)).toBe(false); expect(field.validationSummary).not.toBeNull(); }); }); @@ -908,10 +913,10 @@ describe('FormFieldValidator', () => { const field = new FormFieldModel(new FormModel(), { type: FormFieldTypes.DATE }); - expect(validator.isSupported(field)).toBeFalsy(); + expect(validator.isSupported(field)).toBe(false); field.maxValue = '9999-02-08'; - expect(validator.isSupported(field)).toBeTruthy(); + expect(validator.isSupported(field)).toBe(true); }); it('should support date widgets only', () => { @@ -920,10 +925,10 @@ describe('FormFieldValidator', () => { maxValue: '9999-02-08' }); - expect(validator.isSupported(field)).toBeTruthy(); + expect(validator.isSupported(field)).toBe(true); field.type = FormFieldTypes.TEXT; - expect(validator.isSupported(field)).toBeFalsy(); + expect(validator.isSupported(field)).toBe(false); }); it('should allow empty values', () => { @@ -933,7 +938,7 @@ describe('FormFieldValidator', () => { maxValue: '9999-02-08' }); - expect(validator.validate(field)).toBeTruthy(); + expect(validator.validate(field)).toBe(true); }); it('should succeed for unsupported types', () => { @@ -941,7 +946,7 @@ describe('FormFieldValidator', () => { type: FormFieldTypes.TEXT }); - expect(validator.validate(field)).toBeTruthy(); + expect(validator.validate(field)).toBe(true); }); it('should succeed validating value checking the date', () => { @@ -951,10 +956,10 @@ describe('FormFieldValidator', () => { maxValue: '9999-02-09' }); - expect(validator.validate(field)).toBeTruthy(); + expect(validator.validate(field)).toBe(true); }); - it('should fail validating value checking the date', () => { + it('should fail (display error) validating value checking the date', () => { const field = new FormFieldModel(new FormModel(), { type: FormFieldTypes.DATE, value: '9999-02-08T00:00:00', @@ -962,7 +967,7 @@ describe('FormFieldValidator', () => { }); field.validationSummary = new ErrorMessageModel(); - expect(validator.validate(field)).toBeFalsy(); + expect(validator.validate(field)).toBe(false); expect(field.validationSummary).not.toBeNull(); }); @@ -973,10 +978,10 @@ describe('FormFieldValidator', () => { maxValue: '09-02-9999' }); - expect(validator.validate(field)).toBeTruthy(); + expect(validator.validate(field)).toBe(true); }); - it('should fail validating with APS1 format', () => { + it('should fail (display error) validating with APS1 format', () => { const field = new FormFieldModel(new FormModel(), { type: FormFieldTypes.DATE, value: '9999-02-08T00:00:00', @@ -984,7 +989,7 @@ describe('FormFieldValidator', () => { }); field.validationSummary = new ErrorMessageModel(); - expect(validator.validate(field)).toBeFalsy(); + expect(validator.validate(field)).toBe(false); expect(field.validationSummary).not.toBeNull(); }); }); @@ -1000,10 +1005,10 @@ describe('FormFieldValidator', () => { const field = new FormFieldModel(new FormModel(), { type: FormFieldTypes.DATE }); - expect(validator.isSupported(field)).toBeFalsy(); + expect(validator.isSupported(field)).toBe(false); field.minValue = '9999-02-08'; - expect(validator.isSupported(field)).toBeTruthy(); + expect(validator.isSupported(field)).toBe(true); }); it('should support date widgets only', () => { @@ -1012,10 +1017,10 @@ describe('FormFieldValidator', () => { minValue: '9999-02-08' }); - expect(validator.isSupported(field)).toBeTruthy(); + expect(validator.isSupported(field)).toBe(true); field.type = FormFieldTypes.TEXT; - expect(validator.isSupported(field)).toBeFalsy(); + expect(validator.isSupported(field)).toBe(false); }); it('should allow empty values', () => { @@ -1025,7 +1030,7 @@ describe('FormFieldValidator', () => { minValue: '9999-02-08' }); - expect(validator.validate(field)).toBeTruthy(); + expect(validator.validate(field)).toBe(true); }); it('should succeed for unsupported types', () => { @@ -1033,7 +1038,7 @@ describe('FormFieldValidator', () => { type: FormFieldTypes.TEXT }); - expect(validator.validate(field)).toBeTruthy(); + expect(validator.validate(field)).toBe(true); }); it('should succeed validating value checking the date', () => { @@ -1043,10 +1048,10 @@ describe('FormFieldValidator', () => { minValue: '9999-02-07' }); - expect(validator.validate(field)).toBeTruthy(); + expect(validator.validate(field)).toBe(true); }); - it('should fail validating value checking the date', () => { + it('should fail (display error) validating value checking the date', () => { const field = new FormFieldModel(new FormModel(), { type: FormFieldTypes.DATE, value: '9999-02-08T00:00:00', @@ -1054,7 +1059,7 @@ describe('FormFieldValidator', () => { }); field.validationSummary = new ErrorMessageModel(); - expect(validator.validate(field)).toBeFalsy(); + expect(validator.validate(field)).toBe(false); expect(field.validationSummary).not.toBeNull(); }); @@ -1065,10 +1070,10 @@ describe('FormFieldValidator', () => { minValue: '07-02-9999' }); - expect(validator.validate(field)).toBeTruthy(); + expect(validator.validate(field)).toBe(true); }); - it('should fail validating with APS1 format', () => { + it('should fail (display error) validating with APS1 format', () => { const field = new FormFieldModel(new FormModel(), { type: FormFieldTypes.DATE, value: '9999-02-08T00:00:00', @@ -1076,7 +1081,7 @@ describe('FormFieldValidator', () => { }); field.validationSummary = new ErrorMessageModel(); - expect(validator.validate(field)).toBeFalsy(); + expect(validator.validate(field)).toBe(false); expect(field.validationSummary).not.toBeNull(); }); }); @@ -1095,7 +1100,7 @@ describe('FormFieldValidator', () => { dateDisplayFormat: 'YYYY-MM-DD HH:mm' }); - expect(validator.validate(field)).toBeTruthy(); + expect(validator.validate(field)).toBe(true); }); it('should validate dateTime format with default format', () => { @@ -1105,7 +1110,7 @@ describe('FormFieldValidator', () => { }); expect(field.value).toBe('9-6-2021 11:10 AM'); expect(field.dateDisplayFormat).toBe('D-M-YYYY hh:mm A'); - expect(validator.validate(field)).toBeTrue(); + expect(validator.validate(field)).toBe(true); }); it('should not validate dateTime format with default format', () => { @@ -1115,7 +1120,7 @@ describe('FormFieldValidator', () => { }); expect(field.value).toBe('2021-06-09 14:10 AM'); expect(field.dateDisplayFormat).toBe('D-M-YYYY hh:mm A'); - expect(validator.validate(field)).toBeFalse(); + expect(validator.validate(field)).toBe(false); }); }); @@ -1133,7 +1138,7 @@ describe('FormFieldValidator', () => { precision: 2 }); - expect(decimalValidator.validate(field)).toBeTrue(); + expect(decimalValidator.validate(field)).toBe(true); }); it('should return true when value is of lower precision', () => { @@ -1143,7 +1148,7 @@ describe('FormFieldValidator', () => { precision: 2 }); - expect(decimalValidator.validate(field)).toBeTrue(); + expect(decimalValidator.validate(field)).toBe(true); }); it('should return false when value is of higher precision', () => { @@ -1153,7 +1158,7 @@ describe('FormFieldValidator', () => { precision: 1 }); - expect(decimalValidator.validate(field)).toBeFalse(); + expect(decimalValidator.validate(field)).toBe(false); }); it('should validate decimal of wrong precision when value is of type string', () => { @@ -1163,7 +1168,7 @@ describe('FormFieldValidator', () => { precision: 1 }); - expect(decimalValidator.validate(field)).toBeFalse(); + expect(decimalValidator.validate(field)).toBe(false); }); it('should return false, when value is a negative number and of correct precission', () => { @@ -1173,7 +1178,7 @@ describe('FormFieldValidator', () => { precision: 1 }); - expect(decimalValidator.validate(field)).toBeFalse(); + expect(decimalValidator.validate(field)).toBe(false); }); it('should return true, when value is a positive number and of correct precission', () => { @@ -1183,8 +1188,7 @@ describe('FormFieldValidator', () => { precision: 3 }); - expect(decimalValidator.validate(field)).toBeTrue(); + expect(decimalValidator.validate(field)).toBe(true); }); - }); }); diff --git a/lib/core/src/lib/form/components/widgets/core/form-field-validator.ts b/lib/core/src/lib/form/components/widgets/core/form-field-validator.ts index d646d46c99..ce097b7dd8 100644 --- a/lib/core/src/lib/form/components/widgets/core/form-field-validator.ts +++ b/lib/core/src/lib/form/components/widgets/core/form-field-validator.ts @@ -24,15 +24,11 @@ import { DateFnsUtils } from '../../../../common/utils/date-fns-utils'; import { isValid as isDateValid, isBefore, isAfter } from 'date-fns'; export interface FormFieldValidator { - isSupported(field: FormFieldModel): boolean; - validate(field: FormFieldModel): boolean; - } export class RequiredFieldValidator implements FormFieldValidator { - private supportedTypes = [ FormFieldTypes.TEXT, FormFieldTypes.MULTILINE_TEXT, @@ -54,14 +50,11 @@ export class RequiredFieldValidator implements FormFieldValidator { ]; isSupported(field: FormFieldModel): boolean { - return field && - this.supportedTypes.indexOf(field.type) > -1 && - field.required; + return field && this.supportedTypes.indexOf(field.type) > -1 && field.required; } validate(field: FormFieldModel): boolean { if (this.isSupported(field) && field.isVisible) { - if (field.type === FormFieldTypes.DROPDOWN) { if (field.hasMultipleValues) { return Array.isArray(field.value) && !!field.value.length; @@ -73,7 +66,7 @@ export class RequiredFieldValidator implements FormFieldValidator { } } - if (field.required && typeof field.value === 'object' && field.value && !Object.keys(field.value).length) { + if (field.required && field.value && typeof field.value === 'object' && !Object.keys(field.value).length) { return false; } } @@ -84,11 +77,11 @@ export class RequiredFieldValidator implements FormFieldValidator { } if (field.type === FormFieldTypes.UPLOAD) { - return field.value && field.value.length > 0; + return !!field.value && field.value.length > 0; } if (field.type === FormFieldTypes.DYNAMIC_TABLE) { - return field.value && field.value instanceof Array && field.value.length > 0; + return !!field.value && field.value instanceof Array && field.value.length > 0; } if (field.type === FormFieldTypes.BOOLEAN) { @@ -101,15 +94,10 @@ export class RequiredFieldValidator implements FormFieldValidator { } return true; } - } export class NumberFieldValidator implements FormFieldValidator { - - private supportedTypes = [ - FormFieldTypes.NUMBER, - FormFieldTypes.AMOUNT - ]; + private supportedTypes = [FormFieldTypes.NUMBER, FormFieldTypes.AMOUNT]; static isNumber(value: any): boolean { return isNumberValue(value); @@ -121,9 +109,7 @@ export class NumberFieldValidator implements FormFieldValidator { validate(field: FormFieldModel): boolean { if (this.isSupported(field) && field.isVisible) { - if (field.value === null || - field.value === undefined || - field.value === '') { + if (field.value === null || field.value === undefined || field.value === '') { return true; } const valueStr = '' + field.value; @@ -142,10 +128,7 @@ export class NumberFieldValidator implements FormFieldValidator { } export class DateFieldValidator implements FormFieldValidator { - - private supportedTypes = [ - FormFieldTypes.DATE - ]; + private supportedTypes = [FormFieldTypes.DATE]; // Validates that the input string is a valid date formatted as (default D-M-YYYY) static isValidDate(inputDate: string, dateFormat: string = 'D-M-YYYY'): boolean { @@ -169,10 +152,7 @@ export class DateFieldValidator implements FormFieldValidator { } export class DateTimeFieldValidator implements FormFieldValidator { - - private supportedTypes = [ - FormFieldTypes.DATETIME - ]; + private supportedTypes = [FormFieldTypes.DATETIME]; isSupported(field: FormFieldModel): boolean { return field && this.supportedTypes.indexOf(field.type) > -1; @@ -196,13 +176,10 @@ export class DateTimeFieldValidator implements FormFieldValidator { } export abstract class BoundaryDateFieldValidator implements FormFieldValidator { - DATE_FORMAT_CLOUD = 'YYYY-MM-DD'; DATE_FORMAT = 'DD-MM-YYYY'; - supportedTypes = [ - FormFieldTypes.DATE - ]; + supportedTypes = [FormFieldTypes.DATE]; validate(field: FormFieldModel): boolean { let isValid = true; @@ -226,11 +203,9 @@ export abstract class BoundaryDateFieldValidator implements FormFieldValidator { abstract checkDate(field: FormFieldModel, dateFormat: string); abstract isSupported(field: FormFieldModel); - } export class MinDateFieldValidator extends BoundaryDateFieldValidator { - checkDate(field: FormFieldModel, dateFormat: string): boolean { let isValid = true; const fieldValueData = DateFnsUtils.parseDate(field.value, dateFormat, { dateOnly: true }); @@ -239,23 +214,18 @@ export class MinDateFieldValidator extends BoundaryDateFieldValidator { if (DateFnsUtils.isBeforeDate(fieldValueData, min)) { field.validationSummary.message = `FORM.FIELD.VALIDATOR.NOT_LESS_THAN`; - field.validationSummary.attributes.set( - 'minValue', - DateFnsUtils.formatDate(min, field.dateDisplayFormat).toLocaleUpperCase() - ); + field.validationSummary.attributes.set('minValue', DateFnsUtils.formatDate(min, field.dateDisplayFormat).toLocaleUpperCase()); isValid = false; } return isValid; } isSupported(field: FormFieldModel): boolean { - return field && - this.supportedTypes.indexOf(field.type) > -1 && !!field.minValue; + return field && this.supportedTypes.indexOf(field.type) > -1 && !!field.minValue; } } export class MaxDateFieldValidator extends BoundaryDateFieldValidator { - checkDate(field: FormFieldModel, dateFormat: string): boolean { let isValid = true; const fieldValueData = DateFnsUtils.parseDate(field.value, dateFormat, { dateOnly: true }); @@ -264,18 +234,14 @@ export class MaxDateFieldValidator extends BoundaryDateFieldValidator { if (DateFnsUtils.isAfterDate(fieldValueData, max)) { field.validationSummary.message = `FORM.FIELD.VALIDATOR.NOT_GREATER_THAN`; - field.validationSummary.attributes.set( - 'maxValue', - DateFnsUtils.formatDate(max, field.dateDisplayFormat).toLocaleUpperCase() - ); + field.validationSummary.attributes.set('maxValue', DateFnsUtils.formatDate(max, field.dateDisplayFormat).toLocaleUpperCase()); isValid = false; } return isValid; } isSupported(field: FormFieldModel): boolean { - return field && - this.supportedTypes.indexOf(field.type) > -1 && !!field.maxValue; + return field && this.supportedTypes.indexOf(field.type) > -1 && !!field.maxValue; } } @@ -288,14 +254,10 @@ export class MaxDateFieldValidator extends BoundaryDateFieldValidator { * */ export class MinDateTimeFieldValidator implements FormFieldValidator { - - private supportedTypes = [ - FormFieldTypes.DATETIME - ]; + private supportedTypes = [FormFieldTypes.DATETIME]; isSupported(field: FormFieldModel): boolean { - return field && - this.supportedTypes.indexOf(field.type) > -1 && !!field.minValue; + return field && this.supportedTypes.indexOf(field.type) > -1 && !!field.minValue; } validate(field: FormFieldModel): boolean { @@ -318,10 +280,7 @@ export class MinDateTimeFieldValidator implements FormFieldValidator { if (isBefore(fieldValueDate, min)) { field.validationSummary.message = `FORM.FIELD.VALIDATOR.NOT_LESS_THAN`; - field.validationSummary.attributes.set( - 'minValue', - DateFnsUtils.formatDate(min, field.dateDisplayFormat).replace(':', '-') - ); + field.validationSummary.attributes.set('minValue', DateFnsUtils.formatDate(min, field.dateDisplayFormat).replace(':', '-')); isValid = false; } return isValid; @@ -337,14 +296,10 @@ export class MinDateTimeFieldValidator implements FormFieldValidator { * */ export class MaxDateTimeFieldValidator implements FormFieldValidator { - - private supportedTypes = [ - FormFieldTypes.DATETIME - ]; + private supportedTypes = [FormFieldTypes.DATETIME]; isSupported(field: FormFieldModel): boolean { - return field && - this.supportedTypes.indexOf(field.type) > -1 && !!field.maxValue; + return field && this.supportedTypes.indexOf(field.type) > -1 && !!field.maxValue; } validate(field: FormFieldModel): boolean { @@ -367,10 +322,7 @@ export class MaxDateTimeFieldValidator implements FormFieldValidator { if (isAfter(fieldValueDate, max)) { field.validationSummary.message = `FORM.FIELD.VALIDATOR.NOT_GREATER_THAN`; - field.validationSummary.attributes.set( - 'maxValue', - DateFnsUtils.formatDate(max, field.dateDisplayFormat).replace(':', '-') - ); + field.validationSummary.attributes.set('maxValue', DateFnsUtils.formatDate(max, field.dateDisplayFormat).replace(':', '-')); isValid = false; } return isValid; @@ -378,16 +330,10 @@ export class MaxDateTimeFieldValidator implements FormFieldValidator { } export class MinLengthFieldValidator implements FormFieldValidator { - - private supportedTypes = [ - FormFieldTypes.TEXT, - FormFieldTypes.MULTILINE_TEXT - ]; + private supportedTypes = [FormFieldTypes.TEXT, FormFieldTypes.MULTILINE_TEXT]; isSupported(field: FormFieldModel): boolean { - return field && - this.supportedTypes.indexOf(field.type) > -1 && - field.minLength > 0; + return field && this.supportedTypes.indexOf(field.type) > -1 && field.minLength > 0; } validate(field: FormFieldModel): boolean { @@ -404,16 +350,10 @@ export class MinLengthFieldValidator implements FormFieldValidator { } export class MaxLengthFieldValidator implements FormFieldValidator { - - private supportedTypes = [ - FormFieldTypes.TEXT, - FormFieldTypes.MULTILINE_TEXT - ]; + private supportedTypes = [FormFieldTypes.TEXT, FormFieldTypes.MULTILINE_TEXT]; isSupported(field: FormFieldModel): boolean { - return field && - this.supportedTypes.indexOf(field.type) > -1 && - field.maxLength > 0; + return field && this.supportedTypes.indexOf(field.type) > -1 && field.maxLength > 0; } validate(field: FormFieldModel): boolean { @@ -430,17 +370,10 @@ export class MaxLengthFieldValidator implements FormFieldValidator { } export class MinValueFieldValidator implements FormFieldValidator { - - private supportedTypes = [ - FormFieldTypes.NUMBER, - FormFieldTypes.DECIMAL, - FormFieldTypes.AMOUNT - ]; + private supportedTypes = [FormFieldTypes.NUMBER, FormFieldTypes.DECIMAL, FormFieldTypes.AMOUNT]; isSupported(field: FormFieldModel): boolean { - return field && - this.supportedTypes.indexOf(field.type) > -1 && - NumberFieldValidator.isNumber(field.minValue); + return field && this.supportedTypes.indexOf(field.type) > -1 && NumberFieldValidator.isNumber(field.minValue); } validate(field: FormFieldModel): boolean { @@ -461,17 +394,10 @@ export class MinValueFieldValidator implements FormFieldValidator { } export class MaxValueFieldValidator implements FormFieldValidator { - - private supportedTypes = [ - FormFieldTypes.NUMBER, - FormFieldTypes.DECIMAL, - FormFieldTypes.AMOUNT - ]; + private supportedTypes = [FormFieldTypes.NUMBER, FormFieldTypes.DECIMAL, FormFieldTypes.AMOUNT]; isSupported(field: FormFieldModel): boolean { - return field && - this.supportedTypes.indexOf(field.type) > -1 && - NumberFieldValidator.isNumber(field.maxValue); + return field && this.supportedTypes.indexOf(field.type) > -1 && NumberFieldValidator.isNumber(field.maxValue); } validate(field: FormFieldModel): boolean { @@ -492,15 +418,10 @@ export class MaxValueFieldValidator implements FormFieldValidator { } export class RegExFieldValidator implements FormFieldValidator { - - private supportedTypes = [ - FormFieldTypes.TEXT, - FormFieldTypes.MULTILINE_TEXT - ]; + private supportedTypes = [FormFieldTypes.TEXT, FormFieldTypes.MULTILINE_TEXT]; isSupported(field: FormFieldModel): boolean { - return field && - this.supportedTypes.indexOf(field.type) > -1 && !!field.regexPattern; + return field && this.supportedTypes.indexOf(field.type) > -1 && !!field.regexPattern; } validate(field: FormFieldModel): boolean { @@ -513,14 +434,10 @@ export class RegExFieldValidator implements FormFieldValidator { } return true; } - } export class FixedValueFieldValidator implements FormFieldValidator { - - private supportedTypes = [ - FormFieldTypes.TYPEAHEAD - ]; + private supportedTypes = [FormFieldTypes.TYPEAHEAD]; isSupported(field: FormFieldModel): boolean { return field && this.supportedTypes.indexOf(field.type) > -1; @@ -558,10 +475,7 @@ export class FixedValueFieldValidator implements FormFieldValidator { } export class DecimalFieldValidator implements FormFieldValidator { - - private supportedTypes = [ - FormFieldTypes.DECIMAL - ]; + private supportedTypes = [FormFieldTypes.DECIMAL]; isSupported(field: FormFieldModel): boolean { return field && this.supportedTypes.indexOf(field.type) > -1 && !!field.value; diff --git a/lib/core/src/lib/form/components/widgets/core/form-field.model.spec.ts b/lib/core/src/lib/form/components/widgets/core/form-field.model.spec.ts index ec1afd99dd..f5afc90fb2 100644 --- a/lib/core/src/lib/form/components/widgets/core/form-field.model.spec.ts +++ b/lib/core/src/lib/form/components/widgets/core/form-field.model.spec.ts @@ -60,7 +60,7 @@ describe('FormFieldModel', () => { }; const field = new FormFieldModel(new FormModel(), json); Object.keys(json).forEach((key) => { - expect(field[key]).toBe(json[key]); + expect(field[key]).toEqual(json[key]); }); }); @@ -122,6 +122,59 @@ describe('FormFieldModel', () => { expect(field.value).toBe('deferred'); }); + it('should add value to field options if NOT present', () => { + const field = new FormFieldModel(new FormModel(), { + type: FormFieldTypes.DROPDOWN, + options: [], + value: { id: 'id_one', name: 'One' } + }); + + expect(field.options).toEqual([{ id: 'id_one', name: 'One' }]); + expect(field.value).toEqual('id_one'); + }); + + it('should assign "empty" option as value if value is null and "empty" option is present in options', () => { + const field = new FormFieldModel(new FormModel(), { + type: FormFieldTypes.DROPDOWN, + options: [ + { id: 'empty', name: 'Chose one...' }, + { id: 'one', name: 'One' } + ], + value: null + }); + + expect(field.hasEmptyValue).toBe(true); + expect(field.emptyOption).toEqual({ id: 'empty', name: 'Chose one...' }); + expect(field.value).toEqual('empty'); + }); + + it('should set hasEmptyValue to true if "empty" option is present in options', () => { + const field = new FormFieldModel(new FormModel(), { + type: FormFieldTypes.DROPDOWN, + options: [{ id: 'empty', name: 'Choose one...' }], + value: null + }); + + expect(field.hasEmptyValue).toBe(true); + expect(field.emptyOption).toEqual({ id: 'empty', name: 'Choose one...' }); + }); + + it('should add default "empty" option to the options if hasEmptyValue is true but "empty" option is not present', () => { + const field = new FormFieldModel(new FormModel(), { + type: FormFieldTypes.DROPDOWN, + options: [{ id: 'one', name: 'One' }], + value: null, + hasEmptyValue: true + }); + + expect(field.hasEmptyValue).toBe(true); + expect(field.emptyOption).toEqual({ id: 'empty', name: 'Choose one...' }); + expect(field.options).toEqual([ + { id: 'empty', name: 'Choose one...' }, + { id: 'one', name: 'One' } + ]); + }); + it('should parse the date with the default format (D-M-YYYY) if the display format is missing', () => { const form = new FormModel(); const field = new FormFieldModel(form, { diff --git a/lib/core/src/lib/form/components/widgets/core/form-field.model.ts b/lib/core/src/lib/form/components/widgets/core/form-field.model.ts index 4ee7d36069..6b12fa913a 100644 --- a/lib/core/src/lib/form/components/widgets/core/form-field.model.ts +++ b/lib/core/src/lib/form/components/widgets/core/form-field.model.ts @@ -40,6 +40,8 @@ export class FormFieldModel extends FormWidgetModel { readonly defaultDateFormat: string = 'D-M-YYYY'; readonly defaultDateTimeFormat: string = 'D-M-YYYY hh:mm A'; + private readonly defaultEmptyOptionId = 'empty'; + private readonly defaultEmptyOptionName = 'Choose one...'; // model members fieldType: string; @@ -187,8 +189,9 @@ export class FormFieldModel extends FormWidgetModel { this.maxDateRangeValue = json.maxDateRangeValue; this.dynamicDateRangeSelection = json.dynamicDateRangeSelection; this.regexPattern = json.regexPattern; - this.options = json.options || []; - this.hasEmptyValue = json.hasEmptyValue; + this.options = this.parseValidOptions(json.options); + this.emptyOption = this.getEmptyOption(this.options); + this.hasEmptyValue = json?.hasEmptyValue ?? !!this.emptyOption; this.className = json.className; this.optionType = json.optionType; this.params = json.params || {}; @@ -198,7 +201,6 @@ export class FormFieldModel extends FormWidgetModel { this.enableFractions = json.enableFractions; this.currency = json.currency; this.dateDisplayFormat = json.dateDisplayFormat || this.getDefaultDateFormat(json); - this._value = this.parseValue(json); this.validationSummary = new ErrorMessageModel(); this.tooltip = json.tooltip; this.selectionType = json.selectionType; @@ -210,6 +212,7 @@ export class FormFieldModel extends FormWidgetModel { this.schemaDefinition = json.schemaDefinition; this.precision = json.precision; this.externalProperty = json.externalProperty; + this._value = this.parseValue(json); if (json.placeholder && json.placeholder !== '' && json.placeholder !== 'null') { this.placeholder = json.placeholder; @@ -230,18 +233,13 @@ export class FormFieldModel extends FormWidgetModel { this.leftLabels = form.json.leftLabels || false; } - const emptyOption = Array.isArray(this.options) ? this.options.find(({ id }) => id === 'empty') : undefined; - if (this.hasEmptyValue === undefined) { - this.hasEmptyValue = json?.hasEmptyValue ?? !!emptyOption; - } - - if (this.options && this.options.length > 0 && this.hasEmptyValue) { - this.emptyOption = emptyOption; - } - this.updateForm(); } + private getEmptyOption(options: FormFieldOption[]): FormFieldOption { + return options.find((option) => option?.id === this.defaultEmptyOptionId); + } + private setValueForReadonlyType(form: any) { const value = this.getProcessVariableValue(this.params.field, form); if (value) { @@ -308,22 +306,34 @@ export class FormFieldModel extends FormWidgetModel { but saving back as object: { id: , name: } */ if (json.type === FormFieldTypes.DROPDOWN) { - if (json.options) { - if (json.hasEmptyValue) { - const emptyOption = json.options[0]; - if (value === '' || value === emptyOption.id || value === emptyOption.name) { - value = emptyOption.id; - } - } else { - if (value?.id && value?.name) { - value = value.id; - } + if (this.hasEmptyValue) { + if (!this.emptyOption) { + this.emptyOption = { + id: this.defaultEmptyOptionId, + name: this.defaultEmptyOptionName + }; + this.options.unshift(this.emptyOption); + } + + const isEmptyValue = !value || [this.emptyOption.id, this.emptyOption.name].includes(value); + if (isEmptyValue) { + return this.emptyOption.id; } } - if (this.hasMultipleValues) { - value = Array.isArray(json.value) ? json.value : []; + if (this.isValidOption(value)) { + this.addOption(value); + return value.id; } + + if (this.hasMultipleValues) { + const validSelectedOptions = (Array.isArray(json.value) ? json.value : []).filter((option) => this.isValidOption(option)); + + this.addOptions(validSelectedOptions); + return validSelectedOptions; + } + + return value; } /* @@ -337,9 +347,8 @@ export class FormFieldModel extends FormWidgetModel { const entry: FormFieldOption[] = this.options.filter( (opt) => opt.id === value || opt.name === value || (value && (opt.id === value.id || opt.name === value.name)) ); - if (entry.length > 0) { - value = entry[0].id; - } + + return entry.length > 0 ? entry[0].id : value; } /* @@ -359,13 +368,15 @@ export class FormFieldModel extends FormWidgetModel { } if (isValidDate(dateValue)) { - value = DateFnsUtils.formatDate(dateValue, this.dateDisplayFormat); + return DateFnsUtils.formatDate(dateValue, this.dateDisplayFormat); } } + + return value; } if (this.isCheckboxField(json)) { - value = json.value === 'true' || json.value === true; + return json.value === 'true' || json.value === true; } return value; @@ -511,6 +522,29 @@ export class FormFieldModel extends FormWidgetModel { return this.options?.length > 0; } + isEmptyValueOption(option: FormFieldOption): boolean { + return this.hasEmptyValue && option?.id === this.defaultEmptyOptionId; + } + + private addOptions(options: FormFieldOption[]) { + options.forEach((option) => this.addOption(option)); + } + + private addOption(option: FormFieldOption) { + const alreadyExists = this.options.find((opt) => opt?.id === option?.id); + if (!alreadyExists) { + this.options.push(option); + } + } + + private parseValidOptions(options: any): FormFieldOption[] { + return Array.isArray(options) ? options.filter((option) => this.isValidOption(option)) : []; + } + + private isValidOption(option: any): boolean { + return typeof option === 'object' && !Array.isArray(option) && option?.id && option?.name; + } + private isDateField(json: any) { return json.params?.field?.type === FormFieldTypes.DATE || json.type === FormFieldTypes.DATE; } diff --git a/lib/process-services-cloud/src/lib/form/components/widgets/dropdown/dropdown-cloud.widget.spec.ts b/lib/process-services-cloud/src/lib/form/components/widgets/dropdown/dropdown-cloud.widget.spec.ts index 340dc227cb..cd28d70586 100644 --- a/lib/process-services-cloud/src/lib/form/components/widgets/dropdown/dropdown-cloud.widget.spec.ts +++ b/lib/process-services-cloud/src/lib/form/components/widgets/dropdown/dropdown-cloud.widget.spec.ts @@ -64,11 +64,10 @@ describe('DropdownCloudWidgetComponent', () => { describe('Simple Dropdown', () => { beforeEach(() => { - widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id' }), { + widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id', readOnly: false }), { id: 'dropdown-id', name: 'date-name', type: 'dropdown', - readOnly: false, restUrl: 'https://fake-rest-url', options: [{ id: 'empty', name: 'Choose one...' }] }); @@ -120,6 +119,18 @@ describe('DropdownCloudWidgetComponent', () => { expect(await allOptions[2].getText()).toEqual('option_3'); }); + it('should NOT load data from restUrl when field is readonly', () => { + spyOn(formCloudService, 'getRestWidgetData'); + widget.field.readOnly = true; + widget.field.restUrl = 'https://fake-rest-url'; + widget.field.optionType = 'rest'; + widget.field.restIdProperty = 'name'; + + widget.ngOnInit(); + + expect(formCloudService.getRestWidgetData).not.toHaveBeenCalled(); + }); + it('should show error message if the restUrl failed to fetch options', async () => { const jsonDataSpy = spyOn(formCloudService, 'getRestWidgetData').and.returnValue(throwError('Failed to fetch options')); const errorIcon: string = 'error_outline'; @@ -315,15 +326,30 @@ describe('DropdownCloudWidgetComponent', () => { const requiredErrorElement = fixture.debugElement.query(By.css('.adf-dropdown-required-message .adf-error-text')); expect(requiredErrorElement.nativeElement.innerText).toEqual('FORM.FIELD.REQUIRED'); }); + + it('should NOT display a required error when dropdown is readonly', async () => { + widget.field.readOnly = true; + fixture.detectChanges(); + await fixture.whenStable(); + + expect(element.querySelector('.adf-invalid')).toBeFalsy(); + + const dropdownSelect = element.querySelector('.adf-select'); + dropdownSelect.dispatchEvent(new Event('blur')); + + fixture.detectChanges(); + await fixture.whenStable(); + + expect(element.querySelector('.adf-invalid')).toBeFalsy(); + }); }); describe('filter', () => { beforeEach(() => { - widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id' }), { + widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id', readOnly: false }), { id: 'dropdown-id', name: 'option list', type: 'dropdown', - readOnly: false, options: filterOptionList }); widget.ngOnInit(); @@ -370,11 +396,10 @@ describe('DropdownCloudWidgetComponent', () => { describe('multiple selection', () => { it('should show preselected option', async () => { - widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id' }), { + widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id', readOnly: 'false' }), { id: 'dropdown-id', name: 'date-name', type: 'dropdown', - readOnly: 'false', options: fakeOptionList, selectionType: 'multiple', value: [ @@ -389,11 +414,10 @@ describe('DropdownCloudWidgetComponent', () => { }); it('should support multiple options', async () => { - widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id' }), { + widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id', readOnly: 'false' }), { id: 'dropdown-id', name: 'date-name', type: 'dropdown', - readOnly: 'false', selectionType: 'multiple', options: fakeOptionList }); @@ -408,11 +432,10 @@ describe('DropdownCloudWidgetComponent', () => { }); it('should show preselected option for rest options', async () => { - widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id' }), { + widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id', readOnly: 'false' }), { id: 'dropdown-id', name: 'date-name', type: 'dropdown', - readOnly: 'false', restUrl: 'https://fake-rest-url', optionType: 'rest', selectionType: 'multiple', @@ -448,11 +471,10 @@ describe('DropdownCloudWidgetComponent', () => { }); it('should support multiple options for rest options', async () => { - widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id' }), { + widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id', readOnly: 'false' }), { id: 'dropdown-id', name: 'date-name', type: 'dropdown', - readOnly: 'false', restUrl: 'https://fake-rest-url', optionType: 'rest', selectionType: 'multiple' @@ -498,11 +520,10 @@ describe('DropdownCloudWidgetComponent', () => { validate: () => true }); beforeEach(() => { - widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id' }), { + widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id', readOnly: 'false' }), { id: 'child-dropdown-id', name: 'child-dropdown', type: 'dropdown', - readOnly: 'false', optionType: 'rest', restUrl: 'myFakeDomain.com/cities?country=${parentDropdown}', rule: { @@ -605,11 +626,10 @@ describe('DropdownCloudWidgetComponent', () => { const parentDropdown = new FormFieldModel(new FormModel(), { id: 'parentDropdown', type: 'dropdown' }); beforeEach(() => { - widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id' }), { + widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id', readOnly: 'false' }), { id: 'child-dropdown-id', name: 'child-dropdown', type: 'dropdown', - readOnly: 'false', optionType: 'manual', rule: { ruleOn: 'parentDropdown', @@ -694,11 +714,10 @@ describe('DropdownCloudWidgetComponent', () => { describe('Load selection for linked dropdown (i.e. saved, completed forms)', () => { it('should load the selection of a manual type linked dropdown', () => { - widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id' }), { + widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id', readOnly: 'false' }), { id: 'child-dropdown-id', name: 'child-dropdown', type: 'dropdown', - readOnly: 'false', optionType: 'manual', rule: { ruleOn: 'parentDropdown', @@ -718,11 +737,10 @@ describe('DropdownCloudWidgetComponent', () => { it('should load the selection of a rest type linked dropdown', () => { const jsonDataSpy = spyOn(formCloudService, 'getRestWidgetData').and.returnValue(of(mockRestDropdownOptions)); - widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id' }), { + widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id', readOnly: 'false' }), { id: 'child-dropdown-id', name: 'child-dropdown', type: 'dropdown', - readOnly: 'false', restUrl: 'mock-url.com/country=${country}', optionType: 'rest', rule: { @@ -744,11 +762,10 @@ describe('DropdownCloudWidgetComponent', () => { describe('when form model has left labels', () => { it('should have left labels classes on leftLabels true', async () => { - widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id', leftLabels: true }), { + widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id', readOnly: false, leftLabels: true }), { id: 'dropdown-id', name: 'option list', type: FormFieldTypes.DROPDOWN, - readOnly: false, options: filterOptionList }); @@ -763,11 +780,10 @@ describe('DropdownCloudWidgetComponent', () => { }); it('should not have left labels classes on leftLabels false', async () => { - widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id', leftLabels: false }), { + widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id', readOnly: false, leftLabels: false }), { id: 'dropdown-id', name: 'option list', type: FormFieldTypes.DROPDOWN, - readOnly: false, options: filterOptionList }); @@ -782,11 +798,10 @@ describe('DropdownCloudWidgetComponent', () => { }); it('should not have left labels classes on leftLabels not present', async () => { - widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id' }), { + widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id', readOnly: false }), { id: 'dropdown-id', name: 'option list', type: FormFieldTypes.DROPDOWN, - readOnly: false, options: filterOptionList }); @@ -813,11 +828,10 @@ describe('DropdownCloudWidgetComponent', () => { processVariables?: TaskVariableCloud[], variables?: TaskVariableCloud[] ) => - new FormFieldModel(new FormModel({ taskId: 'fake-task-id', processVariables, variables }), { + new FormFieldModel(new FormModel({ taskId: 'fake-task-id', readOnly: 'false', processVariables, variables }), { id: 'variable-dropdown-id', name: 'variable-options-dropdown', type: 'dropdown', - readOnly: 'false', optionType: 'variable', variableConfig: { variableName, @@ -961,5 +975,20 @@ describe('DropdownCloudWidgetComponent', () => { const failedErrorMsgElement = fixture.debugElement.query(By.css('.adf-dropdown-failed-message')); expect(failedErrorMsgElement).toBeNull(); }); + + it('should NOT display errors if field is readonly', () => { + widget.field = getVariableDropdownWidget( + 'variables.wrong-variable-id', + 'response.wrongPath.players', + 'wrongId', + 'wrongFullName', + mockProcessVariablesWithJson + ); + widget.field.readOnly = true; + fixture.detectChanges(); + + const failedErrorMsgElement = fixture.debugElement.query(By.css('.adf-dropdown-failed-message')); + expect(failedErrorMsgElement).toBeNull(); + }); }); }); diff --git a/lib/process-services-cloud/src/lib/form/components/widgets/dropdown/dropdown-cloud.widget.ts b/lib/process-services-cloud/src/lib/form/components/widgets/dropdown/dropdown-cloud.widget.ts index 57e1e1e23b..3b852b85ad 100644 --- a/lib/process-services-cloud/src/lib/form/components/widgets/dropdown/dropdown-cloud.widget.ts +++ b/lib/process-services-cloud/src/lib/form/components/widgets/dropdown/dropdown-cloud.widget.ts @@ -84,7 +84,9 @@ export class DropdownCloudWidgetComponent extends WidgetComponent implements OnI private checkFieldOptionsSource(): void { switch (true) { - case this.field.restUrl && !this.isLinkedWidget(): + case this.isReadOnly(): + break; + case this.hasRestUrl() && !this.isLinkedWidget(): this.persistFieldOptionsFromRestApi(); break; @@ -377,7 +379,7 @@ export class DropdownCloudWidgetComponent extends WidgetComponent implements OnI } private isValidRestType(): boolean { - return this.field.optionType === 'rest' && !!this.field.restUrl; + return this.field.optionType === 'rest' && this.hasRestUrl(); } private setPreviewState(): void { @@ -390,6 +392,14 @@ export class DropdownCloudWidgetComponent extends WidgetComponent implements OnI } } + private isReadOnly(): boolean { + return this.field.readOnly; + } + + private hasRestUrl(): boolean { + return !!this.field.restUrl; + } + isReadOnlyType(): boolean { return this.field.type === 'readonly'; } @@ -400,6 +410,10 @@ export class DropdownCloudWidgetComponent extends WidgetComponent implements OnI } updateOptions(): void { + if (this.isReadOnly()) { + this.list$ = of(this.field.options); + } + this.showInputFilter = this.field.options.length > this.appConfig.get('form.dropDownFilterLimit', HIDE_FILTER_LIMIT); this.list$ = combineLatest([of(this.field.options), this.filter$]).pipe( map(([items, search]) => { diff --git a/lib/process-services/src/lib/form/form.component.spec.ts b/lib/process-services/src/lib/form/form.component.spec.ts index 10a59333b4..ee895df1a8 100644 --- a/lib/process-services/src/lib/form/form.component.spec.ts +++ b/lib/process-services/src/lib/form/form.component.spec.ts @@ -944,10 +944,13 @@ describe('FormComponent', () => { const formValues: any = {}; formValues.dropdownId = { - id: 'option_2', - name: 'test2' + id: 'dropdown_option_2', + name: 'Dropdown option 2' + }; + formValues.radio = { + id: 'radio_option_3', + name: 'Radio option 3' }; - formValues.radio = { id: 'option_2', name: 'Option 2' }; const change = new SimpleChange(null, formValues, false); formComponent.data = formValues; formComponent.ngOnChanges({ data: change }); @@ -956,9 +959,9 @@ describe('FormComponent', () => { dropdownField = formFields.find((field) => field.id === 'dropdownId'); radioField = formFields.find((field) => field.id === 'radio'); - expect(dropdownField.value.id).toBe('option_2'); - expect(dropdownField.value.name).toBe('test2'); - expect(radioField.value).toBe('option_2'); + expect(dropdownField.value).toBe('dropdown_option_2'); + expect(radioField.value.id).toBe('radio_option_3'); + expect(radioField.value.name).toBe('Radio option 3'); }); it('should refresh radio buttons value when id is given to data', () => {