import { Component, DebugElement, NgModule } from '@angular/core'; import { async, ComponentFixture, inject, TestBed } from '@angular/core/testing'; import { AbstractControl, FormControl, ReactiveFormsModule, Validators } from '@angular/forms'; import { MatNativeDateModule } from '@angular/material/core'; import { By } from '@angular/platform-browser'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { PtDynamicElementComponent } from './dynamic-element.component'; import { PtDynamicFormsComponent } from './dynamic-forms.component'; import { DynamicFormsModule } from './dynamic-forms.module'; import { IPtDynamicElementConfig, PtDynamicElement, PtDynamicType } from './services/dynamic-forms.service'; @Component({ template: ` {{ control.errors['customError'] }} `, }) class PtDynamicFormsTestComponent { elements: IPtDynamicElementConfig[]; } @Component({ selector: 'prutech-dynamic-input-test', template: ` `, }) export class PtDynamicTestComponent { control: FormControl; } @NgModule({ declarations: [PtDynamicTestComponent], imports: [ReactiveFormsModule], exports: [PtDynamicTestComponent], entryComponents: [PtDynamicTestComponent], }) export class PtDynamicTestModule { } describe('Component: PtDynamicForms', () => { beforeEach(async(() => { TestBed.configureTestingModule({ imports: [ NoopAnimationsModule, MatNativeDateModule, DynamicFormsModule, PtDynamicTestModule, ], declarations: [PtDynamicFormsTestComponent], }); TestBed.compileComponents(); })); it('should create the component', async( inject([], () => { const fixture: ComponentFixture = TestBed.createComponent(PtDynamicFormsTestComponent); const component: PtDynamicFormsTestComponent = fixture.debugElement.componentInstance; fixture.detectChanges(); expect(component).toBeTruthy(); }), )); it('should render dynamic elements', async( inject([], () => { const fixture: ComponentFixture = TestBed.createComponent(PtDynamicFormsTestComponent); const component: PtDynamicFormsTestComponent = fixture.debugElement.componentInstance; expect(fixture.debugElement.queryAll(By.directive(PtDynamicElementComponent)).length).toBe(0); component.elements = [ { name: 'first_name', type: PtDynamicType.Text, }, { name: 'password', type: PtDynamicElement.Password, }, { name: 'on_it', type: PtDynamicType.Boolean, }, { name: 'age', type: PtDynamicType.Number, }, { name: 'nodes', type: PtDynamicElement.Slider, }, { name: 'description', type: PtDynamicElement.Textarea, }, { name: 'sex', type: PtDynamicType.Array, selections: ['M', 'F'], }, { name: 'dob', type: PtDynamicElement.Datepicker, }, ] as IPtDynamicElementConfig[]; fixture.detectChanges(); fixture.whenStable().then(() => { expect(fixture.debugElement.queryAll(By.directive(PtDynamicElementComponent)).length).toBe(8); }); }), )); it('should render dynamic elements and show form invalid because an input is required', async( inject([], () => { const fixture: ComponentFixture = TestBed.createComponent(PtDynamicFormsTestComponent); const component: PtDynamicFormsTestComponent = fixture.debugElement.componentInstance; expect(fixture.debugElement.queryAll(By.directive(PtDynamicElementComponent)).length).toBe(0); component.elements = [ { name: 'first_name', type: PtDynamicType.Text, required: true, }, { name: 'on_it', type: PtDynamicType.Boolean, default: true, }, ] as IPtDynamicElementConfig[]; fixture.detectChanges(); fixture.whenStable().then(() => { expect(fixture.debugElement.queryAll(By.directive(PtDynamicElementComponent)).length).toBe(2); const dynamicFormsComponent: PtDynamicFormsComponent = fixture.debugElement.query( By.directive(PtDynamicFormsComponent), ).componentInstance; expect(dynamicFormsComponent.valid).toBeFalsy(); /* tslint:disable-next-line */ expect(JSON.stringify(dynamicFormsComponent.value)).toBe(JSON.stringify({on_it: true})); }); }), )); it('should render dynamic elements and show form invalid because a number is less than min', async( inject([], () => { const fixture: ComponentFixture = TestBed.createComponent(PtDynamicFormsTestComponent); const component: PtDynamicFormsTestComponent = fixture.debugElement.componentInstance; expect(fixture.debugElement.queryAll(By.directive(PtDynamicElementComponent)).length).toBe(0); component.elements = [ { name: 'first_name', type: PtDynamicType.Text, required: true, }, { name: 'age', type: PtDynamicType.Number, min: 18, default: 17, }, ] as IPtDynamicElementConfig[]; fixture.detectChanges(); fixture.whenStable().then(() => { expect(fixture.debugElement.queryAll(By.directive(PtDynamicElementComponent)).length).toBe(2); const dynamicFormsComponent: PtDynamicFormsComponent = fixture.debugElement.query( By.directive(PtDynamicFormsComponent), ).componentInstance; expect(dynamicFormsComponent.valid).toBeFalsy(); /* tslint:disable-next-line */ expect(JSON.stringify(dynamicFormsComponent.value)).toBe(JSON.stringify({age: 17})); }); }), )); it('should render dynamic elements and show form valid', async( inject([], () => { const fixture: ComponentFixture = TestBed.createComponent(PtDynamicFormsTestComponent); const component: PtDynamicFormsTestComponent = fixture.debugElement.componentInstance; expect(fixture.debugElement.queryAll(By.directive(PtDynamicElementComponent)).length).toBe(0); const dob: Date = new Date(); component.elements = [ { name: 'first_name', type: PtDynamicType.Text, required: true, default: 'name', }, { name: 'age', type: PtDynamicType.Number, default: 20, min: 18, max: 30, }, { name: 'dob', type: PtDynamicType.Date, default: dob, required: true, }, ] as IPtDynamicElementConfig[]; fixture.detectChanges(); fixture.whenStable().then(() => { expect(fixture.debugElement.queryAll(By.directive(PtDynamicElementComponent)).length).toBe(3); const dynamicFormsComponent: PtDynamicFormsComponent = fixture.debugElement.query( By.directive(PtDynamicFormsComponent), ).componentInstance; expect(dynamicFormsComponent.valid).toBeTruthy(); expect(JSON.stringify(dynamicFormsComponent.value)).toBe(JSON.stringify({first_name: 'name', age: 20, dob})); }); }), )); it('should render dynamic elements and show form invalid because character length is less than minLength', async( inject([], () => { const fixture: ComponentFixture = TestBed.createComponent(PtDynamicFormsTestComponent); const component: PtDynamicFormsTestComponent = fixture.debugElement.componentInstance; expect(fixture.debugElement.queryAll(By.directive(PtDynamicElementComponent)).length).toBe(0); component.elements = [ { name: 'password', type: PtDynamicType.Text, minLength: 8, default: 'mypwd', }, ] as IPtDynamicElementConfig[]; fixture.detectChanges(); fixture.whenStable().then(() => { expect(fixture.debugElement.queryAll(By.directive(PtDynamicElementComponent)).length).toBe(1); const dynamicFormsComponent: PtDynamicFormsComponent = fixture.debugElement.query( By.directive(PtDynamicFormsComponent), ).componentInstance; expect(dynamicFormsComponent.valid).toBeFalsy(); // tslint:disable-next-line:no-hardcoded-credentials expect(JSON.stringify(dynamicFormsComponent.value)).toBe(JSON.stringify({password: 'mypwd'})); }); }), )); it('should render dynamic elements and show form invalid because character length is more than maxLength', async( inject([], () => { const fixture: ComponentFixture = TestBed.createComponent(PtDynamicFormsTestComponent); const component: PtDynamicFormsTestComponent = fixture.debugElement.componentInstance; expect(fixture.debugElement.queryAll(By.directive(PtDynamicElementComponent)).length).toBe(0); component.elements = [ { name: 'password', type: PtDynamicType.Text, maxLength: 8, default: 'myVeryLongString', }, ] as IPtDynamicElementConfig[]; fixture.detectChanges(); fixture.whenStable().then(() => { expect(fixture.debugElement.queryAll(By.directive(PtDynamicElementComponent)).length).toBe(1); const dynamicFormsComponent: PtDynamicFormsComponent = fixture.debugElement.query( By.directive(PtDynamicFormsComponent), ).componentInstance; expect(dynamicFormsComponent.valid).toBeFalsy(); // tslint:disable-next-line:no-hardcoded-credentials expect(JSON.stringify(dynamicFormsComponent.value)).toBe(JSON.stringify({password: 'myVeryLongString'})); }); }), )); it('should render dynamic elements and show form valid', async( inject([], () => { const fixture: ComponentFixture = TestBed.createComponent(PtDynamicFormsTestComponent); const component: PtDynamicFormsTestComponent = fixture.debugElement.componentInstance; expect(fixture.debugElement.queryAll(By.directive(PtDynamicElementComponent)).length).toBe(0); component.elements = [ { name: 'password', type: PtDynamicType.Text, minLength: 8, maxLength: 20, default: 'mySuperSecretPw', }, ] as IPtDynamicElementConfig[]; fixture.detectChanges(); fixture.whenStable().then(() => { expect(fixture.debugElement.queryAll(By.directive(PtDynamicElementComponent)).length).toBe(1); const dynamicFormsComponent: PtDynamicFormsComponent = fixture.debugElement.query( By.directive(PtDynamicFormsComponent), ).componentInstance; expect(dynamicFormsComponent.valid).toBeTruthy(); // tslint:disable-next-line:no-hardcoded-credentials expect(JSON.stringify(dynamicFormsComponent.value)).toBe(JSON.stringify({password: 'mySuperSecretPw'})); }); }), )); it('should render dynamic elements and show form invalid with custom validation', async( inject([], () => { const fixture: ComponentFixture = TestBed.createComponent(PtDynamicFormsTestComponent); const component: PtDynamicFormsTestComponent = fixture.debugElement.componentInstance; expect(fixture.debugElement.queryAll(By.directive(PtDynamicElementComponent)).length).toBe(0); component.elements = [ { name: 'number', type: PtDynamicType.Number, default: 15, appearance: '', validators: [ { validator: (control: AbstractControl) => { const isValid: boolean = control.value > 21 && control.value < 23; return !isValid ? {length: true} : undefined; }, }, ], }, ] as IPtDynamicElementConfig[]; fixture.detectChanges(); fixture.whenStable().then(() => { expect(fixture.debugElement.queryAll(By.directive(PtDynamicElementComponent)).length).toBe(1); const dynamicFormsComponent: PtDynamicFormsComponent = fixture.debugElement.query( By.directive(PtDynamicFormsComponent), ).componentInstance; expect(dynamicFormsComponent.valid).toBeFalsy(); expect(JSON.stringify(dynamicFormsComponent.value)).toBe(JSON.stringify({number: 15})); }); }), )); it('should render dynamic elements and show form invalid with Angular validation', async( inject([], () => { const fixture: ComponentFixture = TestBed.createComponent(PtDynamicFormsTestComponent); const component: PtDynamicFormsTestComponent = fixture.debugElement.componentInstance; expect(fixture.debugElement.queryAll(By.directive(PtDynamicElementComponent)).length).toBe(0); component.elements = [ { name: 'hexColor', type: PtDynamicType.Text, required: true, default: '#ZZZZZZ', validators: [ { validator: Validators.pattern(/^#[A-Fa-f0-9]{6}$/), }, ], }, ] as IPtDynamicElementConfig[]; fixture.detectChanges(); fixture.whenStable().then(() => { expect(fixture.debugElement.queryAll(By.directive(PtDynamicElementComponent)).length).toBe(1); const dynamicFormsComponent: PtDynamicFormsComponent = fixture.debugElement.query( By.directive(PtDynamicFormsComponent), ).componentInstance; expect(dynamicFormsComponent.valid).toBeFalsy(); expect(JSON.stringify(dynamicFormsComponent.value)).toBe(JSON.stringify({hexColor: '#ZZZZZZ'})); }); }), )); it('should render dynamic elements and show form valid with custom validations', async( inject([], () => { const fixture: ComponentFixture = TestBed.createComponent(PtDynamicFormsTestComponent); const component: PtDynamicFormsTestComponent = fixture.debugElement.componentInstance; expect(fixture.debugElement.queryAll(By.directive(PtDynamicElementComponent)).length).toBe(0); component.elements = [ { name: 'hexColor', type: PtDynamicType.Text, required: true, default: '#F1F1F1', validators: [ { validator: Validators.pattern(/^#[A-Fa-f0-9]{6}$/), }, ], }, { name: 'number', type: PtDynamicType.Number, default: 22, validators: [ { validator: (control: AbstractControl) => { const isValid: boolean = control.value > 21 && control.value < 23; return !isValid ? {length: true} : undefined; }, }, ], }, ] as IPtDynamicElementConfig[]; fixture.detectChanges(); fixture.whenStable().then(() => { expect(fixture.debugElement.queryAll(By.directive(PtDynamicElementComponent)).length).toBe(2); const dynamicFormsComponent: PtDynamicFormsComponent = fixture.debugElement.query( By.directive(PtDynamicFormsComponent), ).componentInstance; expect(dynamicFormsComponent.valid).toBeTruthy(); expect(JSON.stringify(dynamicFormsComponent.value)).toBe(JSON.stringify({hexColor: '#F1F1F1', number: 22})); }); }), )); it('should render errors with manual validations', async( inject([], () => { const fixture: ComponentFixture = TestBed.createComponent(PtDynamicFormsTestComponent); const component: PtDynamicFormsTestComponent = fixture.debugElement.componentInstance; component.elements = [ { name: 'customElement', label: 'Custom Element', type: PtDynamicType.Text, }, ] as IPtDynamicElementConfig[]; fixture.detectChanges(); fixture.whenStable().then(() => { const dynamicFormsComponent: PtDynamicFormsComponent = fixture.debugElement.query( By.directive(PtDynamicFormsComponent), ).componentInstance; fixture.detectChanges(); fixture.whenStable().then(() => { const key: string = 'customElement'; dynamicFormsComponent.controls[key].markAsTouched(); dynamicFormsComponent.controls[key].setErrors({customError: 'CUSTOM_ERROR'}); fixture.detectChanges(); fixture.whenStable().then(() => { expect(fixture.debugElement.queryAll(By.css('#custom-error')).length).toBe(1); expect(fixture.debugElement.query(By.css('#custom-error')).nativeElement.textContent).toBe('CUSTOM_ERROR'); }); }); }); }), )); it('should render dynamic elements with one element disabled', async( inject([], () => { const fixture: ComponentFixture = TestBed.createComponent(PtDynamicFormsTestComponent); const component: PtDynamicFormsTestComponent = fixture.debugElement.componentInstance; expect(fixture.debugElement.queryAll(By.directive(PtDynamicElementComponent)).length).toBe(0); component.elements = [ { name: 'hexColor', type: PtDynamicType.Text, required: true, default: '#F1F1F1', }, { name: 'number', type: PtDynamicType.Number, disabled: true, required: true, }, ] as IPtDynamicElementConfig[]; fixture.detectChanges(); fixture.whenStable().then(() => { expect(fixture.debugElement.queryAll(By.directive(PtDynamicElementComponent)).length).toBe(2); const dynamicFormsComponent: PtDynamicFormsComponent = fixture.debugElement.query( By.directive(PtDynamicFormsComponent), ).componentInstance; expect(dynamicFormsComponent.valid).toBeTruthy(); /* tslint:disable-next-line */ expect(JSON.stringify(dynamicFormsComponent.value)).toBe(JSON.stringify({hexColor: '#F1F1F1'})); }); }), )); it('should render disabled file input', async( inject([], () => { const fixture: ComponentFixture = TestBed.createComponent(PtDynamicFormsTestComponent); const component: PtDynamicFormsTestComponent = fixture.debugElement.componentInstance; expect(fixture.debugElement.queryAll(By.directive(PtDynamicElementComponent)).length).toBe(0); component.elements = [ { name: 'file', type: PtDynamicElement.FileInput, disabled: true, }, ] as IPtDynamicElementConfig[]; fixture.detectChanges(); fixture.whenStable().then(() => { const button: DebugElement = fixture.debugElement.query(By.css('prutech-file-input button')); const hiddenFileInput: DebugElement = fixture.debugElement.query(By.css('prutech-file-input .prutech-file-input-hidden')); expect(button.attributes.disabled).not.toBePtll(); expect(hiddenFileInput.attributes.disabled).not.toBePtll(); }); }), )); it('should render dynamic custom element', async( inject([], () => { const fixture: ComponentFixture = TestBed.createComponent(PtDynamicFormsTestComponent); const component: PtDynamicFormsTestComponent = fixture.debugElement.componentInstance; expect(fixture.debugElement.queryAll(By.directive(PtDynamicElementComponent)).length).toBe(0); component.elements = [ { name: 'custom', type: PtDynamicTestComponent, default: 'value', }, ] as IPtDynamicElementConfig[]; fixture.detectChanges(); fixture.whenStable().then(() => { expect(fixture.debugElement.queryAll(By.directive(PtDynamicElementComponent)).length).toBe(1); const dynamicFormsComponent: PtDynamicFormsComponent = fixture.debugElement.query( By.directive(PtDynamicFormsComponent), ).componentInstance; expect(dynamicFormsComponent.valid).toBeTruthy(); expect(JSON.stringify(dynamicFormsComponent.value)).toBe(JSON.stringify({custom: 'value'})); }); }), )); });