From f2c6a2808ffca7a8853d7aabb91215ef37d78d1b Mon Sep 17 00:00:00 2001 From: Tifenn Guillas <tifenn.guillas@gmail.com> Date: Fri, 8 Oct 2021 16:28:33 +0200 Subject: [PATCH] WIP: tests on search-type components --- .../search-type/datetime.component.spec.ts | 124 +++++++++++++++++ .../search-type/datetime.component.ts | 14 +- .../search-type/field.component.spec.ts | 129 ++++++++++++++++++ .../criteria/search-type/field.component.ts | 26 ++-- .../search-type/help-like.component.spec.ts | 20 +++ .../search-type/help-like.component.ts | 8 +- .../search-type/json.component.spec.ts | 77 +++++++++++ .../criteria/search-type/json.component.ts | 14 +- 8 files changed, 388 insertions(+), 24 deletions(-) create mode 100644 client/src/app/instance/search/components/criteria/search-type/datetime.component.spec.ts create mode 100644 client/src/app/instance/search/components/criteria/search-type/field.component.spec.ts create mode 100644 client/src/app/instance/search/components/criteria/search-type/help-like.component.spec.ts create mode 100644 client/src/app/instance/search/components/criteria/search-type/json.component.spec.ts diff --git a/client/src/app/instance/search/components/criteria/search-type/datetime.component.spec.ts b/client/src/app/instance/search/components/criteria/search-type/datetime.component.spec.ts new file mode 100644 index 00000000..b1b119a8 --- /dev/null +++ b/client/src/app/instance/search/components/criteria/search-type/datetime.component.spec.ts @@ -0,0 +1,124 @@ +import { Component, Input, ViewChild } from '@angular/core'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; + +import { TooltipModule } from 'ngx-bootstrap/tooltip'; + +import { DatetimeComponent } from './datetime.component'; +import { FieldCriterion } from '../../../../store/models/criterion'; +import { BsDatepickerModule } from 'ngx-bootstrap/datepicker'; +import { NgSelectModule } from '@ng-select/ng-select'; +import { combineAll } from 'rxjs/operators'; + +describe('[Instance][Search][Component][Criteria][SearchType] DatetimeComponent', () => { + @Component({ + selector: `app-host`, + template: ` + <app-datetime + [id]="id" + [operator]="operator" + [label]="label" + [criterion]="criterion" + [advancedForm]="advancedForm"> + </app-datetime>` + }) + class TestHostComponent { + @ViewChild(DatetimeComponent, { static: false }) + public testedComponent: DatetimeComponent; + public id: number = undefined; + public operator: string = undefined; + public label: string = undefined; + public criterion: FieldCriterion = undefined; + public advancedForm: boolean = false; + } + + @Component({ selector: 'app-operator', template: '' }) + class OperatorStubComponent { + @Input() operator: string; + @Input() searchType: string; + @Input() advancedForm: boolean; + @Input() disabled: boolean; + } + + @Component({ selector: 'app-help-like', template: '' }) + class HelpLikeStubComponent { } + + let testHostComponent: TestHostComponent; + let testHostFixture: ComponentFixture<TestHostComponent>; + let testedComponent: DatetimeComponent; + + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [ + DatetimeComponent, + TestHostComponent, + OperatorStubComponent, + // HelpLikeStubComponent + ], + imports: [ + FormsModule, + ReactiveFormsModule, + NgSelectModule, + // TooltipModule.forRoot(), + BsDatepickerModule.forRoot() + ] + }); + testHostFixture = TestBed.createComponent(TestHostComponent); + testHostComponent = testHostFixture.componentInstance; + testHostFixture.detectChanges(); + testedComponent = testHostComponent.testedComponent; + }); + + it('should create the component', () => { + expect(testedComponent).toBeTruthy(); + }); + + it('should call ngOnChanges and apply changes', () => { + const spy = jest.spyOn(testedComponent, 'ngOnChanges'); + const date: Date = new Date('2019-02-17'); + testHostComponent.criterion = { id: 1, type: 'field', operator: 'eq', value: '2019-02-17 15:47' } as FieldCriterion; + testHostFixture.detectChanges(); + expect(testedComponent.form.controls.date.value).toEqual(date); + expect(testedComponent.form.controls.hh.value).toEqual('15'); + expect(testedComponent.form.controls.mm.value).toEqual('47'); + expect(testedComponent.form.disabled).toBeTruthy(); + testHostComponent.criterion = undefined; + testHostFixture.detectChanges(); + expect(testedComponent.form.controls.date.value).toBeNull(); + expect(testedComponent.form.controls.hh.value).toBeNull(); + expect(testedComponent.form.controls.mm.value).toBeNull(); + expect(testedComponent.form.enabled).toBeTruthy(); + expect(spy).toHaveBeenCalledTimes(2); + }); + + it('#changeOperator() should change the operator', () => { + expect(testedComponent.operator).toBeUndefined(); + testedComponent.changeOperator('toto'); + expect(testedComponent.operator).toBe('toto'); + }); + + it('raises the add criterion event when clicked', () => { + testedComponent.id = 1; + const operator = 'eq'; + testedComponent.operator = operator; + const date: Date = new Date('2019-02-17'); + testedComponent.form.controls.date.setValue(date); + testedComponent.form.controls.hh.setValue('15'); + testedComponent.form.controls.mm.setValue('47'); + const expectedCriterion = { id: testedComponent.id, type: 'field', operator, value: '2019-02-17 15:47' } as FieldCriterion; + testedComponent.addCriterion.subscribe((event: FieldCriterion) => expect(event).toEqual(expectedCriterion)); + testedComponent.emitAdd(); + }); + + it('#initTime(t) should return an array of string with 2 digits from 0 to t', () => { + const n = 10; + expect(testedComponent.initTime(n).length).toEqual(n); + expect(testedComponent.initTime(n)[5]).toEqual('05'); + }); + + it('#getDateString() should return a date as string', () => { + const dateString = '2019-02-17'; + const date = new Date(dateString); + expect(testedComponent.getDateString(date)).toEqual(dateString); + }); +}); diff --git a/client/src/app/instance/search/components/criteria/search-type/datetime.component.ts b/client/src/app/instance/search/components/criteria/search-type/datetime.component.ts index 0ad31ef7..3f60b69f 100644 --- a/client/src/app/instance/search/components/criteria/search-type/datetime.component.ts +++ b/client/src/app/instance/search/components/criteria/search-type/datetime.component.ts @@ -12,15 +12,17 @@ import { FormGroup, FormControl, Validators } from '@angular/forms'; import { Criterion, FieldCriterion } from 'src/app/instance/store/models'; +/** + * @class + * @classdesc Datetime search type component. + * + * @implements OnChanges + */ @Component({ selector: 'app-datetime', templateUrl: 'datetime.component.html', changeDetection: ChangeDetectionStrategy.OnPush }) -/** - * @class - * @classdesc Datetime search type component. - */ export class DatetimeComponent implements OnChanges { @Input() id: number; @Input() operator: string; @@ -39,9 +41,9 @@ export class DatetimeComponent implements OnChanges { mm: new FormControl('', [Validators.required]) }); - disabledOperator: boolean; + public disabledOperator: boolean; - ngOnChanges(changes: SimpleChanges) { + ngOnChanges(changes: SimpleChanges): void { if (changes.criterion && changes.criterion.currentValue) { const criterion = changes.criterion.currentValue as FieldCriterion; const [date, time] = criterion.value.split(' '); diff --git a/client/src/app/instance/search/components/criteria/search-type/field.component.spec.ts b/client/src/app/instance/search/components/criteria/search-type/field.component.spec.ts new file mode 100644 index 00000000..04076f22 --- /dev/null +++ b/client/src/app/instance/search/components/criteria/search-type/field.component.spec.ts @@ -0,0 +1,129 @@ +import { Component, Input, ViewChild } from '@angular/core'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; + +import { TooltipModule } from 'ngx-bootstrap/tooltip'; + +import { FieldComponent } from './field.component'; +import { FieldCriterion } from '../../../../store/models/criterion'; + +describe('[Instance][Search][Component][Criteria][SearchType] FieldComponent', () => { + @Component({ + selector: `app-host`, + template: ` + <app-field + [id]="id" + [operator]="operator" + [label]="label" + [placeholder]="placeholder" + [attributeType]="attributeType" + [criterion]="criterion" + [advancedForm]="advancedForm"> + </app-field>` + }) + class TestHostComponent { + @ViewChild(FieldComponent, { static: false }) + public testedComponent: FieldComponent; + public id: number = undefined; + public operator: string = undefined; + public label: string = undefined; + public placeholder: string = undefined; + public attributeType: string = undefined; + public criterion: FieldCriterion = undefined; + public advancedForm: boolean = false; + } + + @Component({ selector: 'app-operator', template: '' }) + class OperatorStubComponent { + @Input() operator: string; + @Input() searchType: string; + @Input() advancedForm: boolean; + @Input() disabled: boolean; + } + + @Component({ selector: 'app-help-like', template: '' }) + class HelpLikeStubComponent { } + + let testHostComponent: TestHostComponent; + let testHostFixture: ComponentFixture<TestHostComponent>; + let testedComponent: FieldComponent; + + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [ + FieldComponent, + TestHostComponent, + OperatorStubComponent, + HelpLikeStubComponent + ], + imports: [ + FormsModule, + ReactiveFormsModule, + TooltipModule.forRoot() + ] + }); + testHostFixture = TestBed.createComponent(TestHostComponent); + testHostComponent = testHostFixture.componentInstance; + testHostFixture.detectChanges(); + testedComponent = testHostComponent.testedComponent; + }); + + it('should create the component', () => { + expect(testedComponent).toBeTruthy(); + }); + + it('should call ngOnChanges and apply changes', () => { + const spy = jest.spyOn(testedComponent, 'ngOnChanges'); + testHostComponent.criterion = { id: 1, type: 'field', operator: 'eq', value: 'myValue' } as FieldCriterion; + testHostFixture.detectChanges(); + expect(testedComponent.form.controls.value.value).toEqual('myValue'); + expect(testedComponent.form.disabled).toBeTruthy(); + testHostComponent.criterion = undefined; + testHostFixture.detectChanges(); + expect(testedComponent.form.controls.value.value).toBeNull(); + expect(testedComponent.form.enabled).toBeTruthy(); + expect(spy).toHaveBeenCalledTimes(2); + }); + + it('#changeOperator() should change the operator', () => { + expect(testedComponent.operator).toBeUndefined(); + testedComponent.changeOperator('toto'); + expect(testedComponent.operator).toBe('toto'); + }); + + it('raises the add criterion event when clicked', () => { + testedComponent.id = 1; + const operator = 'eq'; + testedComponent.operator = operator; + testedComponent.form.controls.value.setValue('myValue'); + const expectedCriterion = { id: testedComponent.id, type: 'field', operator, value: 'myValue' } as FieldCriterion; + testedComponent.addCriterion.subscribe((event: FieldCriterion) => expect(event).toEqual(expectedCriterion)); + testedComponent.emitAdd(); + }); + + it('#getType() should return `number` if criterion is a number type', () => { + testedComponent.attributeType = 'smallint'; + expect(testedComponent.getType()).toEqual('number'); + testedComponent.attributeType = 'integer'; + expect(testedComponent.getType()).toEqual('number'); + testedComponent.attributeType = 'decimal'; + expect(testedComponent.getType()).toEqual('number'); + testedComponent.attributeType = 'float'; + expect(testedComponent.getType()).toEqual('number'); + }); + + it('#getType() should return `text` if criterion is not a number type', () => { + testedComponent.attributeType = 'char'; + expect(testedComponent.getType()).toEqual('text'); + }); + + it('#getPlaceholder() should fill the placeholder if defined', () => { + const placeholder = 'placeholder'; + testedComponent.placeholder = placeholder; + expect(testedComponent.getPlaceholder()).toEqual(placeholder); + }); + + it('#getPlaceholder() should not fill the placeholder if not defined', () => { + expect(testedComponent.getPlaceholder()).toEqual(''); + }); +}); diff --git a/client/src/app/instance/search/components/criteria/search-type/field.component.ts b/client/src/app/instance/search/components/criteria/search-type/field.component.ts index fb942cd2..2cf4ed8c 100644 --- a/client/src/app/instance/search/components/criteria/search-type/field.component.ts +++ b/client/src/app/instance/search/components/criteria/search-type/field.component.ts @@ -7,21 +7,31 @@ * file that was distributed with this source code. */ -import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy, SimpleChanges } from '@angular/core'; +import { + Component, + Input, + Output, + EventEmitter, + ChangeDetectionStrategy, + SimpleChanges, + OnChanges +} from '@angular/core'; import { FormGroup, FormControl, Validators } from '@angular/forms'; import { FieldCriterion, Criterion } from 'src/app/instance/store/models'; +/** + * @class + * @classdesc Field search type component. + * + * @implements OnChanges + */ @Component({ selector: 'app-field', templateUrl: 'field.component.html', changeDetection: ChangeDetectionStrategy.OnPush, }) -/** - * @class - * @classdesc Field search type component. - */ -export class FieldComponent { +export class FieldComponent implements OnChanges { @Input() id: number; @Input() operator: string; @Input() label: string; @@ -36,9 +46,9 @@ export class FieldComponent { value: new FormControl('', [Validators.required]) }); - disabledOperator: boolean; + public disabledOperator: boolean; - ngOnChanges(changes: SimpleChanges) { + ngOnChanges(changes: SimpleChanges): void { if (changes.criterion && changes.criterion.currentValue) { this.form.patchValue(this.criterion); this.form.disable(); diff --git a/client/src/app/instance/search/components/criteria/search-type/help-like.component.spec.ts b/client/src/app/instance/search/components/criteria/search-type/help-like.component.spec.ts new file mode 100644 index 00000000..bb1eb2c0 --- /dev/null +++ b/client/src/app/instance/search/components/criteria/search-type/help-like.component.spec.ts @@ -0,0 +1,20 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { HelpLikeComponent } from './help-like.component'; + +describe('[Instance][Search][Component][Criteria][SearchType] HelpLikeComponent', () => { + let component: HelpLikeComponent; + let fixture: ComponentFixture<HelpLikeComponent>; + + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [HelpLikeComponent] + }); + fixture = TestBed.createComponent(HelpLikeComponent); + component = fixture.componentInstance; + }); + + it('should create the component', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/client/src/app/instance/search/components/criteria/search-type/help-like.component.ts b/client/src/app/instance/search/components/criteria/search-type/help-like.component.ts index 3600c605..57598de5 100644 --- a/client/src/app/instance/search/components/criteria/search-type/help-like.component.ts +++ b/client/src/app/instance/search/components/criteria/search-type/help-like.component.ts @@ -9,12 +9,12 @@ import { Component } from '@angular/core'; -@Component({ - selector: 'app-help-like', - templateUrl: 'help-like.component.html' -}) /** * @class * @classdesc Help like operator component. */ +@Component({ + selector: 'app-help-like', + templateUrl: 'help-like.component.html' +}) export class HelpLikeComponent { } diff --git a/client/src/app/instance/search/components/criteria/search-type/json.component.spec.ts b/client/src/app/instance/search/components/criteria/search-type/json.component.spec.ts new file mode 100644 index 00000000..6941d117 --- /dev/null +++ b/client/src/app/instance/search/components/criteria/search-type/json.component.spec.ts @@ -0,0 +1,77 @@ +import { Component, ViewChild } from '@angular/core'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; + +import { JsonComponent } from './json.component'; +import { JsonCriterion } from '../../../../store/models/criterion'; + +describe('[Instance][Search][Component][Criteria][SearchType] JsonComponent', () => { + @Component({ + selector: `app-host`, + template: ` + <app-json-criteria + [id]="id" + [label]="label" + [criterion]="criterion"> + </app-json-criteria>` + }) + class TestHostComponent { + @ViewChild(JsonComponent, { static: false }) + public testedComponent: JsonComponent; + public id: number = undefined; + public label: string = undefined; + public criterion: JsonCriterion = undefined; + } + + let testHostComponent: TestHostComponent; + let testHostFixture: ComponentFixture<TestHostComponent>; + let testedComponent: JsonComponent; + + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [ + JsonComponent, + TestHostComponent + ], + imports: [ + FormsModule, + ReactiveFormsModule + ] + }); + testHostFixture = TestBed.createComponent(TestHostComponent); + testHostComponent = testHostFixture.componentInstance; + testHostFixture.detectChanges(); + testedComponent = testHostComponent.testedComponent; + }); + + it('should create the component', () => { + expect(testedComponent).toBeTruthy(); + }); + + it('should call ngOnChanges and apply changes', () => { + const spy = jest.spyOn(testedComponent, 'ngOnChanges'); + testHostComponent.criterion = { id: testedComponent.id, type: 'json', path: 'myPath', operator: 'myOperator', value: 'myValue' } as JsonCriterion; + testHostFixture.detectChanges(); + expect(testedComponent.form.controls.path.value).toEqual('myPath'); + expect(testedComponent.form.controls.operator.value).toEqual('myOperator'); + expect(testedComponent.form.controls.value.value).toEqual('myValue'); + expect(testedComponent.form.disabled).toBeTruthy(); + testHostComponent.criterion = undefined; + testHostFixture.detectChanges(); + expect(testedComponent.form.controls.path.value).toBeNull(); + expect(testedComponent.form.controls.operator.value).toBeNull(); + expect(testedComponent.form.controls.value.value).toBeNull(); + expect(testedComponent.form.enabled).toBeTruthy(); + expect(spy).toHaveBeenCalledTimes(2); + }); + + it('raises the add criterion event when clicked', () => { + testedComponent.id = 1; + testedComponent.form.controls.path.setValue('myPath'); + testedComponent.form.controls.operator.setValue('myOperator'); + testedComponent.form.controls.value.setValue('myValue'); + const expectedCriterion = { id: testedComponent.id, type: 'json', path: 'myPath', operator: 'myOperator', value: 'myValue' } as JsonCriterion; + testedComponent.addCriterion.subscribe((event: JsonCriterion) => expect(event).toEqual(expectedCriterion)); + testedComponent.emitAdd(); + }); +}); diff --git a/client/src/app/instance/search/components/criteria/search-type/json.component.ts b/client/src/app/instance/search/components/criteria/search-type/json.component.ts index 32ddefd7..cb9e4b16 100644 --- a/client/src/app/instance/search/components/criteria/search-type/json.component.ts +++ b/client/src/app/instance/search/components/criteria/search-type/json.component.ts @@ -12,15 +12,17 @@ import { FormGroup, FormControl, Validators } from '@angular/forms'; import { JsonCriterion, Criterion } from 'src/app/instance/store/models'; +/** + * @class + * @classdesc JSON search type component. + * + * @implements OnChanges + */ @Component({ selector: 'app-json-criteria', templateUrl: 'json.component.html', changeDetection: ChangeDetectionStrategy.OnPush }) -/** - * @class - * @classdesc JSON search type component. - */ export class JsonComponent implements OnChanges { @Input() id: number; @Input() label: string; @@ -34,7 +36,7 @@ export class JsonComponent implements OnChanges { value: new FormControl('', [Validators.required]) }); - ngOnChanges(changes: SimpleChanges) { + ngOnChanges(changes: SimpleChanges): void { if (changes.criterion && changes.criterion.currentValue) { this.form.patchValue(changes.criterion.currentValue); this.form.disable(); @@ -52,7 +54,7 @@ export class JsonComponent implements OnChanges { * @fires EventEmitter<JsonCriterion> */ emitAdd(): void { - const js = {id: this.id, type: 'json', ...this.form.value}; + const js = { id: this.id, type: 'json', ...this.form.value }; this.addCriterion.emit(js); } } -- GitLab