From: Stephan Müller Date: Thu, 2 Aug 2018 10:48:52 +0000 (+0200) Subject: mgr/dashboard: Use form helper in dashboard tests X-Git-Tag: v14.1.0~1047^2~1 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=5dc94fb521636aefcb4ec8fe98af7d869873a74f;p=ceph.git mgr/dashboard: Use form helper in dashboard tests Using form helper in pool, RGW user, user and role form tests and although in the cd-validator tests. Fixes: https://tracker.ceph.com/issues/36467 Signed-off-by: Stephan Müller --- diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/pool-form/pool-form.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/pool-form/pool-form.component.spec.ts index dd550fd6af6f..c5ad64d39a2a 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/pool-form/pool-form.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/pool-form/pool-form.component.spec.ts @@ -8,7 +8,7 @@ import { RouterTestingModule } from '@angular/router/testing'; import { ToastModule } from 'ng2-toastr'; import { of } from 'rxjs'; -import { configureTestBed } from '../../../../testing/unit-test-helper'; +import { configureTestBed, FormHelper } from '../../../../testing/unit-test-helper'; import { NotFoundComponent } from '../../../core/not-found/not-found.component'; import { ErasureCodeProfileService } from '../../../shared/api/erasure-code-profile.service'; import { PoolService } from '../../../shared/api/pool.service'; @@ -24,29 +24,16 @@ import { PoolFormComponent } from './pool-form.component'; describe('PoolFormComponent', () => { const OSDS = 8; + let formHelper: FormHelper; let component: PoolFormComponent; let fixture: ComponentFixture; let poolService: PoolService; let form: CdFormGroup; let router: Router; - const hasError = (control: AbstractControl, error: string) => { - expect(control.hasError(error)).toBeTruthy(); - }; - - const isValid = (control: AbstractControl) => { - expect(control.valid).toBeTruthy(); - }; - - const setValue = (controlName: string, value: any): AbstractControl => { - const control = form.get(controlName); - control.setValue(value); - return control; - }; - const setPgNum = (pgs): AbstractControl => { - setValue('poolType', 'erasure'); - const control = setValue('pgNum', pgs); + formHelper.setValue('poolType', 'erasure'); + const control = formHelper.setValue('pgNum', pgs); fixture.detectChanges(); fixture.debugElement.query(By.css('#pgNum')).nativeElement.dispatchEvent(new Event('blur')); return control; @@ -88,6 +75,7 @@ describe('PoolFormComponent', () => { } ]; component.info['crush_rules_' + type].push(rule); + return rule; }; const testSubmit = (pool: any, taskName: string, poolServiceMethod: 'create' | 'update') => { @@ -122,6 +110,7 @@ describe('PoolFormComponent', () => { }; component.ecProfiles = []; form = component.form; + formHelper = new FormHelper(form); }; const routes: Routes = [{ path: '404', component: NotFoundComponent }]; @@ -215,33 +204,33 @@ describe('PoolFormComponent', () => { it('is invalid at the beginning all sub forms are valid', () => { expect(form.valid).toBeFalsy(); - ['name', 'poolType', 'pgNum'].forEach((name) => hasError(form.get(name), 'required')); + ['name', 'poolType', 'pgNum'].forEach((name) => formHelper.expectError(name, 'required')); ['crushRule', 'size', 'erasureProfile', 'ecOverwrites'].forEach((name) => - isValid(form.get(name)) + formHelper.expectValid(name) ); expect(component.compressionForm.valid).toBeTruthy(); }); it('validates name', () => { - hasError(form.get('name'), 'required'); - isValid(setValue('name', 'some-name')); + formHelper.expectError('name', 'required'); + formHelper.expectValidChange('name', 'some-name'); component.info.pool_names.push('someExistingPoolName'); - hasError(setValue('name', 'someExistingPoolName'), 'uniqueName'); - hasError(setValue('name', 'wrong format with spaces'), 'pattern'); + formHelper.expectErrorChange('name', 'someExistingPoolName', 'uniqueName'); + formHelper.expectErrorChange('name', 'wrong format with spaces', 'pattern'); }); it('validates poolType', () => { - hasError(form.get('poolType'), 'required'); - isValid(setValue('poolType', 'erasure')); - isValid(setValue('poolType', 'replicated')); + formHelper.expectError('poolType', 'required'); + formHelper.expectValidChange('poolType', 'erasure'); + formHelper.expectValidChange('poolType', 'replicated'); }); it('validates pgNum in creation mode', () => { - hasError(form.get('pgNum'), 'required'); - setValue('poolType', 'erasure'); - isValid(setPgNum(-28)); + formHelper.expectError(form.get('pgNum'), 'required'); + formHelper.setValue('poolType', 'erasure'); + formHelper.expectValid(setPgNum(-28)); expect(form.getValue('pgNum')).toBe(1); - isValid(setPgNum(15)); + formHelper.expectValid(setPgNum(15)); expect(form.getValue('pgNum')).toBe(16); }); @@ -262,31 +251,31 @@ describe('PoolFormComponent', () => { component.data.pool.pg_num = 16; component.editing = true; component.ngOnInit(); - hasError(setPgNum('8'), 'noDecrease'); + formHelper.expectError(setPgNum('8'), 'noDecrease'); }); it('is valid if pgNum, poolType and name are valid', () => { - setValue('name', 'some-name'); - setValue('poolType', 'erasure'); + formHelper.setValue('name', 'some-name'); + formHelper.setValue('poolType', 'erasure'); setPgNum(1); expect(form.valid).toBeTruthy(); }); it('validates crushRule', () => { - isValid(form.get('crushRule')); - hasError(setValue('crushRule', { min_size: 20 }), 'tooFewOsds'); + formHelper.expectValid('crushRule'); + formHelper.expectErrorChange('crushRule', { min_size: 20 }, 'tooFewOsds'); }); it('validates size', () => { - setValue('poolType', 'replicated'); - isValid(form.get('size')); - setValue('crushRule', { + formHelper.setValue('poolType', 'replicated'); + formHelper.expectValid('size'); + formHelper.setValue('crushRule', { min_size: 2, max_size: 6 }); - hasError(setValue('size', 1), 'min'); - hasError(setValue('size', 8), 'max'); - isValid(setValue('size', 6)); + formHelper.expectErrorChange('size', 1, 'min'); + formHelper.expectErrorChange('size', 8, 'max'); + formHelper.expectValidChange('size', 6); }); it('validates compression mode default value', () => { @@ -295,8 +284,8 @@ describe('PoolFormComponent', () => { describe('compression form', () => { beforeEach(() => { - setValue('poolType', 'replicated'); - setValue('mode', 'passive'); + formHelper.setValue('poolType', 'replicated'); + formHelper.setValue('mode', 'passive'); }); it('is valid', () => { @@ -304,50 +293,50 @@ describe('PoolFormComponent', () => { }); it('validates minBlobSize to be only valid between 0 and maxBlobSize', () => { - hasError(setValue('minBlobSize', -1), 'min'); - isValid(setValue('minBlobSize', 0)); - setValue('maxBlobSize', '2 KiB'); - hasError(setValue('minBlobSize', '3 KiB'), 'maximum'); - isValid(setValue('minBlobSize', '1.9 KiB')); + formHelper.expectErrorChange('minBlobSize', -1, 'min'); + formHelper.expectValidChange('minBlobSize', 0); + formHelper.setValue('maxBlobSize', '2 KiB'); + formHelper.expectErrorChange('minBlobSize', '3 KiB', 'maximum'); + formHelper.expectValidChange('minBlobSize', '1.9 KiB'); }); it('validates minBlobSize converts numbers', () => { - const control = setValue('minBlobSize', '1'); + const control = formHelper.setValue('minBlobSize', '1'); fixture.detectChanges(); - isValid(control); + formHelper.expectValid(control); expect(control.value).toBe('1 KiB'); }); it('validates maxBlobSize to be only valid bigger than minBlobSize', () => { - hasError(setValue('maxBlobSize', -1), 'min'); - setValue('minBlobSize', '1 KiB'); - hasError(setValue('maxBlobSize', '0.5 KiB'), 'minimum'); - isValid(setValue('maxBlobSize', '1.5 KiB')); + formHelper.expectErrorChange('maxBlobSize', -1, 'min'); + formHelper.setValue('minBlobSize', '1 KiB'); + formHelper.expectErrorChange('maxBlobSize', '0.5 KiB', 'minimum'); + formHelper.expectValidChange('maxBlobSize', '1.5 KiB'); }); it('s valid to only use one blob size', () => { - isValid(setValue('minBlobSize', '1 KiB')); - isValid(setValue('maxBlobSize', '')); - isValid(setValue('minBlobSize', '')); - isValid(setValue('maxBlobSize', '1 KiB')); + formHelper.expectValid(formHelper.setValue('minBlobSize', '1 KiB')); + formHelper.expectValid(formHelper.setValue('maxBlobSize', '')); + formHelper.expectValid(formHelper.setValue('minBlobSize', '')); + formHelper.expectValid(formHelper.setValue('maxBlobSize', '1 KiB')); }); it('dismisses any size error if one of the blob sizes is changed into a valid state', () => { - const min = setValue('minBlobSize', '10 KiB'); - const max = setValue('maxBlobSize', '1 KiB'); + const min = formHelper.setValue('minBlobSize', '10 KiB'); + const max = formHelper.setValue('maxBlobSize', '1 KiB'); fixture.detectChanges(); max.setValue(''); - isValid(min); - isValid(max); + formHelper.expectValid(min); + formHelper.expectValid(max); max.setValue('1 KiB'); fixture.detectChanges(); min.setValue('0.5 KiB'); - isValid(min); - isValid(max); + formHelper.expectValid(min); + formHelper.expectValid(max); }); it('validates maxBlobSize converts numbers', () => { - const control = setValue('maxBlobSize', '2'); + const control = formHelper.setValue('maxBlobSize', '2'); fixture.detectChanges(); expect(control.value).toBe('2 KiB'); }); @@ -364,27 +353,27 @@ describe('PoolFormComponent', () => { }); it('validates ratio to be only valid between 0 and 1', () => { - isValid(form.get('ratio')); - hasError(setValue('ratio', -0.1), 'min'); - isValid(setValue('ratio', 0)); - isValid(setValue('ratio', 1)); - hasError(setValue('ratio', 1.1), 'max'); + formHelper.expectValid('ratio'); + formHelper.expectErrorChange('ratio', -0.1, 'min'); + formHelper.expectValidChange('ratio', 0); + formHelper.expectValidChange('ratio', 1); + formHelper.expectErrorChange('ratio', 1.1, 'max'); }); }); it('validates application metadata name', () => { - setValue('poolType', 'replicated'); + formHelper.setValue('poolType', 'replicated'); fixture.detectChanges(); const selectBadges = fixture.debugElement.query(By.directive(SelectBadgesComponent)) .componentInstance; const control = selectBadges.filter; - isValid(control); + formHelper.expectValid(control); control.setValue('?'); - hasError(control, 'pattern'); + formHelper.expectError(control, 'pattern'); control.setValue('Ab3_'); - isValid(control); + formHelper.expectValid(control); control.setValue('a'.repeat(129)); - hasError(control, 'maxlength'); + formHelper.expectError(control, 'maxlength'); }); }); @@ -397,31 +386,31 @@ describe('PoolFormComponent', () => { }); it('should have a default replicated size of 3', () => { - setValue('poolType', 'replicated'); + formHelper.setValue('poolType', 'replicated'); expect(form.getValue('size')).toBe(3); }); describe('replicatedRuleChange', () => { beforeEach(() => { - setValue('poolType', 'replicated'); - setValue('size', 99); + formHelper.setValue('poolType', 'replicated'); + formHelper.setValue('size', 99); }); it('should not set size if a replicated pool is not set', () => { - setValue('poolType', 'erasure'); + formHelper.setValue('poolType', 'erasure'); expect(form.getValue('size')).toBe(99); - setValue('crushRule', component.info.crush_rules_replicated[1]); + formHelper.setValue('crushRule', component.info.crush_rules_replicated[1]); expect(form.getValue('size')).toBe(99); }); it('should set size to maximum if size exceeds maximum', () => { - setValue('crushRule', component.info.crush_rules_replicated[0]); + formHelper.setValue('crushRule', component.info.crush_rules_replicated[0]); expect(form.getValue('size')).toBe(4); }); it('should set size to minimum if size is lower than minimum', () => { - setValue('size', -1); - setValue('crushRule', component.info.crush_rules_replicated[0]); + formHelper.setValue('size', -1); + formHelper.setValue('crushRule', component.info.crush_rules_replicated[0]); expect(form.getValue('size')).toBe(2); }); }); @@ -429,7 +418,7 @@ describe('PoolFormComponent', () => { describe('rulesChange', () => { it('has no effect if info is not there', () => { delete component.info; - setValue('poolType', 'replicated'); + formHelper.setValue('poolType', 'replicated'); expect(component.current.rules).toEqual([]); }); @@ -439,38 +428,38 @@ describe('PoolFormComponent', () => { }); it('shows all replicated rules when pool type is "replicated"', () => { - setValue('poolType', 'replicated'); + formHelper.setValue('poolType', 'replicated'); expect(component.current.rules).toEqual(component.info.crush_rules_replicated); expect(component.current.rules.length).toBe(2); }); it('shows all erasure code rules when pool type is "erasure"', () => { - setValue('poolType', 'erasure'); + formHelper.setValue('poolType', 'erasure'); expect(component.current.rules).toEqual(component.info.crush_rules_erasure); expect(component.current.rules.length).toBe(1); }); it('disables rule field if only one rule exists which is used in the disabled field', () => { - setValue('poolType', 'erasure'); + formHelper.setValue('poolType', 'erasure'); const control = form.get('crushRule'); expect(control.value).toEqual(component.info.crush_rules_erasure[0]); expect(control.disabled).toBe(true); }); it('does not select the first rule if more than one exist', () => { - setValue('poolType', 'replicated'); + formHelper.setValue('poolType', 'replicated'); const control = form.get('crushRule'); expect(control.value).toEqual(null); expect(control.disabled).toBe(false); }); it('changing between both types will not leave crushRule in a bad state', () => { - setValue('poolType', 'erasure'); - setValue('poolType', 'replicated'); + formHelper.setValue('poolType', 'erasure'); + formHelper.setValue('poolType', 'replicated'); const control = form.get('crushRule'); expect(control.value).toEqual(null); expect(control.disabled).toBe(false); - setValue('poolType', 'erasure'); + formHelper.setValue('poolType', 'erasure'); expect(control.value).toEqual(component.info.crush_rules_erasure[0]); expect(control.disabled).toBe(true); }); @@ -479,7 +468,7 @@ describe('PoolFormComponent', () => { describe('getMaxSize and getMinSize', () => { const setCrushRule = ({ min, max }: { min?: number; max?: number }) => { - setValue('crushRule', { + formHelper.setValue('crushRule', { min_size: min, max_size: max }); @@ -518,7 +507,7 @@ describe('PoolFormComponent', () => { expect(component.getMinSize()).toBe(10); const control = form.get('crushRule'); expect(control.invalid).toBe(true); - hasError(control, 'tooFewOsds'); + formHelper.expectError(control, 'tooFewOsds'); }); }); @@ -545,7 +534,7 @@ describe('PoolFormComponent', () => { }; beforeEach(() => { - setValue('poolType', 'replicated'); + formHelper.setValue('poolType', 'replicated'); fixture.detectChanges(); selectBadges = fixture.debugElement.query(By.directive(SelectBadgesComponent)) .componentInstance; @@ -581,7 +570,7 @@ describe('PoolFormComponent', () => { describe('pg number changes', () => { beforeEach(() => { - setValue('crushRule', { + formHelper.setValue('crushRule', { min_size: 1, max_size: 20 }); @@ -606,11 +595,11 @@ describe('PoolFormComponent', () => { const testPgCalc = ({ type, osds, size, ecp, expected }) => { component.info.osd_count = osds; - setValue('poolType', type); + formHelper.setValue('poolType', type); if (type === 'replicated') { - setValue('size', size); + formHelper.setValue('size', size); } else { - setValue('erasureProfile', ecp); + formHelper.setValue('erasureProfile', ecp); } expect(form.getValue('pgNum')).toBe(expected); expect(component.externalPgChange).toBe(PGS !== expected); @@ -742,7 +731,7 @@ describe('PoolFormComponent', () => { describe('submit - create', () => { const setMultipleValues = (settings: {}) => { Object.keys(settings).forEach((name) => { - setValue(name, settings[name]); + formHelper.setValue(name, settings[name]); }); }; const testCreate = (pool) => { @@ -932,8 +921,8 @@ describe('PoolFormComponent', () => { }); it('is only be possible to use the same or more pgs like before', () => { - isValid(setPgNum(64)); - hasError(setPgNum(4), 'noDecrease'); + formHelper.expectValid(setPgNum(64)); + formHelper.expectError(setPgNum(4), 'noDecrease'); }); describe('submit', () => { @@ -960,9 +949,9 @@ describe('PoolFormComponent', () => { }); it(`will always provide reset value for compression options`, () => { - setValue('minBlobSize', '').markAsDirty(); - setValue('maxBlobSize', '').markAsDirty(); - setValue('ratio', '').markAsDirty(); + formHelper.setValue('minBlobSize', '').markAsDirty(); + formHelper.setValue('maxBlobSize', '').markAsDirty(); + formHelper.setValue('ratio', '').markAsDirty(); testSubmit( { application_metadata: ['rbd', 'rgw'], @@ -977,7 +966,7 @@ describe('PoolFormComponent', () => { }); it(`will unset mode not used anymore`, () => { - setValue('mode', 'none').markAsDirty(); + formHelper.setValue('mode', 'none').markAsDirty(); testSubmit( { application_metadata: ['rbd', 'rgw'], diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-user-form/rgw-user-form.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-user-form/rgw-user-form.component.spec.ts index b6d95627cabc..f6025a23e069 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-user-form/rgw-user-form.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-user-form/rgw-user-form.component.spec.ts @@ -6,7 +6,7 @@ import { RouterTestingModule } from '@angular/router/testing'; import { BsModalService } from 'ngx-bootstrap/modal'; import { of as observableOf } from 'rxjs'; -import { configureTestBed } from '../../../../testing/unit-test-helper'; +import { configureTestBed, FormHelper } from '../../../../testing/unit-test-helper'; import { RgwUserService } from '../../../shared/api/rgw-user.service'; import { SharedModule } from '../../../shared/shared.module'; import { RgwUserS3Key } from '../models/rgw-user-s3-key'; @@ -114,41 +114,33 @@ describe('RgwUserFormComponent', () => { describe('username validation', () => { let rgwUserService: RgwUserService; + let formHelper: FormHelper; beforeEach(() => { rgwUserService = TestBed.get(RgwUserService); spyOn(rgwUserService, 'enumerate').and.returnValue(observableOf(['abc', 'xyz'])); + formHelper = new FormHelper(component.userForm); }); it('should validate that username is required', () => { - const user_id = component.userForm.get('user_id'); - user_id.markAsDirty(); - user_id.setValue(''); - expect(user_id.hasError('required')).toBeTruthy(); - expect(user_id.valid).toBeFalsy(); + formHelper.expectErrorChange('user_id', '', 'required', true); }); it( 'should validate that username is valid', fakeAsync(() => { - const user_id = component.userForm.get('user_id'); - user_id.markAsDirty(); - user_id.setValue('ab'); + formHelper.setValue('user_id', 'ab', true); tick(500); - expect(user_id.hasError('notUnique')).toBeFalsy(); - expect(user_id.valid).toBeTruthy(); + formHelper.expectValid('user_id'); }) ); it( 'should validate that username is invalid', fakeAsync(() => { - const user_id = component.userForm.get('user_id'); - user_id.markAsDirty(); - user_id.setValue('abc'); + formHelper.setValue('user_id', 'abc', true); tick(500); - expect(user_id.hasError('notUnique')).toBeTruthy(); - expect(user_id.valid).toBeFalsy(); + formHelper.expectError('user_id', 'notUnique'); }) ); }); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/core/auth/role-form/role-form.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/core/auth/role-form/role-form.component.spec.ts index 1d743b35be03..eb2f1caab20a 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/core/auth/role-form/role-form.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/core/auth/role-form/role-form.component.spec.ts @@ -8,7 +8,7 @@ import { RouterTestingModule } from '@angular/router/testing'; import { ToastModule } from 'ng2-toastr'; import { of } from 'rxjs'; -import { configureTestBed } from '../../../../testing/unit-test-helper'; +import { configureTestBed, FormHelper } from '../../../../testing/unit-test-helper'; import { RoleService } from '../../../shared/api/role.service'; import { ScopeService } from '../../../shared/api/scope.service'; import { CdFormGroup } from '../../../shared/forms/cd-form-group'; @@ -64,9 +64,12 @@ describe('RoleFormComponent', () => { }); describe('create mode', () => { + let formHelper: FormHelper; + beforeEach(() => { setUrl('/user-management/roles/add'); component.ngOnInit(); + formHelper = new FormHelper(form); }); it('should not disable fields', () => { @@ -76,8 +79,7 @@ describe('RoleFormComponent', () => { }); it('should validate name required', () => { - form.get('name').setValue(''); - expect(form.get('name').hasError('required')).toBeTruthy(); + formHelper.expectErrorChange('name', '', 'required'); }); it('should set mode', () => { @@ -90,7 +92,7 @@ describe('RoleFormComponent', () => { description: 'Role 1', scopes_permissions: { osd: ['read'] } }; - Object.keys(role).forEach((k) => form.get(k).setValue(role[k])); + formHelper.setMultipleValues(role); component.submit(); const roleReq = httpTesting.expectOne('api/role'); expect(roleReq.request.method).toBe('POST'); @@ -100,7 +102,7 @@ describe('RoleFormComponent', () => { }); it('should check all perms for a scope', () => { - form.get('scopes_permissions').setValue({ cephfs: ['read'] }); + formHelper.setValue('scopes_permissions', { cephfs: ['read'] }); component.onClickCellCheckbox('grafana', 'scope'); const scopes_permissions = form.getValue('scopes_permissions'); expect(Object.keys(scopes_permissions)).toContain('grafana'); @@ -108,7 +110,7 @@ describe('RoleFormComponent', () => { }); it('should uncheck all perms for a scope', () => { - form.get('scopes_permissions').setValue({ cephfs: ['read', 'create', 'update', 'delete'] }); + formHelper.setValue('scopes_permissions', { cephfs: ['read', 'create', 'update', 'delete'] }); component.onClickCellCheckbox('cephfs', 'scope'); const scopes_permissions = form.getValue('scopes_permissions'); expect(Object.keys(scopes_permissions)).not.toContain('cephfs'); @@ -116,7 +118,10 @@ describe('RoleFormComponent', () => { it('should uncheck all scopes and perms', () => { component.scopes = ['cephfs', 'grafana']; - form.get('scopes_permissions').setValue({ cephfs: ['read', 'delete'], grafana: ['update'] }); + formHelper.setValue('scopes_permissions', { + cephfs: ['read', 'delete'], + grafana: ['update'] + }); component.onClickHeaderCheckbox('scope', { target: { checked: false } }); const scopes_permissions = form.getValue('scopes_permissions'); expect(scopes_permissions).toEqual({}); @@ -124,9 +129,10 @@ describe('RoleFormComponent', () => { it('should check all scopes and perms', () => { component.scopes = ['cephfs', 'grafana']; - form - .get('scopes_permissions') - .setValue({ cephfs: ['create', 'update'], grafana: ['delete'] }); + formHelper.setValue('scopes_permissions', { + cephfs: ['create', 'update'], + grafana: ['delete'] + }); component.onClickHeaderCheckbox('scope', { target: { checked: true } }); const scopes_permissions = form.getValue('scopes_permissions'); const keys = Object.keys(scopes_permissions); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/core/auth/user-form/user-form.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/core/auth/user-form/user-form.component.spec.ts index 49b414e7b5f7..3b83f1a5f358 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/core/auth/user-form/user-form.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/core/auth/user-form/user-form.component.spec.ts @@ -9,7 +9,7 @@ import { ToastModule } from 'ng2-toastr'; import { BsModalService } from 'ngx-bootstrap/modal'; import { of } from 'rxjs'; -import { configureTestBed } from '../../../../testing/unit-test-helper'; +import { configureTestBed, FormHelper } from '../../../../testing/unit-test-helper'; import { RoleService } from '../../../shared/api/role.service'; import { UserService } from '../../../shared/api/user.service'; import { ComponentsModule } from '../../../shared/components/components.module'; @@ -28,6 +28,8 @@ describe('UserFormComponent', () => { let userService: UserService; let modalService: BsModalService; let router: Router; + let formHelper: FormHelper; + const setUrl = (url) => Object.defineProperty(router, 'url', { value: url }); @Component({ selector: 'cd-fake', template: '' }) @@ -65,6 +67,7 @@ describe('UserFormComponent', () => { fixture.detectChanges(); const notify = TestBed.get(NotificationService); spyOn(notify, 'show'); + formHelper = new FormHelper(form); }); it('should create', () => { @@ -85,30 +88,18 @@ describe('UserFormComponent', () => { }); it('should validate username required', () => { - form.get('username').setValue(''); - expect(form.get('username').hasError('required')).toBeTruthy(); - form.get('username').setValue('user1'); - expect(form.get('username').hasError('required')).toBeFalsy(); + formHelper.expectErrorChange('username', '', 'required'); + formHelper.expectValidChange('username', 'user1'); }); it('should validate password match', () => { - form.get('password').setValue('aaa'); - form.get('confirmpassword').setValue('bbb'); - expect(form.get('confirmpassword').hasError('match')).toBeTruthy(); - form.get('confirmpassword').setValue('aaa'); - expect(form.get('confirmpassword').valid).toBeTruthy(); + formHelper.setValue('password', 'aaa'); + formHelper.expectErrorChange('confirmpassword', 'bbb', 'match'); + formHelper.expectValidChange('confirmpassword', 'aaa'); }); it('should validate email', () => { - form.get('email').setValue('aaa'); - expect(form.get('email').hasError('email')).toBeTruthy(); - }); - - it('should validate all required fields', () => { - form.get('username').setValue(''); - expect(form.valid).toBeFalsy(); - form.get('username').setValue('user1'); - expect(form.valid).toBeTruthy(); + formHelper.expectErrorChange('email', 'aaa', 'email'); }); it('should set mode', () => { @@ -123,8 +114,8 @@ describe('UserFormComponent', () => { email: 'user0@email.com', roles: ['administrator'] }; - Object.keys(user).forEach((k) => form.get(k).setValue(user[k])); - form.get('confirmpassword').setValue(user.password); + formHelper.setMultipleValues(user); + formHelper.setValue('confirmpassword', user.password); component.submit(); const userReq = httpTesting.expectOne('api/user'); expect(userReq.request.method).toBe('POST'); @@ -204,14 +195,14 @@ describe('UserFormComponent', () => { spyOn(modalService, 'show').and.callFake((content, config) => { modalBodyTpl = config.initialState.bodyTpl; }); - form.get('roles').setValue(['read-only']); + formHelper.setValue('roles', ['read-only']); component.submit(); expect(modalBodyTpl).toEqual(component.removeSelfUserReadUpdatePermissionTpl); }); it('should logout if current user roles have been changed', () => { spyOn(TestBed.get(AuthStorageService), 'getUsername').and.callFake(() => user.username); - form.get('roles').setValue(['user-manager']); + formHelper.setValue('roles', ['user-manager']); component.submit(); const userReq = httpTesting.expectOne(`api/user/${user.username}`); expect(userReq.request.method).toBe('PUT'); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/forms/cd-validators.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/forms/cd-validators.spec.ts index 242c66665239..f0e54cd4c06a 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/forms/cd-validators.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/forms/cd-validators.spec.ts @@ -1,462 +1,268 @@ import { fakeAsync, tick } from '@angular/core/testing'; -import { AbstractControl, FormControl, FormGroup } from '@angular/forms'; +import { FormControl } from '@angular/forms'; import { of as observableOf } from 'rxjs'; +import { FormHelper } from '../../../testing/unit-test-helper'; +import { CdFormGroup } from './cd-form-group'; import { CdValidators } from './cd-validators'; describe('CdValidators', () => { - describe('email', () => { - it('should not error on an empty email address', () => { - const control = new FormControl(''); - expect(CdValidators.email(control)).toBeNull(); - }); + let formHelper: FormHelper; + let form: CdFormGroup; - it('should not error on valid email address', () => { - const control = new FormControl('dashboard@ceph.com'); - expect(CdValidators.email(control)).toBeNull(); - }); + const expectValid = (value) => formHelper.expectValidChange('x', value); + const expectPatternError = (value) => formHelper.expectErrorChange('x', value, 'pattern'); + const updateValidity = (controlName) => form.get(controlName).updateValueAndValidity(); - it('should error on invalid email address', () => { - const control = new FormControl('xyz'); - expect(CdValidators.email(control)).toEqual({ email: true }); + beforeEach(() => { + form = new CdFormGroup({ + x: new FormControl() }); + formHelper = new FormHelper(form); }); - describe('ip validator', () => { - let form: FormGroup; - + describe('email', () => { beforeEach(() => { - form = new FormGroup({ - x: new FormControl() - }); + form.get('x').setValidators(CdValidators.email); }); - it('should not error on empty IPv4 addresses', () => { - const x = form.get('x'); - x.setValidators(CdValidators.ip(4)); - x.setValue(''); - expect(x.valid).toBeTruthy(); - expect(x.hasError('pattern')).toBeFalsy(); + it('should not error on an empty email address', () => { + expectValid(''); }); - it('should accept valid IPv4 address', () => { - const x = form.get('x'); - x.setValidators(CdValidators.ip(4)); - x.setValue('19.117.23.141'); - expect(x.valid).toBeTruthy(); - expect(x.hasError('pattern')).toBeFalsy(); + it('should not error on valid email address', () => { + expectValid('dashboard@ceph.com'); }); - it('should error on IPv4 address containing whitespace', () => { - const x = form.get('x'); - x.setValidators(CdValidators.ip(4)); - x.setValue('155.144.133.122 '); - expect(x.valid).toBeFalsy(); - expect(x.hasError('pattern')).toBeTruthy(); - - x.setValue('155. 144.133 .122'); - expect(x.valid).toBeFalsy(); - expect(x.hasError('pattern')).toBeTruthy(); - - x.setValue(' 155.144.133.122'); - expect(x.valid).toBeFalsy(); - expect(x.hasError('pattern')).toBeTruthy(); + it('should error on invalid email address', () => { + formHelper.expectErrorChange('x', 'xyz', 'email'); }); + }); - it('should error on IPv4 address containing invalid char', () => { - const x = form.get('x'); - x.setValidators(CdValidators.ip(4)); - x.setValue('155.144.eee.122 '); - expect(x.valid).toBeFalsy(); - expect(x.hasError('pattern')).toBeTruthy(); + describe('ip validator', () => { + describe('IPv4', () => { + beforeEach(() => { + form.get('x').setValidators(CdValidators.ip(4)); + }); - x.setValue('155.1?.133 .1&2'); - expect(x.valid).toBeFalsy(); - expect(x.hasError('pattern')).toBeTruthy(); - }); + it('should not error on empty addresses', () => { + expectValid(''); + }); - it('should error on IPv4 address containing blocks higher than 255', () => { - const x = form.get('x'); - x.setValidators(CdValidators.ip(4)); - x.setValue('155.270.133.122 '); - expect(x.valid).toBeFalsy(); - expect(x.hasError('pattern')).toBeTruthy(); + it('should accept valid address', () => { + expectValid('19.117.23.141'); + }); - x.setValue('155.144.133.290 '); - expect(x.valid).toBeFalsy(); - expect(x.hasError('pattern')).toBeTruthy(); - }); + it('should error containing whitespace', () => { + expectPatternError('155.144.133.122 '); + expectPatternError('155. 144.133 .122'); + expectPatternError(' 155.144.133.122'); + }); - it('should not error on empty IPv6 addresses', () => { - const x = form.get('x'); - x.setValidators(CdValidators.ip(4)); - x.setValue(''); - expect(x.valid).toBeTruthy(); - expect(x.hasError('pattern')).toBeFalsy(); - }); + it('should error containing invalid char', () => { + expectPatternError('155.144.eee.122 '); + expectPatternError('155.1?.133 .1&2'); + }); - it('should accept valid IPv6 address', () => { - const x = form.get('x'); - x.setValidators(CdValidators.ip(6)); - x.setValue('c4dc:1475:cb0b:24ed:3c80:468b:70cd:1a95'); - expect(x.valid).toBeTruthy(); - expect(x.hasError('pattern')).toBeFalsy(); + it('should error containing blocks higher than 255', () => { + expectPatternError('155.270.133.122'); + expectPatternError('155.144.133.290'); + }); }); - it('should error on IPv6 address containing too many blocks', () => { - const x = form.get('x'); - x.setValidators(CdValidators.ip(6)); - x.setValue('c4dc:14753:cb0b:24ed:3c80:468b:70cd:1a95:a3f3'); - expect(x.valid).toBeFalsy(); - expect(x.hasError('pattern')).toBeTruthy(); - }); + describe('IPv4', () => { + beforeEach(() => { + form.get('x').setValidators(CdValidators.ip(6)); + }); - it('should error on IPv6 address containing more than 4 digits per block', () => { - const x = form.get('x'); - x.setValidators(CdValidators.ip(6)); - x.setValue('c4dc:14753:cb0b:24ed:3c80:468b:70cd:1a95'); - expect(x.valid).toBeFalsy(); - expect(x.hasError('pattern')).toBeTruthy(); - }); + it('should not error on empty IPv6 addresses', () => { + expectValid(''); + }); - it('should error on IPv6 address containing whitespace', () => { - const x = form.get('x'); - x.setValidators(CdValidators.ip(6)); - x.setValue('c4dc:14753:cb0b:24ed:3c80:468b:70cd:1a95 '); - expect(x.valid).toBeFalsy(); - expect(x.hasError('pattern')).toBeTruthy(); + it('should accept valid IPv6 address', () => { + expectValid('c4dc:1475:cb0b:24ed:3c80:468b:70cd:1a95'); + }); - x.setValue('c4dc:14753 :cb0b:24ed:3c80 :468b:70cd :1a95'); - expect(x.valid).toBeFalsy(); - expect(x.hasError('pattern')).toBeTruthy(); + it('should error on IPv6 address containing too many blocks', () => { + formHelper.expectErrorChange( + 'x', + 'c4dc:14753:cb0b:24ed:3c80:468b:70cd:1a95:a3f3', + 'pattern' + ); + }); - x.setValue(' c4dc:14753:cb0b:24ed:3c80:468b:70cd:1a95'); - expect(x.valid).toBeFalsy(); - expect(x.hasError('pattern')).toBeTruthy(); - }); + it('should error on IPv6 address containing more than 4 digits per block', () => { + expectPatternError('c4dc:14753:cb0b:24ed:3c80:468b:70cd:1a95'); + }); - it('should error on IPv6 address containing invalid char', () => { - const x = form.get('x'); - x.setValidators(CdValidators.ip(6)); - x.setValue('c4dx:14753:cb0b:24ed:3c80:468b:70cd:1a95 '); - expect(x.valid).toBeFalsy(); - expect(x.hasError('pattern')).toBeTruthy(); + it('should error on IPv6 address containing whitespace', () => { + expectPatternError('c4dc:14753:cb0b:24ed:3c80:468b:70cd:1a95 '); + expectPatternError('c4dc:14753 :cb0b:24ed:3c80 :468b:70cd :1a95'); + expectPatternError(' c4dc:14753:cb0b:24ed:3c80:468b:70cd:1a95'); + }); - x.setValue('c4dx:14753:cb0b:24ed:3$80:468b:70cd:1a95 '); - expect(x.valid).toBeFalsy(); - expect(x.hasError('pattern')).toBeTruthy(); + it('should error on IPv6 address containing invalid char', () => { + expectPatternError('c4dx:14753:cb0b:24ed:3c80:468b:70cd:1a95'); + expectPatternError('c4da:14753:cb0b:24ed:3$80:468b:70cd:1a95'); + }); }); it('should accept valid IPv4/6 addresses if not protocol version is given', () => { const x = form.get('x'); x.setValidators(CdValidators.ip()); - x.setValue('19.117.23.141'); - expect(x.valid).toBeTruthy(); - expect(x.hasError('pattern')).toBeFalsy(); - - x.setValue('c4dc:1475:cb0b:24ed:3c80:468b:70cd:1a95'); - expect(x.valid).toBeTruthy(); - expect(x.hasError('pattern')).toBeFalsy(); + expectValid('19.117.23.141'); + expectValid('c4dc:1475:cb0b:24ed:3c80:468b:70cd:1a95'); }); }); describe('uuid validator', () => { - let form: FormGroup; - + const expectUuidError = (value) => + formHelper.expectErrorChange('x', value, 'invalidUuid', true); beforeEach(() => { - form = new FormGroup({ - x: new FormControl(null, CdValidators.uuid()) - }); + form.get('x').setValidators(CdValidators.uuid()); }); it('should accept empty value', () => { - const x = form.get('x'); - x.setValue(''); - expect(x.valid).toBeTruthy(); - expect(x.hasError('pattern')).toBeFalsy(); + expectValid(''); }); it('should accept valid version 1 uuid', () => { - const x = form.get('x'); - x.setValue('171af0b2-c305-11e8-a355-529269fb1459'); - expect(x.valid).toBeTruthy(); - expect(x.hasError('pattern')).toBeFalsy(); + expectValid('171af0b2-c305-11e8-a355-529269fb1459'); }); it('should accept valid version 4 uuid', () => { - const x = form.get('x'); - x.setValue('e33bbcb6-fcc3-40b1-ae81-3f81706a35d5'); - expect(x.valid).toBeTruthy(); - expect(x.hasError('pattern')).toBeFalsy(); + expectValid('e33bbcb6-fcc3-40b1-ae81-3f81706a35d5'); }); it('should error on uuid containing too many blocks', () => { - const x = form.get('x'); - x.markAsDirty(); - x.setValue('e33bbcb6-fcc3-40b1-ae81-3f81706a35d5-23d3'); - expect(x.valid).toBeFalsy(); - expect(x.hasError('invalidUuid')).toBeTruthy(); + expectUuidError('e33bbcb6-fcc3-40b1-ae81-3f81706a35d5-23d3'); }); it('should error on uuid containing too many chars in block', () => { - const x = form.get('x'); - x.markAsDirty(); - x.setValue('aae33bbcb6-fcc3-40b1-ae81-3f81706a35d5'); - expect(x.valid).toBeFalsy(); - expect(x.hasError('invalidUuid')).toBeTruthy(); + expectUuidError('aae33bbcb6-fcc3-40b1-ae81-3f81706a35d5'); }); it('should error on uuid containing invalid char', () => { - const x = form.get('x'); - x.markAsDirty(); - x.setValue('x33bbcb6-fcc3-40b1-ae81-3f81706a35d5'); - expect(x.valid).toBeFalsy(); - expect(x.hasError('invalidUuid')).toBeTruthy(); - - x.setValue('$33bbcb6-fcc3-40b1-ae81-3f81706a35d5'); - expect(x.valid).toBeFalsy(); - expect(x.hasError('invalidUuid')).toBeTruthy(); + expectUuidError('x33bbcb6-fcc3-40b1-ae81-3f81706a35d5'); + expectUuidError('$33bbcb6-fcc3-40b1-ae81-3f81706a35d5'); }); }); describe('number validator', () => { - let form: FormGroup; - beforeEach(() => { - form = new FormGroup({ - x: new FormControl() - }); - form.controls['x'].setValidators(CdValidators.number()); + form.get('x').setValidators(CdValidators.number()); }); it('should accept empty value', () => { - const x = form.get('x'); - x.setValue(''); - expect(x.valid).toBeTruthy(); - expect(x.hasError('pattern')).toBeFalsy(); + expectValid(''); }); it('should accept numbers', () => { - const x = form.get('x'); - x.setValue(42); - expect(x.valid).toBeTruthy(); - expect(x.hasError('pattern')).toBeFalsy(); - - x.setValue(-42); - expect(x.valid).toBeTruthy(); - expect(x.hasError('pattern')).toBeFalsy(); - - x.setValue('42'); - expect(x.valid).toBeTruthy(); - expect(x.hasError('pattern')).toBeFalsy(); + expectValid(42); + expectValid(-42); + expectValid('42'); }); it('should error on decimal numbers', () => { - const x = form.get('x'); - x.setValue(42.3); - expect(x.valid).toBeFalsy(); - expect(x.hasError('pattern')).toBeTruthy(); - - x.setValue(-42.3); - expect(x.valid).toBeFalsy(); - expect(x.hasError('pattern')).toBeTruthy(); - - x.setValue('42.3'); - expect(x.valid).toBeFalsy(); - expect(x.hasError('pattern')).toBeTruthy(); + expectPatternError(42.3); + expectPatternError(-42.3); + expectPatternError('42.3'); }); it('should error on chars', () => { - const x = form.get('x'); - x.setValue('char'); - expect(x.valid).toBeFalsy(); - expect(x.hasError('pattern')).toBeTruthy(); - - x.setValue('42char'); - expect(x.valid).toBeFalsy(); - expect(x.hasError('pattern')).toBeTruthy(); + expectPatternError('char'); + expectPatternError('42char'); }); it('should error on whitespaces', () => { - const x = form.get('x'); - x.setValue('42 '); - expect(x.valid).toBeFalsy(); - expect(x.hasError('pattern')).toBeTruthy(); - - x.setValue('4 2'); - expect(x.valid).toBeFalsy(); - expect(x.hasError('pattern')).toBeTruthy(); + expectPatternError('42 '); + expectPatternError('4 2'); }); }); describe('number validator (without negative values)', () => { - let form: FormGroup; - beforeEach(() => { - form = new FormGroup({ - x: new FormControl() - }); - form.controls['x'].setValidators(CdValidators.number(false)); + form.get('x').setValidators(CdValidators.number(false)); }); it('should accept positive numbers', () => { - const x = form.get('x'); - x.setValue(42); - expect(x.valid).toBeTruthy(); - expect(x.hasError('pattern')).toBeFalsy(); - - x.setValue('42'); - expect(x.valid).toBeTruthy(); - expect(x.hasError('pattern')).toBeFalsy(); + expectValid(42); + expectValid('42'); }); it('should error on negative numbers', () => { - const x = form.get('x'); - x.setValue(-42); - expect(x.valid).toBeFalsy(); - expect(x.hasError('pattern')).toBeTruthy(); - - x.setValue('-42'); - expect(x.valid).toBeFalsy(); - expect(x.hasError('pattern')).toBeTruthy(); + expectPatternError(-42); + expectPatternError('-42'); }); }); describe('decimal number validator', () => { - let form: FormGroup; - beforeEach(() => { - form = new FormGroup({ - x: new FormControl() - }); - form.controls['x'].setValidators(CdValidators.decimalNumber()); + form.get('x').setValidators(CdValidators.decimalNumber()); }); it('should accept empty value', () => { - const x = form.get('x'); - x.setValue(''); - expect(x.valid).toBeTruthy(); - expect(x.hasError('pattern')).toBeFalsy(); + expectValid(''); }); it('should accept numbers and decimal numbers', () => { - const x = form.get('x'); - x.setValue(42); - expect(x.valid).toBeTruthy(); - expect(x.hasError('pattern')).toBeFalsy(); - - x.setValue(-42); - expect(x.valid).toBeTruthy(); - expect(x.hasError('pattern')).toBeFalsy(); - - x.setValue(42.3); - expect(x.valid).toBeTruthy(); - expect(x.hasError('pattern')).toBeFalsy(); - - x.setValue(-42.3); - expect(x.valid).toBeTruthy(); - expect(x.hasError('pattern')).toBeFalsy(); - - x.setValue('42'); - expect(x.valid).toBeTruthy(); - expect(x.hasError('pattern')).toBeFalsy(); - - x.setValue('42.3'); - expect(x.valid).toBeTruthy(); - expect(x.hasError('pattern')).toBeFalsy(); + expectValid(42); + expectValid(-42); + expectValid(42.3); + expectValid(-42.3); + expectValid('42'); + expectValid('42.3'); }); it('should error on chars', () => { - const x = form.get('x'); - x.setValue('42e'); - expect(x.valid).toBeFalsy(); - expect(x.hasError('pattern')).toBeTruthy(); - - x.setValue('e42.3'); - expect(x.valid).toBeFalsy(); - expect(x.hasError('pattern')).toBeTruthy(); + expectPatternError('42e'); + expectPatternError('e42.3'); }); it('should error on whitespaces', () => { - const x = form.get('x'); - x.setValue('42.3 '); - expect(x.valid).toBeFalsy(); - expect(x.hasError('pattern')).toBeTruthy(); - - x.setValue('42 .3'); - expect(x.valid).toBeFalsy(); - expect(x.hasError('pattern')).toBeTruthy(); + expectPatternError('42.3 '); + expectPatternError('42 .3'); }); }); describe('decimal number validator (without negative values)', () => { - let form: FormGroup; - beforeEach(() => { - form = new FormGroup({ - x: new FormControl() - }); - form.controls['x'].setValidators(CdValidators.decimalNumber(false)); + form.get('x').setValidators(CdValidators.decimalNumber(false)); }); it('should accept positive numbers and decimals', () => { - const x = form.get('x'); - x.setValue(42); - expect(x.valid).toBeTruthy(); - expect(x.hasError('pattern')).toBeFalsy(); - - x.setValue(42.3); - expect(x.valid).toBeTruthy(); - expect(x.hasError('pattern')).toBeFalsy(); - - x.setValue('42'); - expect(x.valid).toBeTruthy(); - expect(x.hasError('pattern')).toBeFalsy(); - - x.setValue('42.3'); - expect(x.valid).toBeTruthy(); - expect(x.hasError('pattern')).toBeFalsy(); + expectValid(42); + expectValid(42.3); + expectValid('42'); + expectValid('42.3'); }); it('should error on negative numbers and decimals', () => { - const x = form.get('x'); - x.setValue(-42); - expect(x.valid).toBeFalsy(); - expect(x.hasError('pattern')).toBeTruthy(); - - x.setValue('-42'); - expect(x.valid).toBeFalsy(); - expect(x.hasError('pattern')).toBeTruthy(); - - x.setValue(-42.3); - expect(x.valid).toBeFalsy(); - expect(x.hasError('pattern')).toBeTruthy(); - - x.setValue('-42.3'); - expect(x.valid).toBeFalsy(); - expect(x.hasError('pattern')).toBeTruthy(); + expectPatternError(-42); + expectPatternError('-42'); + expectPatternError(-42.3); + expectPatternError('-42.3'); }); }); describe('requiredIf', () => { - let form: FormGroup; - beforeEach(() => { - form = new FormGroup({ + form = new CdFormGroup({ x: new FormControl(true), y: new FormControl('abc'), z: new FormControl('') }); + formHelper = new FormHelper(form); }); it('should not error because all conditions are fulfilled', () => { - form.get('z').setValue('zyx'); + formHelper.setValue('z', 'zyx'); const validatorFn = CdValidators.requiredIf({ x: true, y: 'abc' }); - expect(validatorFn(form.controls['z'])).toBeNull(); + expect(validatorFn(form.get('z'))).toBeNull(); }); it('should not error because of unmet prerequisites', () => { @@ -467,7 +273,7 @@ describe('CdValidators', () => { }); // The validator must succeed because the prereqs do not match, so the // validation of the 'z' control will be skipped. - expect(validatorFn(form.controls['z'])).toBeNull(); + expect(validatorFn(form.get('z'))).toBeNull(); }); it('should error because of an empty value', () => { @@ -478,11 +284,11 @@ describe('CdValidators', () => { y: 'abc' }); // The validator must fail because the value of control 'z' is empty. - expect(validatorFn(form.controls['z'])).toEqual({ required: true }); + expect(validatorFn(form.get('z'))).toEqual({ required: true }); }); it('should not error because of unsuccessful condition', () => { - form.get('z').setValue('zyx'); + formHelper.setValue('z', 'zyx'); // Define prereqs that force the validator to validate the value of // the 'z' control. const validatorFn = CdValidators.requiredIf( @@ -492,7 +298,7 @@ describe('CdValidators', () => { }, () => false ); - expect(validatorFn(form.controls['z'])).toBeNull(); + expect(validatorFn(form.get('z'))).toBeNull(); }); it('should error because of successful condition', () => { @@ -508,15 +314,13 @@ describe('CdValidators', () => { }, conditionFn ); - expect(validatorFn(form.controls['y'])).toEqual({ required: true }); + expect(validatorFn(form.get('y'))).toEqual({ required: true }); }); }); describe('custom validation', () => { - let form: FormGroup; - beforeEach(() => { - form = new FormGroup({ + form = new CdFormGroup({ x: new FormControl(3, CdValidators.custom('odd', (x) => x % 2 === 1)), y: new FormControl( 5, @@ -526,31 +330,24 @@ describe('CdValidators', () => { }) ) }); + formHelper = new FormHelper(form); }); it('should test error and valid condition for odd x', () => { - const x = form.get('x'); - x.updateValueAndValidity(); - expect(x.hasError('odd')).toBeTruthy(); - x.setValue(4); - expect(x.valid).toBeTruthy(); + formHelper.expectError('x', 'odd'); + expectValid(4); }); it('should test error and valid condition for y if its dividable by x', () => { - const y = form.get('y'); - y.updateValueAndValidity(); - expect(y.hasError('not-dividable-by-x')).toBeTruthy(); - y.setValue(6); - y.updateValueAndValidity(); - expect(y.valid).toBeTruthy(); + updateValidity('y'); + formHelper.expectError('y', 'not-dividable-by-x'); + formHelper.expectValidChange('y', 6); }); }); describe('validate if condition', () => { - let form: FormGroup; - beforeEach(() => { - form = new FormGroup({ + form = new CdFormGroup({ x: new FormControl(3), y: new FormControl(5) }); @@ -558,87 +355,71 @@ describe('CdValidators', () => { CdValidators.custom('min', (x) => x < 7), CdValidators.custom('max', (x) => x > 12) ]); + formHelper = new FormHelper(form); }); it('should test min error', () => { - const x = form.get('x'); - const y = form.get('y'); - expect(x.valid).toBeTruthy(); - y.setValue(11); - x.updateValueAndValidity(); - expect(x.hasError('min')).toBeTruthy(); + formHelper.setValue('y', 11); + updateValidity('x'); + formHelper.expectError('x', 'min'); }); it('should test max error', () => { - const x = form.get('x'); - const y = form.get('y'); - expect(x.valid).toBeTruthy(); - y.setValue(11); - x.setValue(13); - expect(x.hasError('max')).toBeTruthy(); + formHelper.setValue('y', 11); + formHelper.setValue('x', 13); + formHelper.expectError('x', 'max'); }); it('should test valid number with validation', () => { - const x = form.get('x'); - const y = form.get('y'); - expect(x.valid).toBeTruthy(); - y.setValue(11); - x.setValue(12); - expect(x.valid).toBeTruthy(); + formHelper.setValue('y', 11); + formHelper.setValue('x', 12); + formHelper.expectValid('x'); }); }); describe('match', () => { - let form: FormGroup; - let x: FormControl; let y: FormControl; beforeEach(() => { - x = new FormControl('aaa'); y = new FormControl('aaa'); - form = new FormGroup({ - x: x, + form = new CdFormGroup({ + x: new FormControl('aaa'), y: y }); + formHelper = new FormHelper(form); }); it('should error when values are different', () => { - y.setValue('aab'); + formHelper.setValue('y', 'aab'); CdValidators.match('x', 'y')(form); - expect(x.hasError('match')).toBeFalsy(); - expect(y.hasError('match')).toBeTruthy(); + formHelper.expectValid('x'); + formHelper.expectError('y', 'match'); }); it('should not error when values are equal', () => { CdValidators.match('x', 'y')(form); - expect(x.hasError('match')).toBeFalsy(); - expect(y.hasError('match')).toBeFalsy(); + formHelper.expectValid('x'); + formHelper.expectValid('y'); }); it('should unset error when values are equal', () => { y.setErrors({ match: true }); CdValidators.match('x', 'y')(form); - expect(x.hasError('match')).toBeFalsy(); - expect(y.hasError('match')).toBeFalsy(); - expect(y.valid).toBeTruthy(); + formHelper.expectValid('x'); + formHelper.expectValid('y'); }); it('should keep other existing errors', () => { y.setErrors({ match: true, notUnique: true }); CdValidators.match('x', 'y')(form); - expect(x.hasError('match')).toBeFalsy(); - expect(y.hasError('match')).toBeFalsy(); - expect(y.hasError('notUnique')).toBeTruthy(); - expect(y.valid).toBeFalsy(); + formHelper.expectValid('x'); + formHelper.expectError('y', 'notUnique'); }); }); describe('unique', () => { - let form: FormGroup; - let x: AbstractControl; - beforeEach(() => { - form = new FormGroup({ + form = new CdFormGroup({ x: new FormControl( '', null, @@ -647,33 +428,28 @@ describe('CdValidators', () => { }) ) }); - x = form.get('x'); - x.markAsDirty(); + formHelper = new FormHelper(form); }); it('should not error because of empty input', () => { - x.setValue(''); - expect(x.hasError('notUnique')).toBeFalsy(); - expect(x.valid).toBeTruthy(); + expectValid(''); }); it( 'should not error because of not existing input', fakeAsync(() => { - x.setValue('abc'); + formHelper.setValue('x', 'abc', true); tick(500); - expect(x.hasError('notUnique')).toBeFalsy(); - expect(x.valid).toBeTruthy(); + formHelper.expectValid('x'); }) ); it( 'should error because of already existing input', fakeAsync(() => { - x.setValue('xyz'); + formHelper.setValue('x', 'xyz', true); tick(500); - expect(x.hasError('notUnique')).toBeTruthy(); - expect(x.valid).toBeFalsy(); + formHelper.expectError('x', 'notUnique'); }) ); });