diff --git a/src/app/shared/search/search-filters/search-filter/search-facet-filter/search-facet-filter.component.spec.ts b/src/app/shared/search/search-filters/search-filter/search-facet-filter/search-facet-filter.component.spec.ts index 919dfc0889..d22496807b 100644 --- a/src/app/shared/search/search-filters/search-filter/search-facet-filter/search-facet-filter.component.spec.ts +++ b/src/app/shared/search/search-filters/search-filter/search-facet-filter/search-facet-filter.component.spec.ts @@ -197,7 +197,6 @@ describe('SearchFacetFilterComponent', () => { describe('when the onSubmit method is called with data', () => { const searchUrl = '/search/path'; const testValue = 'test'; - const data = testValue; beforeEach(() => { comp.selectedValues$ = observableOf(selectedValues.map((value) => @@ -207,15 +206,25 @@ describe('SearchFacetFilterComponent', () => { }))); fixture.detectChanges(); spyOn(comp, 'getSearchLink').and.returnValue(searchUrl); - comp.onSubmit(data); }); - it('should call navigate on the router with the right searchlink and parameters', () => { + it('should call navigate on the router with the right searchlink and parameters when the filter is provided with a valid operator', () => { + comp.onSubmit(testValue + ',equals'); expect(router.navigate).toHaveBeenCalledWith(searchUrl.split('/'), { - queryParams: { [mockFilterConfig.paramName]: [...selectedValues.map((value) => `${value},equals`), testValue] }, + queryParams: { [mockFilterConfig.paramName]: [...selectedValues.map((value) => `${value},equals`), `${testValue},equals`] }, queryParamsHandling: 'merge' }); }); + + it('should not call navigate on the router when the filter is not provided with a valid operator', () => { + comp.onSubmit(testValue); + expect(router.navigate).not.toHaveBeenCalled(); + }); + + it('should not call navigate on the router when the empty string is given as filter', () => { + comp.onSubmit(',equals'); + expect(router.navigate).not.toHaveBeenCalled(); + }); }); describe('when updateFilterValueList is called', () => { diff --git a/src/app/shared/search/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.spec.ts b/src/app/shared/search/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.spec.ts new file mode 100644 index 0000000000..c59ae7a906 --- /dev/null +++ b/src/app/shared/search/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.spec.ts @@ -0,0 +1,153 @@ +import { TestBed, ComponentFixture } from '@angular/core/testing'; +import { SearchHierarchyFilterComponent } from './search-hierarchy-filter.component'; +import { SearchService } from '../../../../../core/shared/search/search.service'; +import { + SearchFilterService, + FILTER_CONFIG, + IN_PLACE_SEARCH +} from '../../../../../core/shared/search/search-filter.service'; +import { RemoteDataBuildService } from '../../../../../core/cache/builders/remote-data-build.service'; +import { SearchFiltersComponent } from '../../search-filters.component'; +import { Router } from '@angular/router'; +import { RouterStub } from '../../../../testing/router.stub'; +import { SearchServiceStub } from '../../../../testing/search-service.stub'; +import { of as observableOf, Observable } from 'rxjs'; +import { SEARCH_CONFIG_SERVICE } from '../../../../../my-dspace-page/my-dspace-page.component'; +import { SearchConfigurationServiceStub } from '../../../../testing/search-configuration-service.stub'; +import { SearchFilterConfig } from '../../../models/search-filter-config.model'; +import { TranslateModule } from '@ngx-translate/core'; +import { + FilterInputSuggestionsComponent +} from '../../../../input-suggestions/filter-suggestions/filter-input-suggestions.component'; +import { FormsModule } from '@angular/forms'; +import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { NO_ERRORS_SCHEMA, ChangeDetectionStrategy } from '@angular/core'; +import { createSuccessfulRemoteDataObject$ } from '../../../../remote-data.utils'; +import { FacetValue } from '../../../models/facet-value.model'; +import { FilterType } from '../../../models/filter-type.model'; +import { createPaginatedList } from '../../../../testing/utils.test'; +import { RemoteData } from '../../../../../core/data/remote-data'; +import { PaginatedList } from '../../../../../core/data/paginated-list.model'; + +describe('SearchHierarchyFilterComponent', () => { + let comp: SearchHierarchyFilterComponent; + let fixture: ComponentFixture; + let searchService: SearchService; + let router; + + const value1 = 'testvalue1'; + const value2 = 'test2'; + const value3 = 'another value3'; + const values: FacetValue[] = [ + { + label: value1, + value: value1, + count: 52, + _links: { + self: { + href: '' + }, + search: { + href: '' + } + } + }, { + label: value2, + value: value2, + count: 20, + _links: { + self: { + href: '' + }, + search: { + href: '' + } + } + }, { + label: value3, + value: value3, + count: 5, + _links: { + self: { + href: '' + }, + search: { + href: '' + } + } + } + ]; + const mockValues = createSuccessfulRemoteDataObject$(createPaginatedList(values)); + + const searchFilterServiceStub = { + getSelectedValuesForFilter(_filterConfig: SearchFilterConfig): Observable { + return observableOf(values.map((value: FacetValue) => value.value)); + }, + getPage(_paramName: string): Observable { + return observableOf(0); + }, + resetPage(_filterName: string): void { + // empty + } + }; + + const remoteDataBuildServiceStub = { + aggregate(_input: Observable>[]): Observable[]>> { + return createSuccessfulRemoteDataObject$([createPaginatedList(values)]); + } + }; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [TranslateModule.forRoot(), NoopAnimationsModule, FormsModule], + declarations: [ + SearchHierarchyFilterComponent, + SearchFiltersComponent, + FilterInputSuggestionsComponent + ], + providers: [ + { provide: SearchService, useValue: new SearchServiceStub() }, + { provide: SearchFilterService, useValue: searchFilterServiceStub }, + { provide: RemoteDataBuildService, useValue: remoteDataBuildServiceStub }, + { provide: Router, useValue: new RouterStub() }, + { provide: SEARCH_CONFIG_SERVICE, useValue: new SearchConfigurationServiceStub() }, + { provide: IN_PLACE_SEARCH, useValue: false }, + { provide: FILTER_CONFIG, useValue: new SearchFilterConfig() } + ], + schemas: [NO_ERRORS_SCHEMA] + }).overrideComponent(SearchHierarchyFilterComponent, { + set: { changeDetection: ChangeDetectionStrategy.Default } + }).compileComponents(); + }) + ; + const mockFilterConfig: SearchFilterConfig = Object.assign(new SearchFilterConfig(), { + name: 'filterName1', + filterType: FilterType.text, + hasFacets: false, + isOpenByDefault: false, + pageSize: 2 + }); + + beforeEach(async () => { + fixture = TestBed.createComponent(SearchHierarchyFilterComponent); + comp = fixture.componentInstance; // SearchHierarchyFilterComponent test instance + comp.filterConfig = mockFilterConfig; + searchService = (comp as any).searchService; + // @ts-ignore + spyOn(searchService, 'getFacetValuesFor').and.returnValue(mockValues); + router = (comp as any).router; + fixture.detectChanges(); + }); + + it('should navigate to the correct filter with the query operator', () => { + expect((comp as any).searchService.getFacetValuesFor).toHaveBeenCalledWith(comp.filterConfig, 0, {}); + + const searchQuery = 'MARVEL'; + comp.onSubmit(searchQuery); + + expect(router.navigate).toHaveBeenCalledWith(['', 'search'], Object({ + queryParams: Object({ [mockFilterConfig.paramName]: [...values.map((value: FacetValue) => `${value.value},equals`), `${searchQuery},query`] }), + queryParamsHandling: 'merge' + })); + }); +}); diff --git a/src/app/shared/search/search.utils.spec.ts b/src/app/shared/search/search.utils.spec.ts index 969ea1927d..fb07e2c82c 100644 --- a/src/app/shared/search/search.utils.spec.ts +++ b/src/app/shared/search/search.utils.spec.ts @@ -50,8 +50,17 @@ describe('Search Utils', () => { }); describe('stripOperatorFromFilterValue', () => { - it('should strip the operator from the value', () => { - expect(stripOperatorFromFilterValue('value,operator')).toEqual('value'); + it('should strip equals operator from the value', () => { + expect(stripOperatorFromFilterValue('value,equals')).toEqual('value'); + }); + it('should strip query operator from the value', () => { + expect(stripOperatorFromFilterValue('value,query')).toEqual('value'); + }); + it('should strip authority operator from the value', () => { + expect(stripOperatorFromFilterValue('value,authority')).toEqual('value'); + }); + it('should not strip a the part after the last , from a value if it isn\'t a valid operator', () => { + expect(stripOperatorFromFilterValue('value,invalid_operator')).toEqual('value,invalid_operator'); }); });