From d1b8f2dfab942c2a1517b628ab62ccd010fbffb3 Mon Sep 17 00:00:00 2001 From: Tifenn Guillas <tifenn.guillas@gmail.com> Date: Wed, 6 Oct 2021 14:35:44 +0200 Subject: [PATCH] WIP: Tests on search type components --- .../search-type/list.component.spec.ts | 82 +++++++++++++ .../criteria/search-type/list.component.ts | 12 +- .../search-type/operator.component.spec.ts | 36 ++++++ .../search-type/operator.component.ts | 8 +- .../search-type/radio.component.spec.ts | 82 +++++++++++++ .../criteria/search-type/radio.component.ts | 12 +- .../select-multiple.component.spec.ts | 88 ++++++++++++++ .../search-type/select-multiple.component.ts | 14 ++- .../search-type/select.component.spec.ts | 108 ++++++++++++++++++ .../criteria/search-type/select.component.ts | 12 +- .../search-type/time.component.spec.ts | 83 ++++++++++---- .../criteria/search-type/time.component.ts | 2 +- 12 files changed, 490 insertions(+), 49 deletions(-) create mode 100644 client/src/app/instance/search/components/criteria/search-type/list.component.spec.ts create mode 100644 client/src/app/instance/search/components/criteria/search-type/operator.component.spec.ts create mode 100644 client/src/app/instance/search/components/criteria/search-type/radio.component.spec.ts create mode 100644 client/src/app/instance/search/components/criteria/search-type/select-multiple.component.spec.ts create mode 100644 client/src/app/instance/search/components/criteria/search-type/select.component.spec.ts diff --git a/client/src/app/instance/search/components/criteria/search-type/list.component.spec.ts b/client/src/app/instance/search/components/criteria/search-type/list.component.spec.ts new file mode 100644 index 00000000..ea009ff9 --- /dev/null +++ b/client/src/app/instance/search/components/criteria/search-type/list.component.spec.ts @@ -0,0 +1,82 @@ +import { Component, ViewChild } from '@angular/core'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; + +import { ListComponent } from './list.component'; +import { ListCriterion } from '../../../../store/models/criterion'; + +describe('[Instance][Search][Component][Criteria][SearchType] ListComponent', () => { + @Component({ + selector: `app-host`, + template: ` + <app-list + [id]="id" + [label]="label" + [placeholder]="placeholder" + [criterion]="criterion"> + </app-list>` + }) + class TestHostComponent { + @ViewChild(ListComponent, { static: false }) + public testedComponent: ListComponent; + public id: number = undefined; + public label: string = undefined; + public placeholder: string = undefined; + public criterion: ListCriterion = undefined; + } + + let testHostComponent: TestHostComponent; + let testHostFixture: ComponentFixture<TestHostComponent>; + let testedComponent: ListComponent; + + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [ + ListComponent, + 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: 'list', values: ['1', '2'] } as ListCriterion; + testHostFixture.detectChanges(); + expect(testedComponent.form.controls.list.value).toEqual('1\n2'); + expect(testedComponent.form.disabled).toBeTruthy(); + testHostComponent.criterion = undefined; + testHostFixture.detectChanges(); + expect(testedComponent.form.controls.list.value).toBeNull(); + expect(testedComponent.form.enabled).toBeTruthy(); + expect(spy).toHaveBeenCalledTimes(2); + }); + + it('#getPlaceholder() should fill the placeholder if defined', () => { + testedComponent.placeholder = 'placeholder'; + expect(testedComponent.getPlaceholder()).toEqual('placeholder'); + }); + + it('#getPlaceholder() should not fill the placeholder if not defined', () => { + expect(testedComponent.getPlaceholder()).toEqual(''); + }); + + it('raises the add criterion event when clicked', () => { + testedComponent.id = 1; + testedComponent.form.controls.list.setValue('1\n2'); + const expectedCriterion = { id: testedComponent.id, type: 'list', values: ['1', '2'] } as ListCriterion; + testedComponent.addCriterion.subscribe((event: ListCriterion) => expect(event).toEqual(expectedCriterion)); + testedComponent.emitAdd(); + }); +}); diff --git a/client/src/app/instance/search/components/criteria/search-type/list.component.ts b/client/src/app/instance/search/components/criteria/search-type/list.component.ts index 9887535b..ed743f79 100644 --- a/client/src/app/instance/search/components/criteria/search-type/list.component.ts +++ b/client/src/app/instance/search/components/criteria/search-type/list.component.ts @@ -12,16 +12,18 @@ import { FormGroup, FormControl, Validators } from '@angular/forms'; import { ListCriterion, Criterion } from 'src/app/instance/store/models'; +/** + * @class + * @classdesc List search type component. + * + * @implements OnChanges + */ @Component({ selector: 'app-list', templateUrl: 'list.component.html', styleUrls: ['operator.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }) -/** - * @class - * @classdesc List search type component. - */ export class ListComponent implements OnChanges { @Input() id: number; @Input() label: string; @@ -34,7 +36,7 @@ export class ListComponent implements OnChanges { list: new FormControl('', [Validators.required]) }); - ngOnChanges(changes: SimpleChanges) { + ngOnChanges(changes: SimpleChanges): void { if (changes.criterion && changes.criterion.currentValue) { const criterion = changes.criterion.currentValue as ListCriterion; diff --git a/client/src/app/instance/search/components/criteria/search-type/operator.component.spec.ts b/client/src/app/instance/search/components/criteria/search-type/operator.component.spec.ts new file mode 100644 index 00000000..e9eb1da2 --- /dev/null +++ b/client/src/app/instance/search/components/criteria/search-type/operator.component.spec.ts @@ -0,0 +1,36 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { OperatorComponent } from './operator.component'; + +describe('[Instance][Search][Component][Criteria][SearchType] OperatorComponent', () => { + let component: OperatorComponent; + let fixture: ComponentFixture<OperatorComponent>; + + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [OperatorComponent] + }); + fixture = TestBed.createComponent(OperatorComponent); + component = fixture.componentInstance; + }); + + it('should create the component', () => { + expect(component).toBeTruthy(); + }); + + it('raises the changeOperator event when the value change', () => { + component.changeOperator.subscribe((event: string) => expect(event).toEqual('eq')); + component.emitChange('eq'); + }); + + it('#getLabel() should return the correct operator form label', () => { + expect(component.getLabel('eq')).toBe('='); + expect(component.getLabel('neq')).toBe('≠'); + expect(component.getLabel('gt')).toBe('>'); + expect(component.getLabel('gte')).toBe('>='); + expect(component.getLabel('lt')).toBe('<'); + expect(component.getLabel('lte')).toBe('<='); + expect(component.getLabel('lk')).toBe('like'); + expect(component.getLabel('nlk')).toBe('not like'); + }); +}); diff --git a/client/src/app/instance/search/components/criteria/search-type/operator.component.ts b/client/src/app/instance/search/components/criteria/search-type/operator.component.ts index 32b44df3..1d0ac866 100644 --- a/client/src/app/instance/search/components/criteria/search-type/operator.component.ts +++ b/client/src/app/instance/search/components/criteria/search-type/operator.component.ts @@ -9,16 +9,16 @@ import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy } from '@angular/core'; +/** + * @class + * @classdesc Operator component. + */ @Component({ selector: 'app-operator', templateUrl: 'operator.component.html', styleUrls: ['operator.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush }) -/** - * @class - * @classdesc Operator component. - */ export class OperatorComponent { @Input() operator: string; @Input() searchType: string; diff --git a/client/src/app/instance/search/components/criteria/search-type/radio.component.spec.ts b/client/src/app/instance/search/components/criteria/search-type/radio.component.spec.ts new file mode 100644 index 00000000..c6abb7b3 --- /dev/null +++ b/client/src/app/instance/search/components/criteria/search-type/radio.component.spec.ts @@ -0,0 +1,82 @@ +import { Component, Input, ViewChild } from '@angular/core'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; + +import { RadioComponent } from './radio.component'; +import { FieldCriterion } from '../../../../store/models/criterion'; +import { Option } from '../../../../../metamodel/models'; + +describe('[Instance][Search][Component][Criteria][SearchType] RadioComponent', () => { + @Component({ + selector: `app-host`, + template: ` + <app-radio + [id]="id" + [label]="label" + [operator]="operator" + [options]="options" + [criterion]="criterion"> + </app-radio>` + }) + class TestHostComponent { + @ViewChild(RadioComponent, { static: false }) + public testedComponent: RadioComponent; + public id: number = undefined; + public label: string = undefined; + public operator: string = undefined; + public options: Option[] = undefined; + public criterion: FieldCriterion = undefined; + } + + let testHostComponent: TestHostComponent; + let testHostFixture: ComponentFixture<TestHostComponent>; + let testedComponent: RadioComponent; + + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [ + RadioComponent, + 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: 1, type: 'field', operator: 'eq', value: 'three' } as FieldCriterion; + testHostFixture.detectChanges(); + expect(testedComponent.form.controls.radio.value).toEqual('three'); + expect(testedComponent.form.disabled).toBeTruthy(); + testHostComponent.criterion = undefined; + testHostFixture.detectChanges(); + expect(testedComponent.form.controls.radio.value).toBeNull(); + expect(testedComponent.form.enabled).toBeTruthy(); + expect(spy).toHaveBeenCalledTimes(2); + }); + + it('raises the add criterion event when clicked', () => { + testedComponent.id = 1; + testedComponent.operator = 'eq'; + testedComponent.form.controls.radio.setValue('three'); + testedComponent.options = [ + { label: 'One', value: 'one', display: 1 }, + { label: 'Two', value: 'two', display: 2 }, + { label: 'Three', value: 'three', display: 3 } + ]; + const expectedCriterion = { id: testedComponent.id, type: 'field', operator: 'eq', value: 'three' } as FieldCriterion; + testedComponent.addCriterion.subscribe((event: FieldCriterion) => expect(event).toEqual(expectedCriterion)); + testedComponent.emitAdd(); + }); +}); diff --git a/client/src/app/instance/search/components/criteria/search-type/radio.component.ts b/client/src/app/instance/search/components/criteria/search-type/radio.component.ts index 8e43ccce..c61794ad 100644 --- a/client/src/app/instance/search/components/criteria/search-type/radio.component.ts +++ b/client/src/app/instance/search/components/criteria/search-type/radio.component.ts @@ -13,15 +13,17 @@ import { FormGroup, FormControl, Validators } from '@angular/forms'; import { Criterion, FieldCriterion } from 'src/app/instance/store/models'; import { Option } from 'src/app/metamodel/models'; +/** + * @class + * @classdesc Radio search type component. + * + * @implements OnChanges + */ @Component({ selector: 'app-radio', templateUrl: 'radio.component.html', changeDetection: ChangeDetectionStrategy.OnPush }) -/** - * @class - * @classdesc Radio search type component. - */ export class RadioComponent implements OnChanges { @Input() id: number; @Input() operator: string; @@ -35,7 +37,7 @@ export class RadioComponent implements OnChanges { radio: new FormControl('', [Validators.required]) }); - ngOnChanges(changes: SimpleChanges) { + ngOnChanges(changes: SimpleChanges): void { if (changes.criterion && changes.criterion.currentValue) { const criterion = this.criterion as FieldCriterion; diff --git a/client/src/app/instance/search/components/criteria/search-type/select-multiple.component.spec.ts b/client/src/app/instance/search/components/criteria/search-type/select-multiple.component.spec.ts new file mode 100644 index 00000000..b89f4faf --- /dev/null +++ b/client/src/app/instance/search/components/criteria/search-type/select-multiple.component.spec.ts @@ -0,0 +1,88 @@ +import { Component, ViewChild } from '@angular/core'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; + +import { NgSelectModule } from '@ng-select/ng-select'; + +import { SelectMultipleComponent } from './select-multiple.component'; +import { SelectMultipleCriterion } from '../../../../store/models/criterion'; +import { Option } from '../../../../../metamodel/models'; + +describe('[Instance][Search][Component][Criteria][SearchType] SelectMultipleComponent', () => { + @Component({ + selector: `app-host`, + template: ` + <app-select-multiple + [id]="id" + [label]="label" + [options]="options" + [criterion]="criterion"> + </app-select-multiple>` + }) + class TestHostComponent { + @ViewChild(SelectMultipleComponent, { static: false }) + public testedComponent: SelectMultipleComponent; + public id: number = undefined; + public label: string = undefined; + public options: Option[] = undefined; + public criterion: SelectMultipleCriterion = undefined; + } + + let testHostComponent: TestHostComponent; + let testHostFixture: ComponentFixture<TestHostComponent>; + let testedComponent: SelectMultipleComponent; + + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [ + SelectMultipleComponent, + TestHostComponent + ], + imports: [ + NgSelectModule, + 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'); + const options: Option[] = [ + { label: 'One', value: 'one', display: 1 }, + { label: 'Two', value: 'two', display: 2 }, + { label: 'Three', value: 'three', display: 3 } + ]; + testHostComponent.criterion = { id: 1, type: 'multiple', options } as SelectMultipleCriterion; + testHostFixture.detectChanges(); + expect(testedComponent.form.controls.select.value).toEqual(['one', 'two', 'three']); + expect(testedComponent.form.disabled).toBeTruthy(); + testHostComponent.criterion = undefined; + testHostFixture.detectChanges(); + expect(testedComponent.form.controls.select.value).toBeNull(); + expect(testedComponent.form.enabled).toBeTruthy(); + expect(spy).toHaveBeenCalledTimes(2); + }); + + it('raises the add criterion event when clicked', () => { + testedComponent.id = 1; + testedComponent.options = [ + { label: 'One', value: 'one', display: 1 }, + { label: 'Two', value: 'two', display: 2 }, + { label: 'Three', value: 'three', display: 3 } + ]; + testedComponent.form.controls.select.setValue(['three']); + const expectedValue = [{ label: 'Three', value: 'three', display: 3 }]; + const expectedCriterion = { id: testedComponent.id, type: 'multiple', options: expectedValue } as SelectMultipleCriterion; + testedComponent.addCriterion.subscribe((event: SelectMultipleCriterion) => expect(event).toEqual(expectedCriterion)); + testedComponent.emitAdd(); + }); +}); diff --git a/client/src/app/instance/search/components/criteria/search-type/select-multiple.component.ts b/client/src/app/instance/search/components/criteria/search-type/select-multiple.component.ts index 650ac066..630b13a0 100644 --- a/client/src/app/instance/search/components/criteria/search-type/select-multiple.component.ts +++ b/client/src/app/instance/search/components/criteria/search-type/select-multiple.component.ts @@ -13,16 +13,18 @@ import { FormGroup, FormControl, Validators } from '@angular/forms'; import { Criterion, SelectMultipleCriterion } from 'src/app/instance/store/models'; import { Option } from 'src/app/metamodel/models'; +/** + * @class + * @classdesc Select multiple search type component. + * + * @implements OnChanges + */ @Component({ selector: 'app-select-multiple', templateUrl: 'select-multiple.component.html', styleUrls: ['operator.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush }) -/** - * @class - * @classdesc Select multiple search type component. - */ export class SelectMultipleComponent implements OnChanges { @Input() id: number; @Input() label: string; @@ -35,7 +37,7 @@ export class SelectMultipleComponent implements OnChanges { select: new FormControl('', [Validators.required]) }); - ngOnChanges(changes: SimpleChanges) { + ngOnChanges(changes: SimpleChanges): void { if (changes.criterion && changes.criterion.currentValue) { const multipleCriterion = this.criterion as SelectMultipleCriterion; @@ -59,7 +61,7 @@ export class SelectMultipleComponent implements OnChanges { const values = this.form.value.select as string[]; const options = this.options.filter(option => values.includes(option.value)); - const ms = {id: this.id, type: 'multiple', options}; + const ms = { id: this.id, type: 'multiple', options }; this.addCriterion.emit(ms); } } diff --git a/client/src/app/instance/search/components/criteria/search-type/select.component.spec.ts b/client/src/app/instance/search/components/criteria/search-type/select.component.spec.ts new file mode 100644 index 00000000..b4496d00 --- /dev/null +++ b/client/src/app/instance/search/components/criteria/search-type/select.component.spec.ts @@ -0,0 +1,108 @@ +import { Component, Input, ViewChild } from '@angular/core'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; + +import { NgSelectModule } from '@ng-select/ng-select'; +import { TooltipModule } from 'ngx-bootstrap/tooltip'; + +import { SelectComponent } from './select.component'; +import { FieldCriterion } from '../../../../store/models/criterion'; +import { Option } from '../../../../../metamodel/models'; + +describe('[Instance][Search][Component][Criteria][SearchType] SelectComponent', () => { + @Component({ + selector: `app-host`, + template: ` + <app-select + [id]="id" + [label]="label" + [operator]="operator" + [options]="options" + [criterion]="criterion" + [advancedForm]="advancedForm"> + </app-select>` + }) + class TestHostComponent { + @ViewChild(SelectComponent, { static: false }) + public testedComponent: SelectComponent; + public id: number = undefined; + public label: string = undefined; + public operator: string = undefined; + public options: Option[] = 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: SelectComponent; + + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [ + SelectComponent, + TestHostComponent, + OperatorStubComponent, + HelpLikeStubComponent + ], + imports: [ + NgSelectModule, + 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: 'three' } as FieldCriterion; + testHostFixture.detectChanges(); + expect(testedComponent.form.controls.select.value).toEqual('three'); + expect(testedComponent.form.disabled).toBeTruthy(); + testHostComponent.criterion = undefined; + testHostFixture.detectChanges(); + expect(testedComponent.form.controls.select.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; + testedComponent.operator = 'eq'; + testedComponent.form.controls.select.setValue('three'); + testedComponent.options = [ + { label: 'One', value: 'one', display: 1 }, + { label: 'Two', value: 'two', display: 2 }, + { label: 'Three', value: 'three', display: 3 } + ]; + const expectedCriterion = { id: testedComponent.id, type: 'field', operator: 'eq', value: 'three' } as FieldCriterion; + testedComponent.addCriterion.subscribe((event: FieldCriterion) => expect(event).toEqual(expectedCriterion)); + testedComponent.emitAdd(); + }); +}); diff --git a/client/src/app/instance/search/components/criteria/search-type/select.component.ts b/client/src/app/instance/search/components/criteria/search-type/select.component.ts index 26dda32e..489df7ea 100644 --- a/client/src/app/instance/search/components/criteria/search-type/select.component.ts +++ b/client/src/app/instance/search/components/criteria/search-type/select.component.ts @@ -13,15 +13,17 @@ import { FormGroup, FormControl, Validators } from '@angular/forms'; import { Criterion, FieldCriterion } from 'src/app/instance/store/models'; import { Option } from 'src/app/metamodel/models'; +/** + * @class + * @classdesc Select search type component. + * + * @implements OnChanges + */ @Component({ selector: 'app-select', templateUrl: 'select.component.html', changeDetection: ChangeDetectionStrategy.OnPush }) -/** - * @class - * @classdesc Select search type component. - */ export class SelectComponent implements OnChanges { @Input() id: number; @Input() operator: string; @@ -38,7 +40,7 @@ export class SelectComponent implements OnChanges { disabledOperator: boolean; - ngOnChanges(changes: SimpleChanges) { + ngOnChanges(changes: SimpleChanges): void { if (changes.criterion && changes.criterion.currentValue) { this.form.controls.select.setValue(changes.criterion.currentValue.value); this.form.disable(); diff --git a/client/src/app/instance/search/components/criteria/search-type/time.component.spec.ts b/client/src/app/instance/search/components/criteria/search-type/time.component.spec.ts index d5f3df13..4b627ac6 100644 --- a/client/src/app/instance/search/components/criteria/search-type/time.component.spec.ts +++ b/client/src/app/instance/search/components/criteria/search-type/time.component.spec.ts @@ -1,16 +1,34 @@ -import { Component, Input } from '@angular/core'; +import { Component, Input, ViewChild } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; -import { FormsModule, ReactiveFormsModule, FormControl } from '@angular/forms'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; - -import { AccordionModule } from 'ngx-bootstrap/accordion'; +import { NgSelectModule } from '@ng-select/ng-select'; import { TimeComponent } from './time.component'; -import { NgSelectModule } from '@ng-select/ng-select'; import { FieldCriterion } from '../../../../store/models/criterion'; describe('[Instance][Search][Component][Criteria][SearchType] TimeComponent', () => { + @Component({ + selector: `app-host`, + template: ` + <app-time + [id]="id" + [label]="label" + [operator]="operator" + [criterion]="criterion" + [advancedForm]="advancedForm"> + </app-time>` + }) + class TestHostComponent { + @ViewChild(TimeComponent, { static: false }) + public testedComponent: TimeComponent; + public id: number = undefined; + public label: string = undefined; + public operator: string = undefined; + public criterion: FieldCriterion = undefined; + public advancedForm: boolean = false; + } + @Component({ selector: 'app-operator', template: '' }) class OperatorStubComponent { @Input() operator: string; @@ -19,13 +37,15 @@ describe('[Instance][Search][Component][Criteria][SearchType] TimeComponent', () @Input() disabled: boolean; } - let component: TimeComponent; - let fixture: ComponentFixture<TimeComponent>; + let testHostComponent: TestHostComponent; + let testHostFixture: ComponentFixture<TestHostComponent>; + let testedComponent: TimeComponent; beforeEach(() => { TestBed.configureTestingModule({ declarations: [ TimeComponent, + TestHostComponent, OperatorStubComponent ], imports: [ @@ -34,34 +54,51 @@ describe('[Instance][Search][Component][Criteria][SearchType] TimeComponent', () ReactiveFormsModule ] }); - fixture = TestBed.createComponent(TimeComponent); - component = fixture.componentInstance; + testHostFixture = TestBed.createComponent(TestHostComponent); + testHostComponent = testHostFixture.componentInstance; + testHostFixture.detectChanges(); + testedComponent = testHostComponent.testedComponent; }); it('should create the component', () => { - expect(component).toBeTruthy(); + 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: '15:47' } as FieldCriterion; + testHostFixture.detectChanges(); + 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.hh.value).toBeNull(); + expect(testedComponent.form.controls.hh.value).toBeNull(); + expect(testedComponent.form.enabled).toBeTruthy(); + expect(spy).toHaveBeenCalledTimes(2); }); it('#changeOperator() should change the operator', () => { - expect(component.operator).toBeUndefined(); - component.changeOperator('toto'); - expect(component.operator).toBe('toto'); + expect(testedComponent.operator).toBeUndefined(); + testedComponent.changeOperator('toto'); + expect(testedComponent.operator).toBe('toto'); }); it('raises the add criterion event when clicked', () => { - component.id = 1; + testedComponent.id = 1; const operator = 'eq'; - component.operator = operator; - component.form.controls.hh.setValue('15'); - component.form.controls.mm.setValue('47'); - const expectedCriterion = { id: component.id, type: 'field', operator, value: '15:47' } as FieldCriterion; - component.addCriterion.subscribe((event: FieldCriterion) => expect(event).toEqual(expectedCriterion)); - component.emitAdd(); + testedComponent.operator = operator; + testedComponent.form.controls.hh.setValue('15'); + testedComponent.form.controls.mm.setValue('47'); + const expectedCriterion = { id: testedComponent.id, type: 'field', operator, value: '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(component.initTime(n).length).toEqual(n); - expect(component.initTime(n)[5]).toEqual('05'); + expect(testedComponent.initTime(n).length).toEqual(n); + expect(testedComponent.initTime(n)[5]).toEqual('05'); }); }); diff --git a/client/src/app/instance/search/components/criteria/search-type/time.component.ts b/client/src/app/instance/search/components/criteria/search-type/time.component.ts index 9205c7a6..8c4a4e59 100644 --- a/client/src/app/instance/search/components/criteria/search-type/time.component.ts +++ b/client/src/app/instance/search/components/criteria/search-type/time.component.ts @@ -43,7 +43,7 @@ export class TimeComponent implements OnChanges { mm: new FormControl('', [Validators.required]) }); - ngOnChanges(changes: SimpleChanges) { + ngOnChanges(changes: SimpleChanges): void { if (changes.criterion && changes.criterion.currentValue) { const criterion = changes.criterion.currentValue as FieldCriterion; -- GitLab