mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 01:54:15 +00:00
375 lines
13 KiB
TypeScript
375 lines
13 KiB
TypeScript
import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core';
|
|
|
|
import { ComponentFixture, fakeAsync, TestBed, tick, waitForAsync } from '@angular/core/testing';
|
|
import { RouterTestingModule } from '@angular/router/testing';
|
|
import { Store } from '@ngrx/store';
|
|
import { TranslateModule } from '@ngx-translate/core';
|
|
import { cold } from 'jasmine-marbles';
|
|
import { BehaviorSubject, Observable, of as observableOf } from 'rxjs';
|
|
import { SortDirection, SortOptions } from '../../core/cache/models/sort-options.model';
|
|
import { CommunityDataService } from '../../core/data/community-data.service';
|
|
import { HostWindowService } from '../host-window.service';
|
|
import { PaginationComponentOptions } from '../pagination/pagination-component-options.model';
|
|
import { SearchComponent } from './search.component';
|
|
import { SearchService } from '../../core/shared/search/search.service';
|
|
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
|
import { ActivatedRoute } from '@angular/router';
|
|
import { By } from '@angular/platform-browser';
|
|
import { NgbCollapseModule } from '@ng-bootstrap/ng-bootstrap';
|
|
import { SidebarService } from '../sidebar/sidebar.service';
|
|
import { SearchFilterService } from '../../core/shared/search/search-filter.service';
|
|
import { SearchConfigurationService } from '../../core/shared/search/search-configuration.service';
|
|
import { SEARCH_CONFIG_SERVICE } from '../../my-dspace-page/my-dspace-page.component';
|
|
import { RouteService } from '../../core/services/route.service';
|
|
import { createSuccessfulRemoteDataObject, createSuccessfulRemoteDataObject$ } from '../remote-data.utils';
|
|
import { PaginatedSearchOptions } from './models/paginated-search-options.model';
|
|
import { SidebarServiceStub } from '../testing/sidebar-service.stub';
|
|
import { SearchConfig, SortConfig } from '../../core/shared/search/search-filters/search-config.model';
|
|
import { Item } from '../../core/shared/item.model';
|
|
import { RemoteData } from '../../core/data/remote-data';
|
|
import { SearchObjects } from './models/search-objects.model';
|
|
import { DSpaceObject } from '../../core/shared/dspace-object.model';
|
|
import { SearchFilterConfig } from './models/search-filter-config.model';
|
|
import { FilterType } from './models/filter-type.model';
|
|
import { getCommunityPageRoute } from '../../community-page/community-page-routing-paths';
|
|
import { getCollectionPageRoute } from '../../collection-page/collection-page-routing-paths';
|
|
import { environment } from '../../../environments/environment.test';
|
|
import { APP_CONFIG } from '../../../config/app-config.interface';
|
|
|
|
let comp: SearchComponent;
|
|
let fixture: ComponentFixture<SearchComponent>;
|
|
const store: Store<SearchComponent> = jasmine.createSpyObj('store', {
|
|
/* eslint-disable no-empty,@typescript-eslint/no-empty-function */
|
|
dispatch: {},
|
|
/* eslint-enable no-empty, @typescript-eslint/no-empty-function */
|
|
select: observableOf(true)
|
|
});
|
|
const sortConfigList: SortConfig[] = [
|
|
{ name: 'score', sortOrder: SortDirection.DESC },
|
|
{ name: 'dc.title', sortOrder: SortDirection.ASC },
|
|
{ name: 'dc.title', sortOrder: SortDirection.DESC }
|
|
];
|
|
const sortOptionsList: SortOptions[] = [
|
|
new SortOptions('score', SortDirection.DESC),
|
|
new SortOptions('dc.title', SortDirection.ASC),
|
|
new SortOptions('dc.title', SortDirection.DESC)
|
|
];
|
|
const searchConfig = Object.assign(new SearchConfig(), {
|
|
sortOptions: sortConfigList
|
|
});
|
|
const paginationId = 'search-test-page-id';
|
|
const pagination: PaginationComponentOptions = new PaginationComponentOptions();
|
|
pagination.id = paginationId;
|
|
pagination.currentPage = 1;
|
|
pagination.pageSize = 10;
|
|
const mockDso = Object.assign(new Item(), {
|
|
metadata: {
|
|
'dc.title': [
|
|
{
|
|
language: 'en_US',
|
|
value: 'Item nr 1'
|
|
}
|
|
]
|
|
},
|
|
_links: {
|
|
self: {
|
|
href: 'selfLink1'
|
|
}
|
|
}
|
|
});
|
|
|
|
const mockDso2 = Object.assign(new Item(), {
|
|
metadata: {
|
|
'dc.title': [
|
|
{
|
|
language: 'en_US',
|
|
value: 'Item nr 2'
|
|
}
|
|
]
|
|
},
|
|
_links: {
|
|
self: {
|
|
href: 'selfLink2'
|
|
}
|
|
}
|
|
});
|
|
const mockSearchResults: SearchObjects<DSpaceObject> = Object.assign(new SearchObjects(), {
|
|
page: [mockDso, mockDso2]
|
|
});
|
|
const mockResultsRD: RemoteData<SearchObjects<DSpaceObject>> = createSuccessfulRemoteDataObject(mockSearchResults);
|
|
const mockResultsRD$: Observable<RemoteData<SearchObjects<DSpaceObject>>> = observableOf(mockResultsRD);
|
|
const searchServiceStub = jasmine.createSpyObj('SearchService', {
|
|
search: mockResultsRD$,
|
|
getSearchLink: '/search',
|
|
getScopes: observableOf(['test-scope']),
|
|
getSearchConfigurationFor: createSuccessfulRemoteDataObject$(searchConfig),
|
|
trackSearch: {},
|
|
}) as SearchService;
|
|
const queryParam = 'test query';
|
|
const scopeParam = '7669c72a-3f2a-451f-a3b9-9210e7a4c02f';
|
|
|
|
const defaultSearchOptions = new PaginatedSearchOptions({ pagination });
|
|
|
|
const paginatedSearchOptions$ = new BehaviorSubject(defaultSearchOptions);
|
|
|
|
const activatedRouteStub = {
|
|
snapshot: {
|
|
queryParamMap: new Map([
|
|
['query', queryParam],
|
|
['scope', scopeParam]
|
|
])
|
|
},
|
|
queryParams: observableOf({
|
|
query: queryParam,
|
|
scope: scopeParam
|
|
})
|
|
};
|
|
|
|
const mockFilterConfig: SearchFilterConfig = Object.assign(new SearchFilterConfig(), {
|
|
name: 'test1',
|
|
filterType: FilterType.text,
|
|
hasFacets: false,
|
|
isOpenByDefault: false,
|
|
pageSize: 2
|
|
});
|
|
const mockFilterConfig2: SearchFilterConfig = Object.assign(new SearchFilterConfig(), {
|
|
name: 'test2',
|
|
filterType: FilterType.text,
|
|
hasFacets: false,
|
|
isOpenByDefault: false,
|
|
pageSize: 1
|
|
});
|
|
|
|
const filtersConfigRD = createSuccessfulRemoteDataObject([mockFilterConfig, mockFilterConfig2]);
|
|
const filtersConfigRD$ = observableOf(filtersConfigRD);
|
|
|
|
const routeServiceStub = {
|
|
getQueryParameterValue: () => {
|
|
return observableOf(null);
|
|
},
|
|
getQueryParamsWithPrefix: () => {
|
|
return observableOf(null);
|
|
},
|
|
setParameter: () => {
|
|
return;
|
|
}
|
|
};
|
|
|
|
let searchConfigurationServiceStub;
|
|
|
|
export function configureSearchComponentTestingModule(compType, additionalDeclarations: any[] = []) {
|
|
searchConfigurationServiceStub = jasmine.createSpyObj('SearchConfigurationService', {
|
|
getConfigurationSortOptions: sortOptionsList,
|
|
getConfig: filtersConfigRD$,
|
|
getConfigurationSearchConfig: observableOf(searchConfig),
|
|
getCurrentConfiguration: observableOf('default'),
|
|
getCurrentScope: observableOf('test-id'),
|
|
getCurrentSort: observableOf(sortOptionsList[0]),
|
|
updateFixedFilter: jasmine.createSpy('updateFixedFilter'),
|
|
setPaginationId: jasmine.createSpy('setPaginationId')
|
|
});
|
|
|
|
searchConfigurationServiceStub.setPaginationId.and.callFake((pageId) => {
|
|
paginatedSearchOptions$.next(Object.assign(paginatedSearchOptions$.value, {
|
|
pagination: Object.assign(new PaginationComponentOptions(), {
|
|
id: pageId
|
|
})
|
|
}));
|
|
});
|
|
searchConfigurationServiceStub.paginatedSearchOptions = new BehaviorSubject(new PaginatedSearchOptions({pagination: {id: 'default'} as any}));
|
|
|
|
TestBed.configureTestingModule({
|
|
imports: [TranslateModule.forRoot(), RouterTestingModule.withRoutes([]), NoopAnimationsModule, NgbCollapseModule],
|
|
declarations: [compType, ...additionalDeclarations],
|
|
providers: [
|
|
{ provide: SearchService, useValue: searchServiceStub },
|
|
{
|
|
provide: CommunityDataService,
|
|
useValue: jasmine.createSpyObj('communityService', ['findById', 'findAll'])
|
|
},
|
|
{ provide: ActivatedRoute, useValue: activatedRouteStub },
|
|
{ provide: RouteService, useValue: routeServiceStub },
|
|
{
|
|
provide: Store, useValue: store
|
|
},
|
|
{
|
|
provide: HostWindowService, useValue: jasmine.createSpyObj('hostWindowService',
|
|
{
|
|
isXs: observableOf(true),
|
|
isSm: observableOf(false),
|
|
isXsOrSm: observableOf(true)
|
|
})
|
|
},
|
|
{
|
|
provide: SidebarService,
|
|
useValue: SidebarServiceStub
|
|
},
|
|
{
|
|
provide: SearchFilterService,
|
|
useValue: {}
|
|
},
|
|
{
|
|
provide: SEARCH_CONFIG_SERVICE,
|
|
useValue: searchConfigurationServiceStub
|
|
},
|
|
{ provide: APP_CONFIG, useValue: environment },
|
|
],
|
|
schemas: [NO_ERRORS_SCHEMA]
|
|
}).overrideComponent(compType, {
|
|
set: {
|
|
changeDetection: ChangeDetectionStrategy.Default,
|
|
providers: [{
|
|
provide: SearchConfigurationService,
|
|
useValue: searchConfigurationServiceStub
|
|
}]
|
|
},
|
|
|
|
}).compileComponents();
|
|
}
|
|
|
|
describe('SearchComponent', () => {
|
|
beforeEach(waitForAsync(() => {
|
|
configureSearchComponentTestingModule(SearchComponent);
|
|
}));
|
|
|
|
beforeEach(() => {
|
|
fixture = TestBed.createComponent(SearchComponent);
|
|
comp = fixture.componentInstance; // SearchComponent test instance
|
|
comp.inPlaceSearch = false;
|
|
comp.paginationId = paginationId;
|
|
|
|
spyOn((comp as any), 'getSearchOptions').and.returnValue(paginatedSearchOptions$.asObservable());
|
|
});
|
|
|
|
afterEach(() => {
|
|
comp = null;
|
|
});
|
|
|
|
it('should init search parameters properly and call retrieveSearchResults', fakeAsync(() => {
|
|
spyOn((comp as any), 'retrieveSearchResults').and.callThrough();
|
|
fixture.detectChanges();
|
|
tick(100);
|
|
|
|
const expectedSearchOptions = Object.assign(paginatedSearchOptions$.value, {
|
|
configuration: 'default',
|
|
sort: sortOptionsList[0]
|
|
});
|
|
expect(comp.currentConfiguration$).toBeObservable(cold('b', {
|
|
b: 'default'
|
|
}));
|
|
expect(comp.currentSortOptions$).toBeObservable(cold('b', {
|
|
b: sortOptionsList[0]
|
|
}));
|
|
expect(comp.sortOptionsList$).toBeObservable(cold('b', {
|
|
b: sortOptionsList
|
|
}));
|
|
expect(comp.searchOptions$).toBeObservable(cold('b', {
|
|
b: expectedSearchOptions
|
|
}));
|
|
expect((comp as any).retrieveSearchResults).toHaveBeenCalledWith(expectedSearchOptions);
|
|
}));
|
|
|
|
it('should retrieve SearchResults', fakeAsync(() => {
|
|
fixture.detectChanges();
|
|
tick(100);
|
|
const expectedResults = mockResultsRD;
|
|
expect(comp.resultsRD$).toBeObservable(cold('b', {
|
|
b: expectedResults
|
|
}));
|
|
}));
|
|
|
|
it('should retrieve Search Filters', fakeAsync(() => {
|
|
fixture.detectChanges();
|
|
tick(100);
|
|
const expectedResults = filtersConfigRD;
|
|
expect(comp.filtersRD$).toBeObservable(cold('b', {
|
|
b: expectedResults
|
|
}));
|
|
}));
|
|
|
|
it('should emit resultFound event', fakeAsync(() => {
|
|
spyOn(comp.resultFound, 'emit');
|
|
const expectedResults = mockSearchResults;
|
|
fixture.detectChanges();
|
|
tick(100);
|
|
expect(comp.resultFound.emit).toHaveBeenCalledWith(expectedResults);
|
|
}));
|
|
|
|
describe('when the open sidebar button is clicked in mobile view', () => {
|
|
|
|
beforeEach(() => {
|
|
spyOn(comp, 'openSidebar');
|
|
});
|
|
|
|
it('should trigger the openSidebar function', fakeAsync(() => {
|
|
fixture.detectChanges();
|
|
tick(100);
|
|
fixture.detectChanges();
|
|
const openSidebarButton = fixture.debugElement.query(By.css('.open-sidebar'));
|
|
openSidebarButton.triggerEventHandler('click', null);
|
|
expect(comp.openSidebar).toHaveBeenCalled();
|
|
}));
|
|
|
|
});
|
|
|
|
describe('getDsoUUIDFromUrl', () => {
|
|
let url: string;
|
|
let result: string;
|
|
|
|
describe('when the navigated URL is an entity route', () => {
|
|
beforeEach(() => {
|
|
url = '/entities/publication/9a364471-3f19-4e7b-916a-a24a44ff48e3';
|
|
result = (comp as any).getDsoUUIDFromUrl(url);
|
|
});
|
|
|
|
it('should return the UUID', () => {
|
|
expect(result).toEqual('9a364471-3f19-4e7b-916a-a24a44ff48e3');
|
|
});
|
|
});
|
|
|
|
describe('when the navigated URL is a community route', () => {
|
|
beforeEach(() => {
|
|
url = `${getCommunityPageRoute('9a364471-3f19-4e7b-916a-a24a44ff48e3')}`;
|
|
result = (comp as any).getDsoUUIDFromUrl(url);
|
|
});
|
|
|
|
it('should return the UUID', () => {
|
|
expect(result).toEqual('9a364471-3f19-4e7b-916a-a24a44ff48e3');
|
|
});
|
|
});
|
|
|
|
describe('when the navigated URL is a collection route', () => {
|
|
beforeEach(() => {
|
|
url = `${getCollectionPageRoute('9a364471-3f19-4e7b-916a-a24a44ff48e3')}`;
|
|
result = (comp as any).getDsoUUIDFromUrl(url);
|
|
});
|
|
|
|
it('should return the UUID', () => {
|
|
expect(result).toEqual('9a364471-3f19-4e7b-916a-a24a44ff48e3');
|
|
});
|
|
});
|
|
|
|
describe('when the navigated URL is an item route', () => {
|
|
beforeEach(() => {
|
|
url = '/items/9a364471-3f19-4e7b-916a-a24a44ff48e3';
|
|
result = (comp as any).getDsoUUIDFromUrl(url);
|
|
});
|
|
|
|
it('should return the UUID', () => {
|
|
expect(result).toEqual('9a364471-3f19-4e7b-916a-a24a44ff48e3');
|
|
});
|
|
});
|
|
|
|
describe('when the navigated URL is an invalid route', () => {
|
|
beforeEach(() => {
|
|
url = '/invalid/object/route/9a364471-3f19-4e7b-916a-a24a44ff48e3';
|
|
result = (comp as any).getDsoUUIDFromUrl(url);
|
|
});
|
|
|
|
it('should return null', () => {
|
|
expect(result).toBeNull();
|
|
});
|
|
});
|
|
});
|
|
});
|