From 333e558d735c4b5fad313951370f2fb3326897ea Mon Sep 17 00:00:00 2001 From: kurilova Date: Mon, 24 Jun 2024 09:43:54 +0000 Subject: [PATCH] Fix validation; change element for text-long --- modules/ui/src/app/mocks/profile.mock.ts | 1 + .../profile-form/profile-form.component.html | 27 +++- .../profile-form.component.spec.ts | 135 ++++++++---------- .../profile-form/profile-form.component.ts | 14 +- .../profile-form/profile.validators.ts | 13 +- 5 files changed, 103 insertions(+), 87 deletions(-) diff --git a/modules/ui/src/app/mocks/profile.mock.ts b/modules/ui/src/app/mocks/profile.mock.ts index 596f922f8..6f6a36b0e 100644 --- a/modules/ui/src/app/mocks/profile.mock.ts +++ b/modules/ui/src/app/mocks/profile.mock.ts @@ -33,6 +33,7 @@ export const PROFILE_FORM: ProfileFormat[] = [ type: FormControlType.EMAIL_MULTIPLE, validation: { required: true, + max: '30', }, }, { diff --git a/modules/ui/src/app/pages/risk-assessment/profile-form/profile-form.component.html b/modules/ui/src/app/pages/risk-assessment/profile-form/profile-form.component.html index b57d93f04..2cd54d328 100644 --- a/modules/ui/src/app/pages/risk-assessment/profile-form/profile-form.component.html +++ b/modules/ui/src/app/pages/risk-assessment/profile-form/profile-form.component.html @@ -178,6 +178,13 @@ The field is required + + The field must be a maximum of + {{ getControl(formControlName).getError('maxlength').requiredLength }} + characters. + @@ -190,10 +197,12 @@ floatLabel="always" class="profile-form-field" [formGroup]="profileForm"> - + [formControlName]="formControlName"> {{ description }} The field is required + + The field must be a maximum of + {{ getControl(formControlName).getError('maxlength').requiredLength }} + characters. + @@ -230,6 +246,13 @@ letters, numbers, @ and . (dot). + + The field must be a maximum of + {{ getControl(formControlName).getError('maxlength').requiredLength }} + characters. + diff --git a/modules/ui/src/app/pages/risk-assessment/profile-form/profile-form.component.spec.ts b/modules/ui/src/app/pages/risk-assessment/profile-form/profile-form.component.spec.ts index 3f3f3e5a3..a1e1b9177 100644 --- a/modules/ui/src/app/pages/risk-assessment/profile-form/profile-form.component.spec.ts +++ b/modules/ui/src/app/pages/risk-assessment/profile-form/profile-form.component.spec.ts @@ -146,6 +146,9 @@ describe('ProfileFormComponent', () => { } else if (item.type === FormControlType.SELECT_MULTIPLE) { const select = fields[uiIndex].querySelector('mat-checkbox'); expect(select).toBeTruthy(); + } else if (item.type === FormControlType.TEXTAREA) { + const input = fields[uiIndex]?.querySelector('textarea'); + expect(input).toBeTruthy(); } else { const input = fields[uiIndex]?.querySelector('input'); expect(input).toBeTruthy(); @@ -202,99 +205,87 @@ describe('ProfileFormComponent', () => { } if ( - (item.type === FormControlType.TEXT || - item.type === FormControlType.TEXTAREA) && - item.validation?.required + item.type === FormControlType.TEXT || + item.type === FormControlType.TEXTAREA || + item.type === FormControlType.EMAIL_MULTIPLE ) { - describe('text or text-long', () => { - it('should have "required" error when field is not filled', () => { - const fields = compiled.querySelectorAll('.profile-form-field'); - const uiIndex = index + 1; // as Profile name is at 0 position, the json items start from 1 i - const input: HTMLInputElement = fields[uiIndex].querySelector( - 'input' - ) as HTMLInputElement; - ['', ' '].forEach(value => { - input.value = value; - input.dispatchEvent(new Event('input')); - component.getControl(index).markAsTouched(); - fixture.detectChanges(); - - const error = - fields[uiIndex].querySelector('mat-error')?.textContent; - - expect(error).toContain('The field is required'); - }); - }); - - it('should have "invalid_format" error when field does not satisfy validation rules', () => { - [ - 'very long value very long value very long value very long value very long value very long value very long value very long value very long value very long value', - 'as\\\\\\\\\\""""""""', - ].forEach(value => { + describe('text or text-long or email-multiple', () => { + if (item.validation?.required) { + it('should have "required" error when field is not filled', () => { const fields = compiled.querySelectorAll('.profile-form-field'); const uiIndex = index + 1; // as Profile name is at 0 position, the json items start from 1 i - const input: HTMLInputElement = fields[uiIndex].querySelector( - 'input' + const input = fields[uiIndex].querySelector( + '.mat-mdc-input-element' ) as HTMLInputElement; - input.value = value; - input.dispatchEvent(new Event('input')); - component.getControl(index).markAsTouched(); - fixture.detectChanges(); - - const error = compiled.querySelector('mat-error')?.textContent; - expect(error).toContain( - 'Please, check. “ and \\ are not allowed.' - ); + ['', ' '].forEach(value => { + input.value = value; + input.dispatchEvent(new Event('input')); + component.getControl(index).markAsTouched(); + fixture.detectChanges(); + const errors = fields[uiIndex].querySelectorAll('mat-error'); + let hasError = false; + errors.forEach(error => { + if (error.textContent === 'The field is required') { + hasError = true; + } + }); + + expect(hasError).toBeTrue(); + }); }); - }); - }); - } + } - if ( - item.type === FormControlType.EMAIL_MULTIPLE && - item.validation?.required - ) { - describe('text or text-long', () => { - it('should have "required" error when field is not filled', () => { + it('should have "invalid_format" error when field does not satisfy validation rules', () => { const fields = compiled.querySelectorAll('.profile-form-field'); const uiIndex = index + 1; // as Profile name is at 0 position, the json items start from 1 i const input: HTMLInputElement = fields[uiIndex].querySelector( - 'input' + '.mat-mdc-input-element' ) as HTMLInputElement; - ['', ' '].forEach(value => { - input.value = value; - input.dispatchEvent(new Event('input')); - component.getControl(index).markAsTouched(); - fixture.detectChanges(); - - const error = - fields[uiIndex].querySelector('mat-error')?.textContent; - - expect(error).toContain('The field is required'); + input.value = 'as\\\\\\\\\\""""""""'; + input.dispatchEvent(new Event('input')); + component.getControl(index).markAsTouched(); + fixture.detectChanges(); + const result = + item.type === FormControlType.EMAIL_MULTIPLE + ? 'Please, check the email address. Valid e-mail can contain only latin letters, numbers, @ and . (dot).' + : 'Please, check. “ and \\ are not allowed.'; + const errors = fields[uiIndex].querySelectorAll('mat-error'); + let hasError = false; + errors.forEach(error => { + if (error.textContent === result) { + hasError = true; + } }); + + expect(hasError).toBeTrue(); }); - it('should have "invalid_format" error when field does not satisfy validation rules', () => { - [ - 'very long value very long value very long value very long value very long value very long value very long value very long value very long value very long value', - 'as\\\\\\\\\\""""""""', - ].forEach(value => { + if (item.validation?.max) { + it('should have "maxlength" error when field is exceeding max length', () => { const fields = compiled.querySelectorAll('.profile-form-field'); const uiIndex = index + 1; // as Profile name is at 0 position, the json items start from 1 i const input: HTMLInputElement = fields[uiIndex].querySelector( - 'input' + '.mat-mdc-input-element' ) as HTMLInputElement; - input.value = value; + input.value = + 'very long value very long value very long value very long value very long value very long value very long value very long value very long value very long value'; input.dispatchEvent(new Event('input')); component.getControl(index).markAsTouched(); fixture.detectChanges(); - const error = compiled.querySelector('mat-error')?.textContent; - expect(error).toContain( - 'Please, check the email address. Valid e-mail can contain only latin letters, numbers, @ and . (dot).' - ); + const errors = fields[uiIndex].querySelectorAll('mat-error'); + let hasError = false; + errors.forEach(error => { + if ( + error.textContent === + `The field must be a maximum of ${item.validation?.max} characters.` + ) { + hasError = true; + } + }); + expect(hasError).toBeTrue(); }); - }); + } }); } }); @@ -318,7 +309,7 @@ describe('ProfileFormComponent', () => { describe('Save button', () => { it('should be enabled when required fields are present', () => { component.nameControl.setValue('test'); - component.getControl('0').setValue('test@test.test'); + component.getControl('0').setValue('a@test.te;b@test.te, c@test.te'); component.getControl('1').setValue('test'); component.getControl('2').setValue('test'); component.getControl('3').setValue({ 0: true, 1: true, 2: true }); diff --git a/modules/ui/src/app/pages/risk-assessment/profile-form/profile-form.component.ts b/modules/ui/src/app/pages/risk-assessment/profile-form/profile-form.component.ts index 1f0ee7656..9270abc4e 100644 --- a/modules/ui/src/app/pages/risk-assessment/profile-form/profile-form.component.ts +++ b/modules/ui/src/app/pages/risk-assessment/profile-form/profile-form.component.ts @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import { TextFieldModule } from '@angular/cdk/text-field'; import { ChangeDetectionStrategy, Component, @@ -31,6 +32,7 @@ import { FormGroup, ReactiveFormsModule, ValidatorFn, + Validators, } from '@angular/forms'; import { MatInputModule } from '@angular/material/input'; import { DeviceValidators } from '../../devices/components/device-form/device.validators'; @@ -54,6 +56,7 @@ import { ProfileValidators } from './profile.validators'; MatFormFieldModule, MatSelectModule, MatCheckboxModule, + TextFieldModule, ], templateUrl: './profile-form.component.html', styleUrl: './profile-form.component.scss', @@ -109,15 +112,14 @@ export class ProfileFormComponent implements OnInit { if (validation.required) { validators.push(this.profileValidators.textRequired()); } + if (validation.max) { + validators.push(Validators.maxLength(Number(validation.max))); + } if (type === FormControlType.EMAIL_MULTIPLE) { - validators.push( - this.profileValidators.emailStringFormat(Number(validation.max)) - ); + validators.push(this.profileValidators.emailStringFormat()); } if (type === FormControlType.TEXT || type === FormControlType.TEXTAREA) { - validators.push( - this.profileValidators.textFormat(Number(validation.max)) - ); + validators.push(this.profileValidators.textFormat()); } } return validators; diff --git a/modules/ui/src/app/pages/risk-assessment/profile-form/profile.validators.ts b/modules/ui/src/app/pages/risk-assessment/profile-form/profile.validators.ts index fe5f60585..720efae97 100644 --- a/modules/ui/src/app/pages/risk-assessment/profile-form/profile.validators.ts +++ b/modules/ui/src/app/pages/risk-assessment/profile-form/profile.validators.ts @@ -25,7 +25,7 @@ import { Profile } from '../../../model/profile'; @Injectable({ providedIn: 'root' }) export class ProfileValidators { readonly MULTIPLE_EMAIL_FORMAT_REGEXP = new RegExp( - '^(([a-zA-Z0-9_\\-\\.]+)@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.)|(([a-zA-Z0-9\\-]+\\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\\]?)(\\s*;\\s*|\\s*$))*$', + '^(([a-zA-Z0-9_\\-\\.]+)@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.)|(([a-zA-Z0-9\\-]+\\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\\]?)(\\s*(;|,)\\s*|\\s*$))*$', 'i' ); @@ -58,19 +58,18 @@ export class ProfileValidators { return null; } - public emailStringFormat(maxLength: number = 128): ValidatorFn { - return this.stringFormat(this.MULTIPLE_EMAIL_FORMAT_REGEXP, maxLength); + public emailStringFormat(): ValidatorFn { + return this.stringFormat(this.MULTIPLE_EMAIL_FORMAT_REGEXP); } - public textFormat(maxLength: number = 128): ValidatorFn { - return this.stringFormat(this.STRING_FORMAT_REGEXP, maxLength); + public textFormat(): ValidatorFn { + return this.stringFormat(this.STRING_FORMAT_REGEXP); } - private stringFormat(regExp: RegExp, maxLength: number = 28): ValidatorFn { + private stringFormat(regExp: RegExp): ValidatorFn { return (control: AbstractControl): ValidationErrors | null => { const value = control.value?.trim(); if (value) { - if (value.length > maxLength) return { invalid_format: true }; const result = regExp.test(value); return !result ? { invalid_format: true } : null; }