From a4c2789f27d4bc6a611cba03a94b9cbb145b8174 Mon Sep 17 00:00:00 2001 From: Volha Mardvilka Date: Mon, 25 Mar 2024 12:16:07 +0000 Subject: [PATCH] 328405692: (fix) [a11y] add validation, error messages, hints for filters modal --- .../filter-dialog.component.html | 39 +++++++++++++++- .../filter-dialog.component.scss | 13 ++++++ .../filter-dialog.component.spec.ts | 44 +++++++++++++++++++ .../filter-dialog/filter-dialog.component.ts | 26 ++++++++++- 4 files changed, 119 insertions(+), 3 deletions(-) diff --git a/modules/ui/src/app/pages/reports/components/filter-dialog/filter-dialog.component.html b/modules/ui/src/app/pages/reports/components/filter-dialog/filter-dialog.component.html index 459ad20d6..f4b88c87f 100644 --- a/modules/ui/src/app/pages/reports/components/filter-dialog/filter-dialog.component.html +++ b/modules/ui/src/app/pages/reports/components/filter-dialog/filter-dialog.component.html @@ -21,21 +21,44 @@ appearance="outline" class="text-field" *ngIf="data.filter === FilterName.DeviceInfo"> + Device + Please enter device model name + + Please, check. The device model name must be a maximum of 64 + characters. Only letters, numbers, and accented letters are + permitted. + + Firmware + Please enter firmware name + + Please, check. The firmware name must be a maximum of 64 characters. + Only letters, numbers, and accented letters are permitted. +

+ + mm/dd/yyyy - mm/dd/yyyy + MM/DD/YYYY – MM/DD/YYYY + + Please, select the correct date range in MM/DD/YYYY format. + { closeSpy.calls.reset(); }); + it('should not close dialog with invalid date on "confirm" click', () => { + fixture.detectChanges(); + component.filterForm.get('deviceInfo')?.setValue('as&@3$'); + const closeSpy = spyOn(component.dialogRef, 'close'); + const confirmButton = compiled.querySelector( + '.confirm-button' + ) as HTMLButtonElement; + + confirmButton?.click(); + + expect(closeSpy).not.toHaveBeenCalled(); + + closeSpy.calls.reset(); + }); + + it('should have "invalid_format" error if 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', + 'as&@3$', + ].forEach(value => { + component.data = { + trigger: mockClientRest, + filter: FilterName.DeviceFirmware, + }; + fixture.detectChanges(); + + const firmware: HTMLInputElement = compiled.querySelector( + '.firmware-input' + ) as HTMLInputElement; + firmware.value = value; + firmware.dispatchEvent(new Event('input')); + component.deviceFirmware.markAsTouched(); + fixture.detectChanges(); + + const firmwareError = compiled.querySelector('mat-error')?.innerHTML; + const error = component.deviceFirmware.hasError('invalid_format'); + + expect(error).toBeTruthy(); + expect(firmwareError).toContain( + 'The firmware name must be a maximum of 64 characters. Only letters, numbers, and accented letters are permitted.' + ); + }); + }); + describe('date filter', () => { beforeEach(() => { component.data = { diff --git a/modules/ui/src/app/pages/reports/components/filter-dialog/filter-dialog.component.ts b/modules/ui/src/app/pages/reports/components/filter-dialog/filter-dialog.component.ts index aed20af50..f8fea286b 100644 --- a/modules/ui/src/app/pages/reports/components/filter-dialog/filter-dialog.component.ts +++ b/modules/ui/src/app/pages/reports/components/filter-dialog/filter-dialog.component.ts @@ -31,11 +31,13 @@ import { } from '@angular/material/dialog'; import { MatButtonModule } from '@angular/material/button'; import { + AbstractControl, FormArray, FormBuilder, FormControl, FormGroup, FormsModule, + NgModel, ReactiveFormsModule, } from '@angular/forms'; import { MatFormFieldModule } from '@angular/material/form-field'; @@ -57,6 +59,7 @@ import { } from '../../../../model/filters'; import { EscapableDialogComponent } from '../../../../components/escapable-dialog/escapable-dialog.component'; import { StatusOfTestResult } from '../../../../model/testrun-status'; +import { DeviceValidators } from '../../../devices/components/device-form/device.validators'; interface DialogData { trigger: ElementRef; @@ -116,15 +119,26 @@ export class FilterDialogComponent } @ViewChild(MatCalendar) calendar!: MatCalendar; + @ViewChild('startDate') startDate!: NgModel; + @ViewChild('endDate') endDate!: NgModel; constructor( public override dialogRef: MatDialogRef, + private deviceValidators: DeviceValidators, @Inject(MAT_DIALOG_DATA) public data: DialogData, private fb: FormBuilder ) { super(dialogRef); } + get deviceInfo() { + return this.filterForm.get('deviceInfo') as AbstractControl; + } + + get deviceFirmware() { + return this.filterForm.get('deviceFirmware') as AbstractControl; + } + ngOnInit() { this.setDialogView(); this.createFilterForm(); @@ -147,8 +161,8 @@ export class FilterDialogComponent } private createFilterForm() { this.filterForm = this.fb.group({ - deviceInfo: [''], - deviceFirmware: [''], + deviceInfo: ['', [this.deviceValidators.deviceStringFormat()]], + deviceFirmware: ['', [this.deviceValidators.deviceStringFormat()]], results: new FormArray(this.resultList.map(() => new FormControl(false))), }); } @@ -175,6 +189,14 @@ export class FilterDialogComponent } confirm(): void { + if ( + this.filterForm?.invalid || + this.startDate?.invalid || + this.endDate?.invalid + ) { + return; + } + const formData = this.filterForm.value; const results = this.resultList .filter((item, i) => {