From f0839c6d8d79c6ca6618b87782e29bea8646abc0 Mon Sep 17 00:00:00 2001
From: Tifenn Guillas <tifenn.guillas@lam.fr>
Date: Mon, 20 Sep 2021 16:01:46 +0200
Subject: [PATCH] WIP: Test on search multiple effects

---
 .../effects/search-multiple.effects.spec.ts   | 715 ++++++++++++++++++
 .../store/effects/search-multiple.effects.ts  |  23 +-
 2 files changed, 733 insertions(+), 5 deletions(-)
 create mode 100644 client/src/app/instance/store/effects/search-multiple.effects.spec.ts

diff --git a/client/src/app/instance/store/effects/search-multiple.effects.spec.ts b/client/src/app/instance/store/effects/search-multiple.effects.spec.ts
new file mode 100644
index 00000000..f09533cf
--- /dev/null
+++ b/client/src/app/instance/store/effects/search-multiple.effects.spec.ts
@@ -0,0 +1,715 @@
+import { TestBed } from '@angular/core/testing';
+
+import { provideMockActions } from '@ngrx/effects/testing';
+import { EffectsMetadata, getEffectsMetadata } from '@ngrx/effects';
+import { MockStore, provideMockStore } from '@ngrx/store/testing';
+import { Observable } from 'rxjs';
+import { cold, hot } from 'jasmine-marbles';
+import { ToastrService } from 'ngx-toastr';
+
+import { SearchMultipleEffects } from './search-multiple.effects';
+import { SearchService } from '../services/search.service';
+import * as searchActions from '../actions/search.actions';
+import * as fromSearch from '../reducers/search.reducer';
+import * as datasetSelector from '../../../metamodel/selectors/dataset.selector';
+import * as searchSelector from '../selectors/search.selector';
+import * as attributeActions from '../../../metamodel/actions/attribute.actions';
+import * as criteriaFamilyActions from '../../../metamodel/actions/criteria-family.actions';
+import * as outputFamilyActions from '../../../metamodel/actions/output-family.actions';
+import * as outputCategoryActions from '../../../metamodel/actions/output-category.actions';
+import * as attributeSelector from '../../../metamodel/selectors/attribute.selector';
+import * as coneSearchSelector from '../selectors/cone-search.selector';
+import * as coneSearchActions from '../actions/cone-search.actions';
+import { Criterion, PaginationOrder } from '../models';
+import * as searchMultipleSelector from '../selectors/search-multiple.selector';
+import * as instanceSelector from '../../../metamodel/selectors/instance.selector';
+import * as searchMultipleActions from '../actions/search-multiple.actions';
+
+describe('SearchMultipleEffects', () => {
+    let actions = new Observable();
+    let effects: SearchMultipleEffects;
+    let metadata: EffectsMetadata<SearchMultipleEffects>;
+    let searchService: SearchService;
+    let toastr: ToastrService;
+    let store: MockStore;
+    const initialState = { search: { ...fromSearch.initialState } };
+    let mockSearchMultipleSelectorSelectPristine;
+    let mockSearchMultipleSelectorSelectSelectedDatasetsByRoute;
+    let mockConeSearchSelectorSelectConeSearchByRoute;
+    let mockInstanceSelectorSelectorSelectInstanceByRouteName;
+    let mockDatasetSelectorSelectAllConeSearchDatasets;
+
+    beforeEach(() => {
+        TestBed.configureTestingModule({
+            providers: [
+                SearchMultipleEffects,
+                { provide: SearchService, useValue: {
+                        // retrieveData: jest.fn(),
+                        retrieveDataLength: jest.fn()
+                    }},
+                { provide: ToastrService, useValue: { error: jest.fn() }},
+                provideMockActions(() => actions),
+                provideMockStore({ initialState }),
+            ]
+        }).compileComponents();
+        effects = TestBed.inject(SearchMultipleEffects);
+        metadata = getEffectsMetadata(effects);
+        searchService = TestBed.inject(SearchService);
+        toastr = TestBed.inject(ToastrService);
+        store = TestBed.inject(MockStore);
+        mockSearchMultipleSelectorSelectPristine = store.overrideSelector(
+            searchMultipleSelector.selectPristine,true
+        );
+        mockSearchMultipleSelectorSelectSelectedDatasetsByRoute = store.overrideSelector(
+            searchMultipleSelector.selectSelectedDatasetsByRoute,''
+        );
+        mockConeSearchSelectorSelectConeSearchByRoute = store.overrideSelector(
+            coneSearchSelector.selectConeSearchByRoute,''
+        );
+        mockInstanceSelectorSelectorSelectInstanceByRouteName = store.overrideSelector(
+            instanceSelector.selectInstanceByRouteName,{
+                name: 'myInstance',
+                label: 'My Instance',
+                data_path: 'data/path',
+                config: {
+                    design: {
+                        design_color: 'green',
+                        design_background_color: 'darker green',
+                        design_logo: 'path/to/logo',
+                        design_favicon: 'path/to/favicon'
+                    },
+                    home: {
+                        home_component: 'HomeComponent',
+                        home_config: {
+                            home_component_text: 'Description',
+                            home_component_logo: 'path/to/logo'
+                        }
+                    },
+                    search: {
+                        search_by_criteria_allowed: true,
+                        search_by_criteria_label: 'Search',
+                        search_multiple_allowed: true,
+                        search_multiple_label: 'Search multiple',
+                        search_multiple_all_datasets_selected: true
+                    },
+                    documentation: {
+                        documentation_allowed: true,
+                        documentation_label: 'Documentation'
+                    }
+                },
+                nb_dataset_families: 1,
+                nb_datasets: 2
+            }
+        );
+        mockDatasetSelectorSelectAllConeSearchDatasets = store.overrideSelector(
+            searchSelector.selectOutputListByRoute,''
+        );
+    });
+
+    it('should be created', () => {
+        expect(effects).toBeTruthy();
+    });
+
+    describe('initSearch$ effect', () => {
+        it('should dispatch the restartSearch action when dataset or cone search changed', () => {
+            mockSearchMultipleSelectorSelectPristine = store.overrideSelector(
+                searchMultipleSelector.selectPristine,true
+            );
+            mockSearchMultipleSelectorSelectSelectedDatasetsByRoute = store.overrideSelector(
+                searchMultipleSelector.selectSelectedDatasetsByRoute,''
+            );
+            mockConeSearchSelectorSelectConeSearchByRoute = store.overrideSelector(
+                coneSearchSelector.selectConeSearchByRoute,''
+            );
+            mockInstanceSelectorSelectorSelectInstanceByRouteName = store.overrideSelector(
+                instanceSelector.selectInstanceByRouteName,{
+                    name: 'myInstance',
+                    label: 'My Instance',
+                    data_path: 'data/path',
+                    config: {
+                        design: {
+                            design_color: 'green',
+                            design_background_color: 'darker green',
+                            design_logo: 'path/to/logo',
+                            design_favicon: 'path/to/favicon'
+                        },
+                        home: {
+                            home_component: 'HomeComponent',
+                            home_config: {
+                                home_component_text: 'Description',
+                                home_component_logo: 'path/to/logo'
+                            }
+                        },
+                        search: {
+                            search_by_criteria_allowed: true,
+                            search_by_criteria_label: 'Search',
+                            search_multiple_allowed: true,
+                            search_multiple_label: 'Search multiple',
+                            search_multiple_all_datasets_selected: true
+                        },
+                        documentation: {
+                            documentation_allowed: true,
+                            documentation_label: 'Documentation'
+                        }
+                    },
+                    nb_dataset_families: 1,
+                    nb_datasets: 2
+                }
+            );
+            mockDatasetSelectorSelectAllConeSearchDatasets = store.overrideSelector(
+                searchSelector.selectOutputListByRoute,''
+            );
+
+            const action = searchMultipleActions.initSearch();
+            actions = hot('-a', { a: action });
+            const expected = cold('-(bc)', {
+                b: coneSearchActions.deleteConeSearch(),
+                c: searchMultipleActions.restartSearch()
+            });
+
+            expect(effects.initSearch$).toBeObservable(expected);
+        });
+
+    //     it('should dispatch a bunch of actions when a dataset is selected or a page is reloaded', () => {
+    //         mockDatasetSelectorSelectDatasetNameByRoute = store.overrideSelector(
+    //             datasetSelector.selectDatasetNameByRoute, 'myDatasetName'
+    //         );
+    //         mockSearchSelectorSelectPristine = store.overrideSelector(
+    //             searchSelector.selectPristine,true
+    //         );
+    //         mockSearchSelectorSelectCurrentDataset = store.overrideSelector(
+    //             searchSelector.selectCurrentDataset,'myDatasetName'
+    //         );
+    //
+    //         const action = searchActions.initSearch();
+    //         actions = hot('-a', { a: action });
+    //         const expected = cold('-(bcdef)', {
+    //             b: searchActions.changeCurrentDataset({ currentDataset: 'myDatasetName' }),
+    //             c: attributeActions.loadAttributeList(),
+    //             d: criteriaFamilyActions.loadCriteriaFamilyList(),
+    //             e: outputFamilyActions.loadOutputFamilyList(),
+    //             f: outputCategoryActions.loadOutputCategoryList()
+    //         });
+    //
+    //         expect(effects.initSearch$).toBeObservable(expected);
+    //     });
+    //
+    //     it('should dispatch a bunch of actions when a dataset is selected or a page is reloaded with steps checked', () => {
+    //         mockDatasetSelectorSelectDatasetNameByRoute = store.overrideSelector(
+    //             datasetSelector.selectDatasetNameByRoute, 'myDatasetName'
+    //         );
+    //         mockSearchSelectorSelectPristine = store.overrideSelector(
+    //             searchSelector.selectPristine,true
+    //         );
+    //         mockSearchSelectorSelectCurrentDataset = store.overrideSelector(
+    //             searchSelector.selectCurrentDataset,'myDatasetName'
+    //         );
+    //         mockSearchSelectorSelectStepsByRoute = store.overrideSelector(
+    //             searchSelector.selectStepsByRoute, '111'
+    //         );
+    //
+    //         const action = searchActions.initSearch();
+    //         actions = hot('-a', { a: action });
+    //         const expected = cold('-(bcdefghi)', {
+    //             b: searchActions.changeCurrentDataset({ currentDataset: 'myDatasetName' }),
+    //             c: attributeActions.loadAttributeList(),
+    //             d: criteriaFamilyActions.loadCriteriaFamilyList(),
+    //             e: outputFamilyActions.loadOutputFamilyList(),
+    //             f: outputCategoryActions.loadOutputCategoryList(),
+    //             g: searchActions.checkCriteria(),
+    //             h: searchActions.checkOutput(),
+    //             i: searchActions.checkResult()
+    //         });
+    //
+    //         expect(effects.initSearch$).toBeObservable(expected);
+    //     });
+    //
+    //     it('should dispatch a resetSearch action when user get back to search module', () => {
+    //         mockDatasetSelectorSelectDatasetNameByRoute = store.overrideSelector(
+    //             datasetSelector.selectDatasetNameByRoute, ''
+    //         );
+    //         mockSearchSelectorSelectPristine = store.overrideSelector(
+    //             searchSelector.selectPristine,false
+    //         );
+    //
+    //         const action = searchActions.initSearch();
+    //         const outcome = searchActions.resetSearch();
+    //
+    //         actions = hot('-a', { a: action });
+    //         const expected = cold('-b', { b: outcome });
+    //
+    //         expect(effects.initSearch$).toBeObservable(expected);
+    //     });
+    //
+    //     it('should not dispatch action when step changed on same search', () => {
+    //         mockDatasetSelectorSelectDatasetNameByRoute = store.overrideSelector(
+    //             datasetSelector.selectDatasetNameByRoute, ''
+    //         );
+    //
+    //         const action = searchActions.initSearch();
+    //         const outcome = { type: '[No Action] Init Search' };
+    //
+    //         actions = hot('-a', { a: action });
+    //         const expected = cold('-b', { b: outcome });
+    //
+    //         expect(effects.initSearch$).toBeObservable(expected);
+    //     });
+    });
+
+    describe('restartSearch$ effect', () => {
+        it('should dispatch the initSearch action', () => {
+            const action = searchMultipleActions.restartSearch();
+            const outcome = searchMultipleActions.initSearch();
+
+            actions = hot('-a', { a: action });
+            const expected = cold('-b', { b: outcome });
+
+            expect(effects.restartSearch$).toBeObservable(expected);
+        });
+    });
+
+    // describe('loadDefaultFormParameters$ effect', () => {
+    //     it('should not dispatch action if params already loaded', () => {
+    //         mockSearchSelectorSelectPristine = store.overrideSelector(
+    //             searchSelector.selectPristine, false
+    //         );
+    //         mockSearchSelectorSelectCurrentDataset = store.overrideSelector(
+    //             searchSelector.selectCurrentDataset, 'myDataset'
+    //         );
+    //
+    //         const action = searchActions.loadDefaultFormParameters();
+    //         const outcome = { type: '[No Action] Load Default Form Parameters' };
+    //
+    //         actions = hot('-a', { a: action });
+    //         const expected = cold('-b', { b: outcome });
+    //
+    //         expect(effects.loadDefaultFormParameters$).toBeObservable(expected);
+    //     });
+    //
+    //     it('should not dispatch action if no dataset selected', () => {
+    //         const action = searchActions.loadDefaultFormParameters();
+    //         const outcome = { type: '[No Action] Load Default Form Parameters' };
+    //
+    //         actions = hot('-a', { a: action });
+    //         const expected = cold('-b', { b: outcome });
+    //
+    //         expect(effects.loadDefaultFormParameters$).toBeObservable(expected);
+    //     });
+    //
+    //     it('should dispatch a bunch of actions to update search', () => {
+    //         mockSearchSelectorSelectPristine = store.overrideSelector(
+    //             searchSelector.selectPristine, true
+    //         );
+    //         mockSearchSelectorSelectCurrentDataset = store.overrideSelector(
+    //             searchSelector.selectCurrentDataset, 'myDataset'
+    //         );
+    //
+    //         const action = searchActions.loadDefaultFormParameters();
+    //         actions = hot('-a', { a: action });
+    //
+    //         const defaultCriteriaList = [];
+    //         const defaultConeSearch = null;
+    //         const defaultOutputList = [];
+    //         const expected = cold('-(bcde)', {
+    //             b: searchActions.updateCriteriaList({ criteriaList: defaultCriteriaList }),
+    //             c: coneSearchActions.addConeSearch({ coneSearch: defaultConeSearch }),
+    //             d: searchActions.updateOutputList({ outputList: defaultOutputList }),
+    //             e: searchActions.markAsDirty()
+    //         });
+    //
+    //         expect(effects.loadDefaultFormParameters$).toBeObservable(expected);
+    //     });
+    //
+    //     it('should set a default criteria list', () => {
+    //         mockSearchSelectorSelectPristine = store.overrideSelector(
+    //             searchSelector.selectPristine, true
+    //         );
+    //         mockSearchSelectorSelectCurrentDataset = store.overrideSelector(
+    //             searchSelector.selectCurrentDataset, 'myDataset'
+    //         );
+    //         mockAttributeSelectorSelectAllAttributes = store.overrideSelector(
+    //             attributeSelector.selectAllAttributes, [
+    //                 {
+    //                     id: 1,
+    //                     name: 'att1',
+    //                     label: 'attribute1',
+    //                     form_label: 'Attribute 1',
+    //                     output_display: 1,
+    //                     criteria_display: 1,
+    //                     search_type: 'field',
+    //                     operator: 'eq',
+    //                     type: 'string',
+    //                     min: 'one',
+    //                     display_detail: 1,
+    //                     id_criteria_family: 1,
+    //                     id_output_category: 1
+    //                 },
+    //                 {
+    //                     id: 2,
+    //                     name: 'att2',
+    //                     label: 'attribute2',
+    //                     form_label: 'Attribute 2',
+    //                     output_display: 1,
+    //                     criteria_display: 1,
+    //                     search_type: 'field',
+    //                     operator: 'eq',
+    //                     type: 'string',
+    //                     min: 'two',
+    //                     display_detail: 1,
+    //                     id_criteria_family: 2,
+    //                     id_output_category: 1
+    //                 }
+    //             ]
+    //         );
+    //
+    //         const action = searchActions.loadDefaultFormParameters();
+    //         actions = hot('-a', { a: action });
+    //
+    //         const defaultCriteriaList = [
+    //             {'id':1,'type':'field','operator':'eq','value':'one'},
+    //             {'id':2,'type':'field','operator':'eq','value':'two'}
+    //         ];
+    //         const defaultConeSearch = null;
+    //         const defaultOutputList = [];
+    //         const expected = cold('-(bcde)', {
+    //             b: searchActions.updateCriteriaList({ criteriaList: defaultCriteriaList }),
+    //             c: coneSearchActions.addConeSearch({ coneSearch: defaultConeSearch }),
+    //             d: searchActions.updateOutputList({ outputList: defaultOutputList }),
+    //             e: searchActions.markAsDirty()
+    //         });
+    //
+    //         expect(effects.loadDefaultFormParameters$).toBeObservable(expected);
+    //     });
+    //
+    //     it('should set criteria list from URL', () => {
+    //         mockSearchSelectorSelectPristine = store.overrideSelector(
+    //             searchSelector.selectPristine, true
+    //         );
+    //         mockSearchSelectorSelectCurrentDataset = store.overrideSelector(
+    //             searchSelector.selectCurrentDataset, 'myDataset'
+    //         );
+    //         mockAttributeSelectorSelectAllAttributes = store.overrideSelector(
+    //             attributeSelector.selectAllAttributes, [
+    //                 {
+    //                     id: 1,
+    //                     name: 'att1',
+    //                     label: 'attribute1',
+    //                     form_label: 'Attribute 1',
+    //                     output_display: 1,
+    //                     criteria_display: 1,
+    //                     search_type: 'field',
+    //                     operator: 'eq',
+    //                     type: 'string',
+    //                     min: 'one',
+    //                     display_detail: 1,
+    //                     id_criteria_family: 1,
+    //                     id_output_category: 1
+    //                 },
+    //                 {
+    //                     id: 2,
+    //                     name: 'att2',
+    //                     label: 'attribute2',
+    //                     form_label: 'Attribute 2',
+    //                     output_display: 1,
+    //                     criteria_display: 1,
+    //                     search_type: 'field',
+    //                     operator: 'eq',
+    //                     type: 'string',
+    //                     min: 'two',
+    //                     display_detail: 1,
+    //                     id_criteria_family: 2,
+    //                     id_output_category: 1
+    //                 }
+    //             ]
+    //         );
+    //         mockSearchSelectorSelectCriteriaListByRoute = store.overrideSelector(
+    //             searchSelector.selectCriteriaListByRoute, '1::eq::un;2::eq::deux'
+    //         );
+    //
+    //         const action = searchActions.loadDefaultFormParameters();
+    //         actions = hot('-a', { a: action });
+    //
+    //         const criteriaList = [
+    //             {'id':1,'type':'field','operator':'eq','value':'un'},
+    //             {'id':2,'type':'field','operator':'eq','value':'deux'}
+    //         ];
+    //         const defaultConeSearch = null;
+    //         const defaultOutputList = [];
+    //         const expected = cold('-(bcde)', {
+    //             b: searchActions.updateCriteriaList({ criteriaList: criteriaList }),
+    //             c: coneSearchActions.addConeSearch({ coneSearch: defaultConeSearch }),
+    //             d: searchActions.updateOutputList({ outputList: defaultOutputList }),
+    //             e: searchActions.markAsDirty()
+    //         });
+    //
+    //         expect(effects.loadDefaultFormParameters$).toBeObservable(expected);
+    //     });
+    //
+    //     it('should set cone search from URL', () => {
+    //         mockSearchSelectorSelectPristine = store.overrideSelector(
+    //             searchSelector.selectPristine, true
+    //         );
+    //         mockSearchSelectorSelectCurrentDataset = store.overrideSelector(
+    //             searchSelector.selectCurrentDataset, 'myDataset'
+    //         );
+    //         mockConeSearchSelectorSelectConeSearchByRoute = store.overrideSelector(
+    //             coneSearchSelector.selectConeSearchByRoute, '1:2:3'
+    //         );
+    //
+    //         const action = searchActions.loadDefaultFormParameters();
+    //         actions = hot('-a', { a: action });
+    //
+    //         const defaultCriteriaList = [];
+    //         const coneSearch = { ra: 1, dec: 2, radius: 3 };
+    //         const defaultOutputList = [];
+    //         const expected = cold('-(bcde)', {
+    //             b: searchActions.updateCriteriaList({ criteriaList: defaultCriteriaList }),
+    //             c: coneSearchActions.addConeSearch({ coneSearch: coneSearch }),
+    //             d: searchActions.updateOutputList({ outputList: defaultOutputList }),
+    //             e: searchActions.markAsDirty()
+    //         });
+    //
+    //         expect(effects.loadDefaultFormParameters$).toBeObservable(expected);
+    //     });
+    //
+    //     it('should set a default output list', () => {
+    //         mockSearchSelectorSelectPristine = store.overrideSelector(
+    //             searchSelector.selectPristine, true
+    //         );
+    //         mockSearchSelectorSelectCurrentDataset = store.overrideSelector(
+    //             searchSelector.selectCurrentDataset, 'myDataset'
+    //         );
+    //         mockAttributeSelectorSelectAllAttributes = store.overrideSelector(
+    //             attributeSelector.selectAllAttributes, [
+    //                 {
+    //                     id: 1,
+    //                     name: 'att1',
+    //                     label: 'attribute1',
+    //                     form_label: 'Attribute 1',
+    //                     output_display: 1,
+    //                     criteria_display: 1,
+    //                     search_type: 'field',
+    //                     operator: 'eq',
+    //                     type: 'string',
+    //                     display_detail: 1,
+    //                     selected: true,
+    //                     id_criteria_family: 1,
+    //                     id_output_category: 1
+    //                 },
+    //                 {
+    //                     id: 2,
+    //                     name: 'att2',
+    //                     label: 'attribute2',
+    //                     form_label: 'Attribute 2',
+    //                     output_display: 1,
+    //                     criteria_display: 1,
+    //                     search_type: 'field',
+    //                     operator: 'eq',
+    //                     type: 'string',
+    //                     display_detail: 1,
+    //                     selected: true,
+    //                     id_criteria_family: 2,
+    //                     id_output_category: 1
+    //                 }
+    //             ]
+    //         );
+    //
+    //         const action = searchActions.loadDefaultFormParameters();
+    //         actions = hot('-a', { a: action });
+    //
+    //         const defaultCriteriaList = [];
+    //         const defaultConeSearch = null;
+    //         const defaultOutputList = [1, 2];
+    //         const expected = cold('-(bcde)', {
+    //             b: searchActions.updateCriteriaList({ criteriaList: defaultCriteriaList }),
+    //             c: coneSearchActions.addConeSearch({ coneSearch: defaultConeSearch }),
+    //             d: searchActions.updateOutputList({ outputList: defaultOutputList }),
+    //             e: searchActions.markAsDirty()
+    //         });
+    //
+    //         expect(effects.loadDefaultFormParameters$).toBeObservable(expected);
+    //     });
+    //
+    //     it('should set output list from URL', () => {
+    //         mockSearchSelectorSelectPristine = store.overrideSelector(
+    //             searchSelector.selectPristine, true
+    //         );
+    //         mockSearchSelectorSelectCurrentDataset = store.overrideSelector(
+    //             searchSelector.selectCurrentDataset, 'myDataset'
+    //         );
+    //         mockSearchSelectorSelectOutputListByRoute = store.overrideSelector(
+    //             searchSelector.selectOutputListByRoute, '1;2;3'
+    //         );
+    //
+    //         const action = searchActions.loadDefaultFormParameters();
+    //         actions = hot('-a', { a: action });
+    //
+    //         const defaultCriteriaList = [];
+    //         const defaultConeSearch = null;
+    //         const outputList = [1, 2, 3];
+    //         const expected = cold('-(bcde)', {
+    //             b: searchActions.updateCriteriaList({ criteriaList: defaultCriteriaList }),
+    //             c: coneSearchActions.addConeSearch({ coneSearch: defaultConeSearch }),
+    //             d: searchActions.updateOutputList({ outputList: outputList }),
+    //             e: searchActions.markAsDirty()
+    //         });
+    //
+    //         expect(effects.loadDefaultFormParameters$).toBeObservable(expected);
+    //     });
+    // });
+
+    // describe('retrieveDataLength$ effect', () => {
+    //     it('should dispatch the retrieveDataLengthSuccess action on success', () => {
+    //         const action = searchActions.retrieveDataLength();
+    //         const outcome = searchActions.retrieveDataLengthSuccess({ length: 5 });
+    //
+    //         actions = hot('-a', { a: action });
+    //         const response = cold('-b|', { b: [{ nb: 5 }] });
+    //         const expected = cold('--c', { c: outcome });
+    //         searchService.retrieveDataLength = jest.fn(() => response);
+    //
+    //         expect(effects.retrieveDataLength$).toBeObservable(expected);
+    //     });
+    //
+    //     it('should dispatch the retrieveDataLengthFail action on failure', () => {
+    //         const action = searchActions.retrieveDataLength();
+    //         const error = new Error();
+    //         const outcome = searchActions.retrieveDataLengthFail();
+    //
+    //         actions = hot('-a', { a: action });
+    //         const response = cold('-#|', {}, error);
+    //         const expected = cold('--b', { b: outcome });
+    //         searchService.retrieveDataLength = jest.fn(() => response);
+    //
+    //         expect(effects.retrieveDataLength$).toBeObservable(expected);
+    //     });
+    //
+    //     it('should pass correct query to the service', () => {
+    //         mockDatasetSelectorSelectDatasetNameByRoute = store.overrideSelector(
+    //             datasetSelector.selectDatasetNameByRoute, 'myDataset'
+    //         );
+    //         mockSearchSelectorSelectCriteriaList = store.overrideSelector(
+    //             searchSelector.selectCriteriaList, [{'id':1,'type':'field','operator':'eq','value':'one'} as Criterion]
+    //         );
+    //         mockConeSearchSelectorSelectConeSearch = store.overrideSelector(
+    //             coneSearchSelector.selectConeSearch, { ra: 1, dec: 2, radius: 3 }
+    //         );
+    //
+    //         jest.spyOn(searchService, 'retrieveDataLength');
+    //
+    //         const action = searchActions.retrieveDataLength();
+    //         const outcome = searchActions.retrieveDataLengthSuccess({ length: 5 });
+    //
+    //         actions = hot('-a', { a: action });
+    //         const response = cold('-b|', { b: [{ nb: 5 }] });
+    //         const expected = cold('--c', { c: outcome });
+    //         searchService.retrieveDataLength = jest.fn(() => response);
+    //
+    //         expect(effects.retrieveDataLength$).toBeObservable(expected);
+    //         expect(searchService.retrieveDataLength).toHaveBeenCalledTimes(1);
+    //         expect(searchService.retrieveDataLength).toHaveBeenCalledWith('myDataset?a=count&c=1::eq::one&cs=1:2:3');
+    //     });
+    // });
+
+    describe('retrieveDataLengthFail$ effect', () => {
+        it('should not dispatch', () => {
+            expect(metadata.retrieveDataLengthFail$).toEqual(
+                expect.objectContaining({ dispatch: false })
+            );
+        });
+
+        it('should display a error notification', () => {
+            const spy = jest.spyOn(toastr, 'error');
+            const action = searchMultipleActions.retrieveDataLengthFail();
+
+            actions = hot('a', { a: action });
+            const expected = cold('a', { a: action });
+
+            expect(effects.retrieveDataLengthFail$).toBeObservable(expected);
+            expect(spy).toHaveBeenCalledTimes(1);
+            expect(spy).toHaveBeenCalledWith('Loading Failed', 'The search multiple data length loading failed');
+        });
+    });
+
+    // describe('retrieveData$ effect', () => {
+    //     it('should dispatch the retrieveDataSuccess action on success', () => {
+    //         const action = searchActions.retrieveData( {
+    //             pagination: { dname: 'myDatasetName', page: 1, nbItems: 10, sortedCol: 1, order: PaginationOrder.a }
+    //         });
+    //         const outcome = searchActions.retrieveDataSuccess({ data: ['data'] });
+    //
+    //         actions = hot('-a', { a: action });
+    //         const response = cold('-b|', { b: ['data'] });
+    //         const expected = cold('--c', { c: outcome });
+    //         searchService.retrieveData = jest.fn(() => response);
+    //
+    //         expect(effects.retrieveData$).toBeObservable(expected);
+    //     });
+    //
+    //     it('should dispatch the retrieveDataFail action on failure', () => {
+    //         const action = searchActions.retrieveData({
+    //             pagination: { dname: 'myDatasetName', page: 1, nbItems: 10, sortedCol: 1, order: PaginationOrder.a }
+    //         });
+    //         const error = new Error();
+    //         const outcome = searchActions.retrieveDataFail();
+    //
+    //         actions = hot('-a', { a: action });
+    //         const response = cold('-#|', {}, error);
+    //         const expected = cold('--b', { b: outcome });
+    //         searchService.retrieveData = jest.fn(() => response);
+    //
+    //         expect(effects.retrieveData$).toBeObservable(expected);
+    //     });
+    //
+    //     it('should pass correct query to the service', () => {
+    //         mockDatasetSelectorSelectDatasetNameByRoute = store.overrideSelector(
+    //             datasetSelector.selectDatasetNameByRoute, 'myDataset'
+    //         );
+    //         mockSearchSelectorSelectCriteriaList = store.overrideSelector(
+    //             searchSelector.selectCriteriaList, [{'id':1,'type':'field','operator':'eq','value':'one'} as Criterion]
+    //         );
+    //         mockConeSearchSelectorSelectConeSearch = store.overrideSelector(
+    //             coneSearchSelector.selectConeSearch, { ra: 1, dec: 2, radius: 3 }
+    //         );
+    //         mockSearchSelectorSelectOutputList = store.overrideSelector(
+    //             searchSelector.selectOutputList, [1, 2]
+    //         );
+    //
+    //         jest.spyOn(searchService, 'retrieveData');
+    //
+    //         const action = searchActions.retrieveData({
+    //             pagination: { dname: 'myDatasetName', page: 1, nbItems: 10, sortedCol: 1, order: PaginationOrder.a }
+    //         });
+    //         const outcome = searchActions.retrieveDataSuccess({ data: ['data'] });
+    //
+    //         actions = hot('-a', { a: action });
+    //         const response = cold('-b|', { b: ['data'] });
+    //         const expected = cold('--c', { c: outcome });
+    //         searchService.retrieveData = jest.fn(() => response);
+    //
+    //         expect(effects.retrieveData$).toBeObservable(expected);
+    //         expect(searchService.retrieveData).toHaveBeenCalledTimes(1);
+    //         expect(searchService.retrieveData).toHaveBeenCalledWith('myDataset?a=1;2&c=1::eq::one&cs=1:2:3&p=10:1&o=1:a');
+    //     });
+    // });
+
+    // describe('retrieveDataFail$ effect', () => {
+    //     it('should not dispatch', () => {
+    //         expect(metadata.retrieveDataFail$).toEqual(
+    //             expect.objectContaining({ dispatch: false })
+    //         );
+    //     });
+    //
+    //     it('should display a error notification', () => {
+    //         const spy = jest.spyOn(toastr, 'error');
+    //         const action = searchActions.retrieveDataFail();
+    //
+    //         actions = hot('a', { a: action });
+    //         const expected = cold('a', { a: action });
+    //
+    //         expect(effects.retrieveDataFail$).toBeObservable(expected);
+    //         expect(spy).toHaveBeenCalledTimes(1);
+    //         expect(spy).toHaveBeenCalledWith('Loading Failed', 'The search data loading failed');
+    //     });
+    // });
+});
diff --git a/client/src/app/instance/store/effects/search-multiple.effects.ts b/client/src/app/instance/store/effects/search-multiple.effects.ts
index 84382d44..8fd7a53c 100644
--- a/client/src/app/instance/store/effects/search-multiple.effects.ts
+++ b/client/src/app/instance/store/effects/search-multiple.effects.ts
@@ -26,7 +26,11 @@ import * as coneSearchSelector from '../selectors/cone-search.selector';
 
 @Injectable()
 export class SearchMultipleEffects {
-    initSearch$ = createEffect(() =>
+
+    /**
+     * Calls actions to initialize search multiple.
+     */
+    initSearch$ = createEffect((): any =>
         this.actions$.pipe(
             ofType(searchMultipleActions.initSearch),
             concatLatestFrom(() => [
@@ -86,14 +90,20 @@ export class SearchMultipleEffects {
         )
     );
 
-    restartSearch$ = createEffect(() => 
+    /**
+     * Calls actions to restart search multiple.
+     */
+    restartSearch$ = createEffect((): any =>
         this.actions$.pipe(
             ofType(searchMultipleActions.restartSearch),
             map(() => searchMultipleActions.initSearch())
         )
     );
 
-    retrieveDataLength$ = createEffect(() =>
+    /**
+     * Calls actions to retrieve data length.
+     */
+    retrieveDataLength$ = createEffect((): any =>
         this.actions$.pipe(
             ofType(searchMultipleActions.retrieveDataLength),
             concatLatestFrom(() => [
@@ -116,11 +126,14 @@ export class SearchMultipleEffects {
         )
     );
 
-    retrieveDataLengthFail$ = createEffect(() => 
+    /**
+     * Displays retrieve data length error notification.
+     */
+    retrieveDataLengthFail$ = createEffect(() =>
         this.actions$.pipe(
             ofType(searchMultipleActions.retrieveDataLengthFail),
             tap(() => this.toastr.error('Loading Failed', 'The search multiple data length loading failed'))
-        ), { dispatch: false}
+        ), { dispatch: false }
     );
 
     constructor(
-- 
GitLab