diff --git a/src/app/+community-page/community-page.resolver.spec.ts b/src/app/+community-page/community-page.resolver.spec.ts new file mode 100644 index 0000000000..aa6e9d9c1f --- /dev/null +++ b/src/app/+community-page/community-page.resolver.spec.ts @@ -0,0 +1,28 @@ +import { of as observableOf } from 'rxjs'; +import { first } from 'rxjs/operators'; +import { CommunityPageResolver } from './community-page.resolver'; + +describe('CommunityPageResolver', () => { + describe('resolve', () => { + let resolver: CommunityPageResolver; + let communityService: any; + const uuid = '1234-65487-12354-1235'; + + beforeEach(() => { + communityService = { + findById: (id: string) => observableOf({ payload: { id }, hasSucceeded: true }) + }; + resolver = new CommunityPageResolver(communityService); + }); + + it('should resolve a community with the correct id', () => { + resolver.resolve({ params: { id: uuid } } as any, undefined) + .pipe(first()) + .subscribe( + (resolved) => { + expect(resolved.payload.id).toEqual(uuid); + } + ); + }); + }); +}); diff --git a/src/app/+item-page/edit-item-page/edit-item-page.module.ts b/src/app/+item-page/edit-item-page/edit-item-page.module.ts index 4e1636e28a..71924cf6c8 100644 --- a/src/app/+item-page/edit-item-page/edit-item-page.module.ts +++ b/src/app/+item-page/edit-item-page/edit-item-page.module.ts @@ -22,7 +22,6 @@ import { EditRelationshipComponent } from './item-relationships/edit-relationshi import { EditRelationshipListComponent } from './item-relationships/edit-relationship-list/edit-relationship-list.component'; import { ItemMoveComponent } from './item-move/item-move.component'; import { VirtualMetadataComponent } from './virtual-metadata/virtual-metadata.component'; -import { MySimpleItemActionComponent } from './simple-item-action/abstract-simple-item-action.component.spec'; /** * Module that contains all components related to the Edit Item page administrator functionality @@ -54,7 +53,6 @@ import { MySimpleItemActionComponent } from './simple-item-action/abstract-simpl ItemCollectionMapperComponent, ItemMoveComponent, VirtualMetadataComponent, - MySimpleItemActionComponent ] }) export class EditItemPageModule { diff --git a/src/app/core/cache/builders/remote-data-build.service.ts b/src/app/core/cache/builders/remote-data-build.service.ts index 48f5e2ea07..55538ab70a 100644 --- a/src/app/core/cache/builders/remote-data-build.service.ts +++ b/src/app/core/cache/builders/remote-data-build.service.ts @@ -1,8 +1,6 @@ import { Injectable } from '@angular/core'; - import { combineLatest as observableCombineLatest, Observable, of as observableOf, race as observableRace } from 'rxjs'; import { distinctUntilChanged, map, startWith, switchMap } from 'rxjs/operators'; - import { hasNoValue, hasValue, @@ -40,6 +38,12 @@ export class RemoteDataBuildService { protected requestService: RequestService) { } + /** + * Creates a single {@link RemoteData} object based on the response of a request to the REST server, with a list of + * {@link FollowLinkConfig} that indicate which embedded info should be added to the object + * @param href$ Observable href of object we want to retrieve + * @param linksToFollow List of {@link FollowLinkConfig} that indicate which embedded info should be added + */ buildSingle(href$: string | Observable, ...linksToFollow: Array>): Observable> { if (typeof href$ === 'string') { href$ = observableOf(href$); @@ -118,6 +122,12 @@ export class RemoteDataBuildService { ); } + /** + * Creates a list of {@link RemoteData} objects based on the response of a request to the REST server, with a list of + * {@link FollowLinkConfig} that indicate which embedded info should be added to the objects + * @param href$ Observable href of objects we want to retrieve + * @param linksToFollow List of {@link FollowLinkConfig} that indicate which embedded info should be added + */ buildList(href$: string | Observable, ...linksToFollow: Array>): Observable>> { if (typeof href$ === 'string') { href$ = observableOf(href$); diff --git a/src/app/core/data/collection-data.service.ts b/src/app/core/data/collection-data.service.ts index 38d2d72756..19c825a943 100644 --- a/src/app/core/data/collection-data.service.ts +++ b/src/app/core/data/collection-data.service.ts @@ -243,6 +243,10 @@ export class CollectionDataService extends ComColDataService { ); } + /** + * Returns {@link RemoteData} of {@link Collection} that is the owing collection of the given item + * @param item Item we want the owning collection of + */ findOwningCollectionFor(item: Item): Observable> { return this.findByHref(item._links.owningCollection.href); } diff --git a/src/app/core/data/comcol-data.service.spec.ts b/src/app/core/data/comcol-data.service.spec.ts index 624c88fe45..4d1cd05489 100644 --- a/src/app/core/data/comcol-data.service.spec.ts +++ b/src/app/core/data/comcol-data.service.spec.ts @@ -167,13 +167,12 @@ describe('ComColDataService', () => { expect(objectCache.getObjectByUUID).toHaveBeenCalledWith(scopeID); }); - // TODO fix - // it('should return the endpoint to fetch resources within the given scope', () => { - // const result = service.getBrowseEndpoint(options); - // const expected = '--e-'; - // - // scheduler.expectObservable(result).toBe(expected, { e: scopedEndpoint }); - // }); + it('should return the endpoint to fetch resources within the given scope', () => { + const result = service.getBrowseEndpoint(options); + const expected = '--e-'; + + scheduler.expectObservable(result).toBe(expected, { e: scopedEndpoint }); + }); }); describe('if the scope Community can\'t be found', () => { diff --git a/src/app/core/data/data.service.ts b/src/app/core/data/data.service.ts index 60fd5e4ed7..9e9560705a 100644 --- a/src/app/core/data/data.service.ts +++ b/src/app/core/data/data.service.ts @@ -1,5 +1,6 @@ import { HttpClient } from '@angular/common/http'; - +import { Store } from '@ngrx/store'; +import { Operation } from 'fast-json-patch'; import { Observable } from 'rxjs'; import { distinctUntilChanged, @@ -13,13 +14,30 @@ import { take, tap } from 'rxjs/operators'; -import { Store } from '@ngrx/store'; - import { hasValue, isNotEmpty, isNotEmptyOperator } from '../../shared/empty.util'; +import { NotificationOptions } from '../../shared/notifications/models/notification-options.model'; +import { NotificationsService } from '../../shared/notifications/notifications.service'; import { FollowLinkConfig } from '../../shared/utils/follow-link-config.model'; +import { getMapsToType } from '../cache/builders/build-decorators'; +import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service'; import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service'; +import { NormalizedObject } from '../cache/models/normalized-object.model'; +import { SearchParam } from '../cache/models/search-param.model'; +import { CacheableObject } from '../cache/object-cache.reducer'; +import { ObjectCacheService } from '../cache/object-cache.service'; +import { ErrorResponse, RestResponse } from '../cache/response.models'; +import { CoreState } from '../core.reducers'; +import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer'; +import { DSpaceObject } from '../shared/dspace-object.model'; import { HALEndpointService } from '../shared/hal-endpoint.service'; +import { + configureRequest, + getRemoteDataPayload, + getResponseFromEntry, + getSucceededRemoteData +} from '../shared/operators'; import { URLCombiner } from '../url-combiner/url-combiner'; +import { ChangeAnalyzer } from './change-analyzer'; import { PaginatedList } from './paginated-list'; import { RemoteData } from './remote-data'; import { @@ -30,24 +48,9 @@ import { FindListRequest, GetRequest } from './request.models'; -import { RequestService } from './request.service'; -import { NormalizedObject } from '../cache/models/normalized-object.model'; -import { SearchParam } from '../cache/models/search-param.model'; -import { Operation } from 'fast-json-patch'; -import { ObjectCacheService } from '../cache/object-cache.service'; -import { DSpaceObject } from '../shared/dspace-object.model'; -import { NotificationsService } from '../../shared/notifications/notifications.service'; -import { configureRequest, getRemoteDataPayload, getResponseFromEntry, getSucceededRemoteData } from '../shared/operators'; -import { ErrorResponse, RestResponse } from '../cache/response.models'; -import { NotificationOptions } from '../../shared/notifications/models/notification-options.model'; -import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer'; -import { CacheableObject } from '../cache/object-cache.reducer'; import { RequestEntry } from './request.reducer'; -import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service'; -import { ChangeAnalyzer } from './change-analyzer'; +import { RequestService } from './request.service'; import { RestRequestMethod } from './rest-request-method'; -import { getMapsToType } from '../cache/builders/build-decorators'; -import { CoreState } from '../core.reducers'; export abstract class DataService { protected abstract requestService: RequestService; @@ -60,6 +63,7 @@ export abstract class DataService { protected abstract notificationsService: NotificationsService; protected abstract http: HttpClient; protected abstract comparator: ChangeAnalyzer; + /** * Allows subclasses to reset the response cache time. */ @@ -148,10 +152,21 @@ export abstract class DataService { } } + /** + * Returns {@link RemoteData} of all object with a list of {@link FollowLinkConfig}, to indicate which embedded + * info should be added to the objects + * @param linksToFollow List of {@link FollowLinkConfig} to indicate which embedded info should be retrieved and added + */ findAll(options: FindListOptions = {}, ...linksToFollow: Array>): Observable>> { return this.findList(this.getFindAllHref(options), options, ...linksToFollow); } + /** + * Returns an observable of {@link RemoteData} of an object, based on href observable, + * with a list of {@link FollowLinkConfig}, to add embedded info to the object + * @param href$ Observable of href of object we want to retrieve + * @param linksToFollow List of {@link FollowLinkConfig} to indicate which embedded info should be retrieved and added + */ protected findList(href$, options: FindListOptions, ...linksToFollow: Array>) { href$.pipe( first((href: string) => hasValue(href))) @@ -175,6 +190,12 @@ export abstract class DataService { return `${endpoint}/${resourceID}`; } + /** + * Returns an observable of {@link RemoteData} of an object, based on its ID, with a list of {@link FollowLinkConfig}, + * to add embedded info to the object + * @param id ID of object we want to retrieve + * @param linksToFollow List of {@link FollowLinkConfig} to indicate which embedded info should be retrieved and added + */ findById(id: string, ...linksToFollow: Array>): Observable> { const hrefObs = this.halService.getEndpoint(this.linkPath).pipe( @@ -193,6 +214,12 @@ export abstract class DataService { return this.rdbService.buildSingle(hrefObs, ...linksToFollow); } + /** + * Returns an observable of {@link RemoteData} of an object, based on an href, with a list of {@link FollowLinkConfig}, + * to add embedded info to the object + * @param href Href of object we want to retrieve + * @param linksToFollow List of {@link FollowLinkConfig} to indicate which embedded info should be retrieved and added + */ findByHref(href: string, ...linksToFollow: Array>): Observable> { const requestHref = this.buildHrefFromFindOptions(href, {}, []); const request = new GetRequest(this.requestService.generateRequestId(), requestHref); @@ -203,6 +230,12 @@ export abstract class DataService { return this.rdbService.buildSingle(href, ...linksToFollow); } + /** + * Returns a list of observables of {@link RemoteData} of objects, based on an href, with a list of {@link FollowLinkConfig}, + * to add embedded info to the object + * @param id ID of object we want to retrieve + * @param linksToFollow List of {@link FollowLinkConfig} to indicate which embedded info should be retrieved and added + */ findAllByHref(href: string, findListOptions: FindListOptions = {}, ...linksToFollow: Array>): Observable>> { const requestHref = this.buildHrefFromFindOptions(href, findListOptions, []); const request = new GetRequest(this.requestService.generateRequestId(), requestHref); @@ -274,13 +307,13 @@ export abstract class DataService { getSucceededRemoteData(), getRemoteDataPayload(), mergeMap((oldVersion: T) => { - const operations = this.comparator.diff(oldVersion, object); - if (isNotEmpty(operations)) { - this.objectCache.addPatch(object.self, operations); + const operations = this.comparator.diff(oldVersion, object); + if (isNotEmpty(operations)) { + this.objectCache.addPatch(object.self, operations); + } + return this.findByHref(object.self); } - return this.findByHref(object.self); - } - )); + )); } /** diff --git a/src/app/core/data/request.reducer.spec.ts b/src/app/core/data/request.reducer.spec.ts index f79618d48d..d32fe348b5 100644 --- a/src/app/core/data/request.reducer.spec.ts +++ b/src/app/core/data/request.reducer.spec.ts @@ -1,4 +1,3 @@ -// TODO Fix on complete test run import * as deepFreeze from 'deep-freeze'; import { RestResponse } from '../cache/response.models'; import { @@ -38,7 +37,6 @@ describe('requestReducer', () => { }; deepFreeze(testState); - // TODO Fix it('should return the current state when no valid actions have been made', () => { const action = new NullAction(); const newState = requestReducer(testState, action); diff --git a/src/app/core/data/request.service.spec.ts b/src/app/core/data/request.service.spec.ts index 9d83af91d7..017721fdf9 100644 --- a/src/app/core/data/request.service.spec.ts +++ b/src/app/core/data/request.service.spec.ts @@ -1,4 +1,3 @@ -// TODO Fix on complete test run import * as ngrx from '@ngrx/store'; import { ActionsSubject, Store } from '@ngrx/store'; import { cold, getTestScheduler, hot } from 'jasmine-marbles'; diff --git a/src/app/core/data/resource-policy.service.spec.ts b/src/app/core/data/resource-policy.service.spec.ts index 1a02171be3..56918fd941 100644 --- a/src/app/core/data/resource-policy.service.spec.ts +++ b/src/app/core/data/resource-policy.service.spec.ts @@ -1,15 +1,15 @@ +import { HttpClient } from '@angular/common/http'; import { cold, getTestScheduler } from 'jasmine-marbles'; import { TestScheduler } from 'rxjs/testing'; +import { NotificationsService } from '../../shared/notifications/notifications.service'; +import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service'; import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service'; -import { ResourcePolicy } from '../shared/resource-policy.model'; +import { ObjectCacheService } from '../cache/object-cache.service'; import { HALEndpointService } from '../shared/hal-endpoint.service'; +import { ResourcePolicy } from '../shared/resource-policy.model'; import { GetRequest } from './request.models'; import { RequestService } from './request.service'; import { ResourcePolicyService } from './resource-policy.service'; -import { ObjectCacheService } from '../cache/object-cache.service'; -import { NotificationsService } from '../../shared/notifications/notifications.service'; -import { HttpClient } from '@angular/common/http'; -import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service'; describe('ResourcePolicyService', () => { let scheduler: TestScheduler; @@ -61,7 +61,7 @@ describe('ResourcePolicyService', () => { scheduler.schedule(() => service.findByHref(requestURL)); scheduler.flush(); - expect(requestService.configure).toHaveBeenCalledWith(new GetRequest(requestUUID, requestURL, null)); + expect(requestService.configure).toHaveBeenCalledWith(new GetRequest(requestUUID, requestURL, {})); }); it('should return a RemoteData for the object with the given URL', () => { diff --git a/src/app/shared/testing/test-module.ts b/src/app/shared/testing/test-module.ts index f097540c8e..f25fda8d72 100644 --- a/src/app/shared/testing/test-module.ts +++ b/src/app/shared/testing/test-module.ts @@ -1,10 +1,10 @@ -import {CUSTOM_ELEMENTS_SCHEMA, NgModule} from '@angular/core'; -import { QueryParamsDirectiveStub } from './query-params-directive-stub'; -// import { MySimpleItemActionComponent } from '../../+item-page/edit-item-page/simple-item-action/abstract-simple-item-action.component.spec'; -import {CommonModule} from '@angular/common'; -import {SharedModule} from '../shared.module'; -import { RouterLinkDirectiveStub } from './router-link-directive-stub'; +import { CommonModule } from '@angular/common'; +import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core'; +import { MySimpleItemActionComponent } from '../../+item-page/edit-item-page/simple-item-action/abstract-simple-item-action.component.spec'; +import { SharedModule } from '../shared.module'; import { NgComponentOutletDirectiveStub } from './ng-component-outlet-directive-stub'; +import { QueryParamsDirectiveStub } from './query-params-directive-stub'; +import { RouterLinkDirectiveStub } from './router-link-directive-stub'; /** * This module isn't used. It serves to prevent the AoT compiler @@ -19,11 +19,12 @@ import { NgComponentOutletDirectiveStub } from './ng-component-outlet-directive- ], declarations: [ QueryParamsDirectiveStub, - // MySimpleItemActionComponent, + MySimpleItemActionComponent, RouterLinkDirectiveStub, NgComponentOutletDirectiveStub ], schemas: [ CUSTOM_ELEMENTS_SCHEMA ] }) -export class TestModule {} +export class TestModule { +}