From 22e1025e85991cdd6fa6cc1a46a8dd6736897858 Mon Sep 17 00:00:00 2001 From: Tifenn Guillas <tifenn.guillas@gmail.com> Date: Tue, 2 Nov 2021 17:46:00 +0100 Subject: [PATCH] WIP: tests on cone search --- .../cone-search/ra.component.spec.ts | 111 ++++++++++++++++++ .../components/cone-search/ra.component.ts | 38 ++++-- .../cone-search/radius.component.spec.ts | 22 ++++ .../cone-search/radius.component.ts | 8 +- .../cone-search/resolver.component.spec.ts | 75 ++++++++++++ .../cone-search/resolver.component.ts | 17 ++- .../datatable/datatable.component.ts | 25 ++-- 7 files changed, 268 insertions(+), 28 deletions(-) create mode 100644 client/src/app/instance/shared-search/components/cone-search/ra.component.spec.ts create mode 100644 client/src/app/instance/shared-search/components/cone-search/radius.component.spec.ts create mode 100644 client/src/app/instance/shared-search/components/cone-search/resolver.component.spec.ts diff --git a/client/src/app/instance/shared-search/components/cone-search/ra.component.spec.ts b/client/src/app/instance/shared-search/components/cone-search/ra.component.spec.ts new file mode 100644 index 00000000..efb1dc3e --- /dev/null +++ b/client/src/app/instance/shared-search/components/cone-search/ra.component.spec.ts @@ -0,0 +1,111 @@ +import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; +import { Component, ViewChild } from '@angular/core'; +import { FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms'; + +import { RaComponent } from './ra.component'; +import { ConeSearch, Resolver } from '../../../store/models'; +import { nanValidator, rangeValidator } from '../../validators'; +import { of } from 'rxjs'; + +describe('[Instance][SharedSearch][Components][ConeSearch] RaComponent', () => { + let form = new FormGroup({ + ra: new FormControl('', [Validators.required, nanValidator, rangeValidator(0, 360, 'RA')]), + ra_hms: new FormGroup({ + h: new FormControl('', [Validators.required, nanValidator, rangeValidator(0, 24, 'Hours')]), + m: new FormControl('', [Validators.required, nanValidator, rangeValidator(0, 60, 'Minutes')]), + s: new FormControl('', [Validators.required, nanValidator, rangeValidator(0, 60, 'Seconds')]) + }) + }); + @Component({ + selector: `app-host`, + template: ` + <app-ra + [form]="form" + [unit]="unit" + [resolver]="resolver"> + </app-ra>` + }) + class TestHostComponent { + @ViewChild(RaComponent, { static: false }) + public testedComponent: RaComponent; + public form: FormGroup = form; + public unit: string = 'degree'; + public resolver: Resolver = undefined; + } + + let testHostComponent: TestHostComponent; + let testHostFixture: ComponentFixture<TestHostComponent>; + let testedComponent: RaComponent; + + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [ + TestHostComponent, + RaComponent + ], + imports: [ReactiveFormsModule] + }); + testHostFixture = TestBed.createComponent(TestHostComponent); + testHostComponent = testHostFixture.componentInstance; + testHostFixture.detectChanges(); + testedComponent = testHostComponent.testedComponent; + }); + + it('should create the component', () => { + expect(testedComponent).toBeTruthy(); + }); + + it('#ngOnInit() should disable ra_hms control and convert degrees to HMS', () => { + expect(testedComponent.form.controls.ra_hms.disabled).toBeTruthy(); + }); + + it('should call ngOnChanges and apply changes', () => { + testedComponent.raControlSubscription = of().subscribe(); + testedComponent.raHmsFormSubscription = of().subscribe(); + const spyRa = jest.spyOn(testedComponent.raControlSubscription, 'unsubscribe'); + const spyRaHms = jest.spyOn(testedComponent.raHmsFormSubscription, 'unsubscribe'); + const spy = jest.spyOn(testedComponent, 'ngOnChanges'); + testHostComponent.unit = 'degree'; + testHostFixture.detectChanges(); + // expect(spy).toHaveBeenCalledTimes(1); + expect(testedComponent.form.controls.ra_hms.disabled).toBeTruthy(); + expect(testedComponent.form.controls.ra.enabled).toBeTruthy(); + // expect(spyRaHms).toHaveBeenCalledTimes(1); + testHostComponent.unit = 'hms'; + testHostFixture.detectChanges(); + // expect(spy).toHaveBeenCalledTimes(2); + expect(testedComponent.form.controls.ra_hms.enabled).toBeTruthy(); + expect(testedComponent.form.controls.ra.disabled).toBeTruthy(); + // expect(spyRa).toHaveBeenCalledTimes(1); + }); + + it('#getRaHmsForm() should return RA HMS form control', () => { + const form: FormGroup = testedComponent.getRaHmsForm(); + expect(Object.keys(form.controls).length).toEqual(3); + expect(Object.keys(form.controls)).toContain('h'); + expect(Object.keys(form.controls)).toContain('m'); + expect(Object.keys(form.controls)).toContain('s'); + }); + + it('#deg2HMS(value) convert RA from degree to HH:MM:SS', () => { + testedComponent.deg2HMS(78.2); + expect(testedComponent.getRaHmsForm().controls.h.value).toBe(5); + expect(testedComponent.getRaHmsForm().controls.m.value).toBe(12); + expect(parseFloat(testedComponent.getRaHmsForm().controls.s.value)).toBe(48); + }); + + it('#HMS2Deg(hms) convert RA from HH:MM:SS to degree', () => { + testedComponent.HMS2Deg({ h: 5, m: 12, s: 48 }); + expect(testedComponent.form.controls.ra.value).toBe(78.2); + }); + + it('#ngOnDestroy() should unsubscribe from raControlSubscription and raHmsFormSubscription', () => { + testedComponent.raControlSubscription = of().subscribe(); + testedComponent.raHmsFormSubscription = of().subscribe(); + const spyRa = jest.spyOn(testedComponent.raControlSubscription, 'unsubscribe'); + const spyRaHms = jest.spyOn(testedComponent.raHmsFormSubscription, 'unsubscribe'); + testedComponent.ngOnDestroy(); + expect(spyRa).toHaveBeenCalledTimes(1); + expect(spyRaHms).toHaveBeenCalledTimes(1); + }); +}); diff --git a/client/src/app/instance/shared-search/components/cone-search/ra.component.ts b/client/src/app/instance/shared-search/components/cone-search/ra.component.ts index aab36bf7..7a7a6365 100644 --- a/client/src/app/instance/shared-search/components/cone-search/ra.component.ts +++ b/client/src/app/instance/shared-search/components/cone-search/ra.component.ts @@ -15,16 +15,20 @@ import { debounceTime } from 'rxjs/operators'; import { Resolver } from 'src/app/instance/store/models'; +/** + * @class + * @classdesc RA component. + * + * @implements OnInit + * @implements OnChanges + * @implements OnDestroy + */ @Component({ selector: 'app-ra', templateUrl: 'ra.component.html', styleUrls: ['input-group.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush }) -/** - * @class - * @classdesc RA component. - */ export class RaComponent implements OnInit, OnDestroy, OnChanges { @Input() form: FormGroup; @Input() unit: string; @@ -33,7 +37,7 @@ export class RaComponent implements OnInit, OnDestroy, OnChanges { public raControlSubscription: Subscription; public raHmsFormSubscription: Subscription; - ngOnInit() { + ngOnInit(): void { this.form.controls.ra_hms.disable(); this.raControlSubscription = this.form.controls.ra.valueChanges.pipe(debounceTime(250)) .subscribe(deg => this.deg2HMS(deg)); @@ -62,11 +66,20 @@ export class RaComponent implements OnInit, OnDestroy, OnChanges { } } - getRaHmsForm() { - const raHmsForm = this.form.controls.ra_hms as FormGroup; - return raHmsForm; + /** + * Returns RA form group. + * + * @return FormGroup + */ + getRaHmsForm(): FormGroup { + return this.form.controls.ra_hms as FormGroup; } + /** + * Converts RA hour minute second from degree and sets RA HMS fields. + * + * @param {number} deg - The degree value. + */ deg2HMS(deg: number): void { let tmp = deg / 15; const hh = Math.trunc(tmp); @@ -80,12 +93,17 @@ export class RaComponent implements OnInit, OnDestroy, OnChanges { raHmsForm.controls.s.setValue(ss); } - HMS2Deg(hms: {h: number, m: number, s: number }): void { + /** + * Sets RA degree from hour minute second and sets RA degree field. + * + * @param {h: number, m: number, s: number} hms - Coordinates in HMS. + */ + HMS2Deg(hms: { h: number, m: number, s: number }): void { const deg = +(((((hms.s / 60) + hms.m) / 60) + hms.h) * 15).toFixed(8); this.form.controls.ra.setValue(deg); } - ngOnDestroy() { + ngOnDestroy(): void { if (this.raControlSubscription) this.raControlSubscription.unsubscribe(); if (this.raHmsFormSubscription) this.raHmsFormSubscription.unsubscribe(); } diff --git a/client/src/app/instance/shared-search/components/cone-search/radius.component.spec.ts b/client/src/app/instance/shared-search/components/cone-search/radius.component.spec.ts new file mode 100644 index 00000000..1af9f997 --- /dev/null +++ b/client/src/app/instance/shared-search/components/cone-search/radius.component.spec.ts @@ -0,0 +1,22 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ReactiveFormsModule } from '@angular/forms'; + +import { RadiusComponent } from './radius.component'; + +describe('[Instance][SharedSearch][Components][ConeSearch] RadiusComponent', () => { + let component: RadiusComponent; + let fixture: ComponentFixture<RadiusComponent>; + + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [RadiusComponent], + imports: [ReactiveFormsModule] + }); + fixture = TestBed.createComponent(RadiusComponent); + component = fixture.componentInstance; + }); + + it('should create the component', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/client/src/app/instance/shared-search/components/cone-search/radius.component.ts b/client/src/app/instance/shared-search/components/cone-search/radius.component.ts index fde6ceb2..21114acb 100644 --- a/client/src/app/instance/shared-search/components/cone-search/radius.component.ts +++ b/client/src/app/instance/shared-search/components/cone-search/radius.component.ts @@ -10,16 +10,16 @@ import { Component, Input, ChangeDetectionStrategy } from '@angular/core'; import { FormGroup } from '@angular/forms'; +/** + * @class + * @classdesc Radius component. + */ @Component({ selector: 'app-radius', templateUrl: 'radius.component.html', styleUrls: ['radius.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush }) -/** - * @class - * @classdesc Radius component. - */ export class RadiusComponent { @Input() form: FormGroup; } diff --git a/client/src/app/instance/shared-search/components/cone-search/resolver.component.spec.ts b/client/src/app/instance/shared-search/components/cone-search/resolver.component.spec.ts new file mode 100644 index 00000000..8c62843f --- /dev/null +++ b/client/src/app/instance/shared-search/components/cone-search/resolver.component.spec.ts @@ -0,0 +1,75 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { Component, ViewChild } from '@angular/core'; +import { ReactiveFormsModule } from '@angular/forms'; + +import { ResolverComponent } from './resolver.component'; +import { ConeSearch, Resolver } from '../../../store/models'; + +describe('[Instance][SharedSearch][Components][ConeSearch] ResolverComponent', () => { + @Component({ + selector: `app-host`, + template: ` + <app-resolver + [coneSearch]="coneSearch" + [resolver]="resolver" + [resolverIsLoading]="resolverIsLoading" + [resolverIsLoaded]="resolverIsLoaded"> + </app-resolver>` + }) + class TestHostComponent { + @ViewChild(ResolverComponent, { static: false }) + public testedComponent: ResolverComponent; + public coneSearch: ConeSearch = undefined; + public resolver: Resolver = undefined; + public resolverIsLoading: boolean = false; + public resolverIsLoaded: boolean = false; + } + + let testHostComponent: TestHostComponent; + let testHostFixture: ComponentFixture<TestHostComponent>; + let testedComponent: ResolverComponent; + + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [ + TestHostComponent, + ResolverComponent + ], + imports: [ReactiveFormsModule] + }); + testHostFixture = TestBed.createComponent(TestHostComponent); + testHostComponent = testHostFixture.componentInstance; + testHostFixture.detectChanges(); + testedComponent = testHostComponent.testedComponent; + }); + + it('should create the component', () => { + expect(testedComponent).toBeTruthy(); + }); + + it('#ngOnInit() should disable form if cone search already defined', () => { + expect(testedComponent.form.enabled).toBeTruthy(); + testedComponent.coneSearch = { ra: 1, dec: 2, radius: 3 }; + testedComponent.ngOnInit(); + expect(testedComponent.form.disabled).toBeTruthy(); + }); + + it('should call ngOnChanges and apply changes', () => { + const spy = jest.spyOn(testedComponent, 'ngOnChanges'); + testHostComponent.coneSearch = null; + testHostFixture.detectChanges(); + expect(testedComponent.form.enabled).toBeTruthy(); + testHostComponent.coneSearch = { ra: 1, dec: 2, radius: 3 }; + testHostFixture.detectChanges(); + expect(testedComponent.form.disabled).toBeTruthy(); + expect(spy).toHaveBeenCalledTimes(2); + }); + + it('#submit() should raise retrieveCoordinates event', () => { + testedComponent.form.controls.name.setValue('myObjectName'); + const spy = jest.spyOn(testedComponent.retrieveCoordinates, 'emit'); + testedComponent.submit(); + expect(spy).toHaveBeenCalledTimes(1); + expect(spy).toHaveBeenCalledWith('myObjectName'); + }); +}); diff --git a/client/src/app/instance/shared-search/components/cone-search/resolver.component.ts b/client/src/app/instance/shared-search/components/cone-search/resolver.component.ts index 18c09444..2d2434f4 100644 --- a/client/src/app/instance/shared-search/components/cone-search/resolver.component.ts +++ b/client/src/app/instance/shared-search/components/cone-search/resolver.component.ts @@ -12,15 +12,15 @@ import { FormGroup, FormControl, Validators } from '@angular/forms'; import { ConeSearch, Resolver } from 'src/app/instance/store/models'; +/** + * @class + * @classdesc Resolver component. + */ @Component({ selector: 'app-resolver', templateUrl: 'resolver.component.html', changeDetection: ChangeDetectionStrategy.OnPush }) -/** - * @class - * @classdesc Resolver component. - */ export class ResolverComponent implements OnInit, OnChanges { @Input() coneSearch: ConeSearch; @Input() resolver: Resolver; @@ -32,7 +32,7 @@ export class ResolverComponent implements OnInit, OnChanges { name: new FormControl('', [Validators.required]) }); - ngOnInit() { + ngOnInit(): void { if (this.coneSearch) { this.form.disable(); } @@ -48,7 +48,12 @@ export class ResolverComponent implements OnInit, OnChanges { } } - submit() { + /** + * Emits event to retrieve coordinates. + * + * @fires EventEmitter<string> + */ + submit(): void { this.retrieveCoordinates.emit(this.form.controls.name.value); } } diff --git a/client/src/app/instance/shared-search/components/datatable/datatable.component.ts b/client/src/app/instance/shared-search/components/datatable/datatable.component.ts index b9887163..afd7d5e9 100644 --- a/client/src/app/instance/shared-search/components/datatable/datatable.component.ts +++ b/client/src/app/instance/shared-search/components/datatable/datatable.component.ts @@ -67,25 +67,34 @@ export class DatatableComponent implements OnInit { * * @param {Attribute} attribute - The attribute. * - * @return DetailRendererConfig | LinkRendererConfig | DownloadRendererConfig | ImageRendererConfig | RendererConfig | null */ - getRendererConfig(attribute: Attribute): DetailRendererConfig | LinkRendererConfig | DownloadRendererConfig | ImageRendererConfig | RendererConfig | null { + // getRendererConfig(attribute: Attribute): DetailRendererConfig | LinkRendererConfig | DownloadRendererConfig | ImageRendererConfig | RendererConfig | null { + getRendererConfig(attribute: Attribute) { + let config = null; switch(attribute.renderer) { case 'detail': - return attribute.renderer_config as DetailRendererConfig; + config = attribute.renderer_config as DetailRendererConfig; + break; case 'link': - return attribute.renderer_config as LinkRendererConfig; + config = attribute.renderer_config as LinkRendererConfig; + break; case 'download': - return attribute.renderer_config as DownloadRendererConfig; + config = attribute.renderer_config as DownloadRendererConfig; + break; case 'image': - return attribute.renderer_config as ImageRendererConfig; + config = attribute.renderer_config as ImageRendererConfig; + break; case 'json': - return attribute.renderer_config as RendererConfig; + config = attribute.renderer_config as RendererConfig; + break; default: - return null; + config = null; } + return config; + } + /** * Returns output list from attribute list. * -- GitLab