From 51816c4b197a766a7a8a0021eaeb81573924276d Mon Sep 17 00:00:00 2001 From: Tifenn Guillas <tifenn.guillas@gmail.com> Date: Thu, 5 Aug 2021 15:56:14 +0200 Subject: [PATCH] WIP: Tests on detail effects --- .../store/effects/cone-search.effects.spec.ts | 4 +- .../store/effects/detail.effects.spec.ts | 188 ++++++++++++++++++ .../instance/store/effects/detail.effects.ts | 23 ++- .../instance/store/services/detail.service.ts | 1 + 4 files changed, 211 insertions(+), 5 deletions(-) create mode 100644 client/src/app/instance/store/effects/detail.effects.spec.ts diff --git a/client/src/app/instance/store/effects/cone-search.effects.spec.ts b/client/src/app/instance/store/effects/cone-search.effects.spec.ts index 3befaed4..172bacf7 100644 --- a/client/src/app/instance/store/effects/cone-search.effects.spec.ts +++ b/client/src/app/instance/store/effects/cone-search.effects.spec.ts @@ -37,7 +37,7 @@ describe('ConeSearchEffects', () => { expect(effects).toBeTruthy(); }); - describe('retrieveCoordinates effect', () => { + describe('retrieveCoordinates$ effect', () => { it('should dispatch the retrieveCoordinatesSuccess action on success', () => { const name: string = 'myObjectName'; const apiResponse = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + @@ -107,7 +107,7 @@ describe('ConeSearchEffects', () => { }); }); - describe('retrieveCoordinatesFail effect', () => { + describe('retrieveCoordinatesFail$ effect', () => { it('should not dispatch', () => { expect(metadata.retrieveCoordinatesFail$).toEqual( expect.objectContaining({ dispatch: false }) diff --git a/client/src/app/instance/store/effects/detail.effects.spec.ts b/client/src/app/instance/store/effects/detail.effects.spec.ts new file mode 100644 index 00000000..ec713df9 --- /dev/null +++ b/client/src/app/instance/store/effects/detail.effects.spec.ts @@ -0,0 +1,188 @@ +import { TestBed } from '@angular/core/testing'; + +import { provideMockActions } from '@ngrx/effects/testing'; +import { EffectsMetadata, getEffectsMetadata } from '@ngrx/effects'; +import { Observable } from 'rxjs'; +import { cold, hot } from 'jasmine-marbles'; +import { ToastrService } from 'ngx-toastr'; + +import { DetailEffects } from './detail.effects'; +import { DetailService } from '../services/detail.service'; +import * as detailActions from '../actions/detail.actions'; +import { Resolver } from '../models'; +import { MockStore, provideMockStore } from '@ngrx/store/testing'; +import * as detailSelector from '../selectors/detail.selector'; +import * as attributeSelector from 'src/app/metamodel/selectors/attribute.selector'; +import * as datasetSelector from 'src/app/metamodel/selectors/dataset.selector'; +import * as fromDetail from '../reducers/detail.reducer'; + +describe('DetailEffects', () => { + let actions = new Observable(); + let effects: DetailEffects; + let metadata: EffectsMetadata<DetailEffects>; + let coneSearchService: DetailService; + let store: MockStore; + let toastr: ToastrService; + const initialState = { detail: { ...fromDetail.initialState } }; + + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [ + DetailEffects, + { provide: DetailService, useValue: { retrieveCoordinates: jest.fn() }}, + { provide: ToastrService, useValue: { error: jest.fn() } }, + provideMockActions(() => actions), + provideMockStore({ initialState }), + ] + }).compileComponents(); + effects = TestBed.inject(DetailEffects); + metadata = getEffectsMetadata(effects); + coneSearchService = TestBed.inject(DetailService); + store = TestBed.inject(MockStore); + toastr = TestBed.inject(ToastrService); + }); + + it('should be created', () => { + expect(effects).toBeTruthy(); + }); + + describe('retrieveObject$ effect', () => { + // it('should dispatch the retrieveObjectSuccess action on success', () => { + // const name: string = 'myObjectName'; + // const apiResponse = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + + // "<Sesame xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" + + // " xsi:noNamespaceSchemaLocation=\"http://vizier.u-strasbg.fr/xml/sesame_4x.xsd\">\n" + + // "<Target option=\"NSV\">\n" + + // " <name>myObjectName</name>\n" + + // " <!-- Q1525761 #1 -->\n" + + // " <Resolver name=\"N=NED\"><!--delay: 989ms [2] -->\n" + + // " <otype>!*</otype>\n" + + // " <jpos>06:45:09.24 -16:42:47.3</jpos>\n" + + // " <jradeg>1</jradeg>\n" + + // " <jdedeg>2</jdedeg>\n" + + // " <refPos>2007A&A...474..653V</refPos>\n" + + // " <errRAmas>50</errRAmas><errDEmas>500</errDEmas>\n" + + // " <oname>Sirius</oname>\n" + + // " </Resolver>\n" + + // "</Target>\n" + + // "</Sesame>\n" + + // "<!--- ====Done (2021-Aug-04,15:00:56z)==== -->\n"; + // const resolver: Resolver = { name: 'myObjectName', ra: 1, dec: 2 }; + // const action = coneSearchActions.retrieveCoordinates({ name }); + // const outcome = coneSearchActions.retrieveCoordinatesSuccess({ resolver }); + // + // actions = hot('-a', { a: action }); + // const response = cold('-a|', { a: apiResponse }); + // const expected = cold('--b', { b: outcome }); + // coneSearchService.retrieveCoordinates = jest.fn(() => response); + // + // expect(effects.retrieveCoordinates$).toBeObservable(expected); + // console.log(store.select()) + // expect(false).toBeTruthy(); + // }); + + // it('should dispatch the retrieveObjectFail action on failure', () => { + // const name: string = 'myObjectName'; + // const action = coneSearchActions.retrieveCoordinates({ name }); + // const error = new Error(); + // const outcome = coneSearchActions.retrieveCoordinatesFail(); + // + // actions = hot('-a', { a: action }); + // const response = cold('-#|', {}, error); + // const expected = cold('--b', { b: outcome }); + // coneSearchService.retrieveCoordinates = jest.fn(() => response); + // + // expect(effects.retrieveCoordinates$).toBeObservable(expected); + // }); + }); + + describe('retrieveObjectFail$ effect', () => { + it('should not dispatch', () => { + expect(metadata.retrieveObjectFail$).toEqual( + expect.objectContaining({ dispatch: false }) + ); + }); + + it('should display an error notification', () => { + const spy = jest.spyOn(toastr, 'error'); + const action = detailActions.retrieveObjectFail(); + + actions = hot('a', { a: action }); + const expected = cold('a', { a: action }); + + expect(effects.retrieveObjectFail$).toBeObservable(expected); + expect(spy).toHaveBeenCalledTimes(1); + expect(spy).toHaveBeenCalledWith('Loading Failed!', 'Unable to load the object'); + }); + }); + + describe('retrieveSpectra$ effect', () => { + // it('should dispatch the retrieveSpectraSuccess action on success', () => { + // const name: string = 'myObjectName'; + // const apiResponse = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + + // "<Sesame xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" + + // " xsi:noNamespaceSchemaLocation=\"http://vizier.u-strasbg.fr/xml/sesame_4x.xsd\">\n" + + // "<Target option=\"NSV\">\n" + + // " <name>myObjectName</name>\n" + + // " <!-- Q1525761 #1 -->\n" + + // " <Resolver name=\"N=NED\"><!--delay: 989ms [2] -->\n" + + // " <otype>!*</otype>\n" + + // " <jpos>06:45:09.24 -16:42:47.3</jpos>\n" + + // " <jradeg>1</jradeg>\n" + + // " <jdedeg>2</jdedeg>\n" + + // " <refPos>2007A&A...474..653V</refPos>\n" + + // " <errRAmas>50</errRAmas><errDEmas>500</errDEmas>\n" + + // " <oname>Sirius</oname>\n" + + // " </Resolver>\n" + + // "</Target>\n" + + // "</Sesame>\n" + + // "<!--- ====Done (2021-Aug-04,15:00:56z)==== -->\n"; + // const resolver: Resolver = { name: 'myObjectName', ra: 1, dec: 2 }; + // const action = coneSearchActions.retrieveCoordinates({ name }); + // const outcome = coneSearchActions.retrieveCoordinatesSuccess({ resolver }); + // + // actions = hot('-a', { a: action }); + // const response = cold('-a|', { a: apiResponse }); + // const expected = cold('--b', { b: outcome }); + // coneSearchService.retrieveCoordinates = jest.fn(() => response); + // + // expect(effects.retrieveCoordinates$).toBeObservable(expected); + // console.log(store.select()) + // expect(false).toBeTruthy(); + // }); + + // it('should dispatch the retrieveSpectraFail action on failure', () => { + // const name: string = 'myObjectName'; + // const action = coneSearchActions.retrieveCoordinates({ name }); + // const error = new Error(); + // const outcome = coneSearchActions.retrieveCoordinatesFail(); + // + // actions = hot('-a', { a: action }); + // const response = cold('-#|', {}, error); + // const expected = cold('--b', { b: outcome }); + // coneSearchService.retrieveCoordinates = jest.fn(() => response); + // + // expect(effects.retrieveCoordinates$).toBeObservable(expected); + // }); + }); + + describe('retrieveSpectraFail$ effect', () => { + it('should not dispatch', () => { + expect(metadata.retrieveSpectraFail$).toEqual( + expect.objectContaining({ dispatch: false }) + ); + }); + + it('should display an error notification', () => { + const spy = jest.spyOn(toastr, 'error'); + const action = detailActions.retrieveSpectraFail(); + + actions = hot('a', { a: action }); + const expected = cold('a', { a: action }); + + expect(effects.retrieveSpectraFail$).toBeObservable(expected); + expect(spy).toHaveBeenCalledTimes(1); + expect(spy).toHaveBeenCalledWith('Loading Failed!', 'Unable to load spectra'); + }); + }); +}); diff --git a/client/src/app/instance/store/effects/detail.effects.ts b/client/src/app/instance/store/effects/detail.effects.ts index 256412ae..2a18c7ff 100644 --- a/client/src/app/instance/store/effects/detail.effects.ts +++ b/client/src/app/instance/store/effects/detail.effects.ts @@ -20,10 +20,18 @@ import * as detailActions from '../actions/detail.actions'; import * as detailSelector from '../selectors/detail.selector'; import * as attributeSelector from 'src/app/metamodel/selectors/attribute.selector'; import * as datasetSelector from 'src/app/metamodel/selectors/dataset.selector'; - + +/** + * @class + * @classdesc Detail effects. + */ @Injectable() export class DetailEffects { - retrieveObject$ = createEffect(() => + + /** + * Calls actions to retrieve object. + */ + retrieveObject$ = createEffect((): any => this.actions$.pipe( ofType(detailActions.retrieveObject), concatLatestFrom(() => [ @@ -43,6 +51,9 @@ export class DetailEffects { ) ); + /** + * Displays retrieve object error notification. + */ retrieveObjectFail$ = createEffect(() => this.actions$.pipe( ofType(detailActions.retrieveObjectFail), @@ -50,7 +61,10 @@ export class DetailEffects { ), { dispatch: false} ); - retrieveSpectra$ = createEffect(() => + /** + * Calls actions to retrieve spectra. + */ + retrieveSpectra$ = createEffect((): any => this.actions$.pipe( ofType(detailActions.retrieveSpectra), concatLatestFrom(() => this.store.select(datasetSelector.selectDatasetNameByRoute)), @@ -64,6 +78,9 @@ export class DetailEffects { ) ); + /** + * Displays retrieve spectra error notification. + */ retrieveSpectraFail$ = createEffect(() => this.actions$.pipe( ofType(detailActions.retrieveSpectraFail), diff --git a/client/src/app/instance/store/services/detail.service.ts b/client/src/app/instance/store/services/detail.service.ts index 3b946c5b..978c046a 100644 --- a/client/src/app/instance/store/services/detail.service.ts +++ b/client/src/app/instance/store/services/detail.service.ts @@ -33,6 +33,7 @@ export class DetailService { * @return Observable<any[]> */ retrieveObject(dname: string, criterionId: number, objectSelected: string, outputList: number[]): Observable<any[]> { + console.log(dname, criterionId, objectSelected, outputList); const query = dname + '?c=' + criterionId + '::eq::' + objectSelected + '&a=' + outputList.join(';'); return this.http.get<any[]>(this.config.apiUrl + '/search/' + query); } -- GitLab