Skip to content
Snippets Groups Projects
search.effects.spec.ts 28.6 KiB
Newer Older
  • Learn to ignore specific revisions
  • 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 { SearchEffects } from './search.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';
    
    
    describe('SearchEffects', () => {
        let actions = new Observable();
        let effects: SearchEffects;
        let metadata: EffectsMetadata<SearchEffects>;
        let searchService: SearchService;
        let toastr: ToastrService;
        let store: MockStore;
        const initialState = { search: { ...fromSearch.initialState } };
    
        let mockDatasetSelectorSelectDatasetNameByRoute;
        let mockSearchSelectorSelectCurrentDataset;
        let mockSearchSelectorSelectPristine;
        let mockSearchSelectorSelectStepsByRoute;
        let mockAttributeSelectorSelectAllAttributes;
        let mockSearchSelectorSelectCriteriaListByRoute;
    
        let mockSearchSelectorSelectCriteriaList;
    
        let mockConeSearchSelectorSelectConeSearchByRoute;
    
        let mockConeSearchSelectorSelectConeSearch;
    
        let mockSearchSelectorSelectOutputListByRoute;
    
        let mockSearchSelectorSelectOutputList;
    
    
        beforeEach(() => {
            TestBed.configureTestingModule({
                providers: [
                    SearchEffects,
                    { provide: SearchService, useValue: {
                            retrieveData: jest.fn(),
                            retrieveDataLength: jest.fn()
                        }},
                    { provide: ToastrService, useValue: { error: jest.fn() }},
                    provideMockActions(() => actions),
                    provideMockStore({ initialState }),
                ]
            }).compileComponents();
            effects = TestBed.inject(SearchEffects);
            metadata = getEffectsMetadata(effects);
            searchService = TestBed.inject(SearchService);
            toastr = TestBed.inject(ToastrService);
            store = TestBed.inject(MockStore);
    
            mockDatasetSelectorSelectDatasetNameByRoute = store.overrideSelector(
                datasetSelector.selectDatasetNameByRoute,''
            );
            mockSearchSelectorSelectCurrentDataset = store.overrideSelector(
                searchSelector.selectCurrentDataset,''
            );
            mockSearchSelectorSelectPristine = store.overrideSelector(
                searchSelector.selectPristine,true
            );
            mockAttributeSelectorSelectAllAttributes = store.overrideSelector(
                attributeSelector.selectAllAttributes,[]
            );
            mockSearchSelectorSelectStepsByRoute = store.overrideSelector(
                searchSelector.selectStepsByRoute,''
            );
            mockSearchSelectorSelectCriteriaListByRoute = store.overrideSelector(
                searchSelector.selectCriteriaListByRoute,''
            );
    
            mockSearchSelectorSelectCriteriaList = store.overrideSelector(
                searchSelector.selectCriteriaList,[]
            );
    
            mockConeSearchSelectorSelectConeSearchByRoute = store.overrideSelector(
                coneSearchSelector.selectConeSearchByRoute,''
            );
    
            mockConeSearchSelectorSelectConeSearch = store.overrideSelector(
                coneSearchSelector.selectConeSearch,{ ra: 1, dec: 2, radius: 3 }
            );
    
            mockSearchSelectorSelectOutputListByRoute = store.overrideSelector(
                searchSelector.selectOutputListByRoute,''
            );
    
            mockSearchSelectorSelectOutputList = store.overrideSelector(
                searchSelector.selectOutputList,[]
            );
    
        });
    
        it('should be created', () => {
            expect(effects).toBeTruthy();
        });
    
    
        describe('initSearch$ effect', () => {
            it('should dispatch the restartSearch action when dataset changed', () => {
                mockDatasetSelectorSelectDatasetNameByRoute = store.overrideSelector(
                    datasetSelector.selectDatasetNameByRoute, 'myNewDataset'
                );
                mockSearchSelectorSelectCurrentDataset = store.overrideSelector(
                    searchSelector.selectCurrentDataset,'myOldDataset'
                );
    
                const action = searchActions.initSearch();
                const outcome = searchActions.restartSearch();
    
                actions = hot('-a', { a: action });
                const expected = cold('-b', { b: outcome });
    
                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 = searchActions.restartSearch();
                const outcome = searchActions.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 = searchActions.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 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');
            });
        });
    });