diff --git a/src/app/shared/comcol-forms/create-comcol-page/create-comcol-page.component.spec.ts b/src/app/shared/comcol-forms/create-comcol-page/create-comcol-page.component.spec.ts index 780589d0c5..d2335f623f 100644 --- a/src/app/shared/comcol-forms/create-comcol-page/create-comcol-page.component.spec.ts +++ b/src/app/shared/comcol-forms/create-comcol-page/create-comcol-page.component.spec.ts @@ -2,7 +2,7 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { CommunityDataService } from '../../../core/data/community-data.service'; import { RouteService } from '../../../core/services/route.service'; import { Router } from '@angular/router'; -import { TranslateModule } from '@ngx-translate/core'; +import {TranslateModule, TranslateService} from '@ngx-translate/core'; import { of as observableOf } from 'rxjs'; import { Community } from '../../../core/shared/community.model'; import { SharedModule } from '../../shared.module'; @@ -12,12 +12,14 @@ import { NO_ERRORS_SCHEMA } from '@angular/core'; import { DSpaceObject } from '../../../core/shared/dspace-object.model'; import { CreateComColPageComponent } from './create-comcol-page.component'; import { - createFailedRemoteDataObject$, + createFailedRemoteDataObject$, createNoContentRemoteDataObject$, createSuccessfulRemoteDataObject$ } from '../../remote-data.utils'; import { ComColDataService } from '../../../core/data/comcol-data.service'; import { NotificationsService } from '../../notifications/notifications.service'; import { NotificationsServiceStub } from '../../testing/notifications-service.stub'; +import { RequestService } from '../../../core/data/request.service'; +import {getTestScheduler} from 'jasmine-marbles'; describe('CreateComColPageComponent', () => { let comp: CreateComColPageComponent; @@ -29,9 +31,11 @@ describe('CreateComColPageComponent', () => { let community; let newCommunity; + let parentCommunity; let communityDataServiceStub; let routeServiceStub; let routerStub; + let requestServiceStub; const logoEndpoint = 'rest/api/logo/endpoint'; @@ -44,6 +48,15 @@ describe('CreateComColPageComponent', () => { }] }); + parentCommunity = Object.assign(new Community(), { + uuid: 'a20da287-e174-466a-9926-f66as300d399', + id: 'a20da287-e174-466a-9926-f66as300d399', + metadata: [{ + key: 'dc.title', + value: 'parent community' + }] + }); + newCommunity = Object.assign(new Community(), { uuid: '1ff59938-a69a-4e62-b9a4-718569c55d48', metadata: [{ @@ -61,7 +74,8 @@ describe('CreateComColPageComponent', () => { }] })), create: (com, uuid?) => createSuccessfulRemoteDataObject$(newCommunity), - getLogoEndpoint: () => observableOf(logoEndpoint) + getLogoEndpoint: () => observableOf(logoEndpoint), + findByHref: () => null }; routeServiceStub = { @@ -71,6 +85,10 @@ describe('CreateComColPageComponent', () => { navigate: (commands) => commands }; + requestServiceStub = jasmine.createSpyObj('RequestService', { + removeByHrefSubstring: jasmine.createSpy('removeByHrefSubstring'), + }); + } beforeEach(async(() => { @@ -82,7 +100,9 @@ describe('CreateComColPageComponent', () => { { provide: CommunityDataService, useValue: communityDataServiceStub }, { provide: RouteService, useValue: routeServiceStub }, { provide: Router, useValue: routerStub }, - { provide: NotificationsService, useValue: new NotificationsServiceStub() } + { provide: NotificationsService, useValue: new NotificationsServiceStub() }, + { provide: TranslateService, useValue: {}}, + { provide: RequestService, useValue: requestServiceStub} ], schemas: [NO_ERRORS_SCHEMA] }).compileComponents(); @@ -123,19 +143,23 @@ describe('CreateComColPageComponent', () => { }; }); - it('should navigate when successful', () => { + it('should navigate and refresh cache when successful', () => { spyOn(router, 'navigate'); + spyOn((comp as any), 'refreshCache'); comp.onSubmit(data); fixture.detectChanges(); expect(router.navigate).toHaveBeenCalled(); + expect((comp as any).refreshCache).toHaveBeenCalled(); }); - it('should not navigate on failure', () => { + it('should neither navigate nor refresh cache on failure', () => { spyOn(router, 'navigate'); spyOn(dsoDataService, 'create').and.returnValue(createFailedRemoteDataObject$(newCommunity)); + spyOn((comp as any), 'refreshCache') comp.onSubmit(data); fixture.detectChanges(); expect(router.navigate).not.toHaveBeenCalled(); + expect((comp as any).refreshCache).not.toHaveBeenCalled(); }); }); @@ -182,5 +206,77 @@ describe('CreateComColPageComponent', () => { expect(data.uploader.uploadAll).toHaveBeenCalled(); }); }); + + describe('cache refresh', () => { + let scheduler; + let communityWithoutParentHref; + + beforeEach(() => { + scheduler = getTestScheduler(); + + }) + describe('cache refreshed top level community', () => { + beforeEach(() => { + spyOn(dsoDataService, 'findByHref').and.returnValue(createNoContentRemoteDataObject$()); + data = { + dso: Object.assign(new Community(), { + metadata: [{ + key: 'dc.title', + value: 'top level community' + }] + }), + _links: { + parentCommunity: { + href: 'topLevel/parentCommunity' + } + } + }; + communityWithoutParentHref = { + dso: Object.assign(new Community(), { + metadata: [{ + key: 'dc.title', + value: 'top level community' + }] + }), + _links: {} + }; + }); + it('top level community cache refreshed', () => { + scheduler.schedule(() => (comp as any).refreshCache(data)); + scheduler.flush(); + expect(requestServiceStub.removeByHrefSubstring).toHaveBeenCalledWith('communities/search/top'); + }); + it('top level community without parent link, cache not refreshed', () => { + scheduler.schedule(() => (comp as any).refreshCache(communityWithoutParentHref)); + scheduler.flush(); + expect(requestServiceStub.removeByHrefSubstring).not.toHaveBeenCalled(); + }); + }); + + describe('cache refreshed child community', () => { + beforeEach(() => { + spyOn(dsoDataService, 'findByHref').and.returnValue(createSuccessfulRemoteDataObject$(parentCommunity)); + data = { + dso: Object.assign(new Community(), { + metadata: [{ + key: 'dc.title', + value: 'child community' + }] + }), + _links: { + parentCommunity: { + href: 'child/parentCommunity' + } + } + }; + }); + it('child level community cache refreshed', () => { + scheduler.schedule(() => (comp as any).refreshCache(data)); + scheduler.flush(); + expect(requestServiceStub.removeByHrefSubstring).toHaveBeenCalledWith('a20da287-e174-466a-9926-f66as300d399'); + }); + }); + }); + }); }); diff --git a/src/app/shared/comcol-forms/create-comcol-page/create-comcol-page.component.ts b/src/app/shared/comcol-forms/create-comcol-page/create-comcol-page.component.ts index f55a7f0156..336998aab3 100644 --- a/src/app/shared/comcol-forms/create-comcol-page/create-comcol-page.component.ts +++ b/src/app/shared/comcol-forms/create-comcol-page/create-comcol-page.component.ts @@ -11,8 +11,7 @@ import { Community } from '../../../core/shared/community.model'; import { DSpaceObject } from '../../../core/shared/dspace-object.model'; import { getFirstSucceededRemoteDataPayload, - getRemoteDataPayload, - getSucceededRemoteData + getSucceededOrNoContentResponse, } from '../../../core/shared/operators'; import { ResourceType } from '../../../core/shared/resource-type'; import {hasValue, isEmpty, isNotEmpty, isNotUndefined} from '../../empty.util'; @@ -123,11 +122,12 @@ export class CreateComColPageComponent implements return; } this.dsoDataService.findByHref(parentCommunityUrl).pipe( - getSucceededRemoteData(), - getRemoteDataPayload(), - map((pc: TDomain) => isEmpty(pc) ? 'communities/search/top' : pc.id), - take(1) - ).subscribe((href: string) => this.requestService.removeByHrefSubstring(href)); + getSucceededOrNoContentResponse(), + take(1), + ).subscribe((rd: RemoteData) => { + const href = rd.hasSucceeded && !isEmpty(rd.payload.id) ? rd.payload.id : 'communities/search/top'; + this.requestService.removeByHrefSubstring(href) + }); } private parentCommunityUrl(dso: Collection | Community) { diff --git a/src/app/shared/comcol-forms/delete-comcol-page/delete-comcol-page.component.spec.ts b/src/app/shared/comcol-forms/delete-comcol-page/delete-comcol-page.component.spec.ts index e791f41d56..9da77df007 100644 --- a/src/app/shared/comcol-forms/delete-comcol-page/delete-comcol-page.component.spec.ts +++ b/src/app/shared/comcol-forms/delete-comcol-page/delete-comcol-page.component.spec.ts @@ -1,7 +1,7 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { CommunityDataService } from '../../../core/data/community-data.service'; import { ActivatedRoute, Router } from '@angular/router'; -import { TranslateModule } from '@ngx-translate/core'; +import {TranslateModule, TranslateService} from '@ngx-translate/core'; import { of as observableOf } from 'rxjs'; import { Community } from '../../../core/shared/community.model'; import { SharedModule } from '../../shared.module'; @@ -13,6 +13,9 @@ import { DataService } from '../../../core/data/data.service'; import { DeleteComColPageComponent } from './delete-comcol-page.component'; import { NotificationsService } from '../../notifications/notifications.service'; import { NotificationsServiceStub } from '../../testing/notifications-service.stub'; +import {RequestService} from '../../../core/data/request.service'; +import {getTestScheduler} from 'jasmine-marbles'; +import {createNoContentRemoteDataObject$, createSuccessfulRemoteDataObject$} from '../../remote-data.utils'; describe('DeleteComColPageComponent', () => { let comp: DeleteComColPageComponent; @@ -22,9 +25,13 @@ describe('DeleteComColPageComponent', () => { let community; let newCommunity; + let parentCommunity; let routerStub; let routeStub; let notificationsService; + let translateServiceStub; + let requestServiceStub; + const validUUID = 'valid-uuid'; const invalidUUID = 'invalid-uuid'; const frontendURL = '/testType'; @@ -45,10 +52,20 @@ describe('DeleteComColPageComponent', () => { }] }); + parentCommunity = Object.assign(new Community(), { + uuid: 'a20da287-e174-466a-9926-f66as300d399', + id: 'a20da287-e174-466a-9926-f66as300d399', + metadata: [{ + key: 'dc.title', + value: 'parent community' + }] + }); + dsoDataService = jasmine.createSpyObj( 'dsoDataService', { - delete: observableOf({ isSuccessful: true }) + delete: observableOf({ isSuccessful: true }), + findByHref: jasmine.createSpy('findByHref') }); routerStub = { @@ -59,6 +76,14 @@ describe('DeleteComColPageComponent', () => { data: observableOf(community) }; + requestServiceStub = jasmine.createSpyObj('RequestService', { + removeByHrefSubstring: jasmine.createSpy('removeByHrefSubstring') + }); + + translateServiceStub = jasmine.createSpyObj('TranslateService', { + instant: jasmine.createSpy('instant') + }); + } beforeEach(async(() => { @@ -70,6 +95,8 @@ describe('DeleteComColPageComponent', () => { { provide: Router, useValue: routerStub }, { provide: ActivatedRoute, useValue: routeStub }, { provide: NotificationsService, useValue: new NotificationsServiceStub() }, + { provide: TranslateService, useValue: translateServiceStub}, + { provide: RequestService, useValue: requestServiceStub} ], schemas: [NO_ERRORS_SCHEMA] }).compileComponents(); @@ -108,17 +135,21 @@ describe('DeleteComColPageComponent', () => { it('should show an error notification on failure', () => { (dsoDataService.delete as any).and.returnValue(observableOf({ isSuccessful: false })); spyOn(router, 'navigate'); + spyOn((comp as any), 'refreshCache'); comp.onConfirm(data2); fixture.detectChanges(); expect(notificationsService.error).toHaveBeenCalled(); + expect((comp as any).refreshCache).not.toHaveBeenCalled(); expect(router.navigate).toHaveBeenCalled(); }); it('should show a success notification on success and navigate', () => { spyOn(router, 'navigate'); + spyOn((comp as any), 'refreshCache'); comp.onConfirm(data1); fixture.detectChanges(); expect(notificationsService.success).toHaveBeenCalled(); + expect((comp as any).refreshCache).toHaveBeenCalled(); expect(router.navigate).toHaveBeenCalled(); }); @@ -127,6 +158,78 @@ describe('DeleteComColPageComponent', () => { fixture.detectChanges(); expect(dsoDataService.delete).toHaveBeenCalledWith(data1.id); }); + + describe('cache refresh', () => { + let scheduler; + let communityWithoutParentHref; + let deletedCommunity; + + beforeEach(() => { + scheduler = getTestScheduler(); + + }) + describe('cache refreshed top level community', () => { + beforeEach(() => { + (dsoDataService.findByHref as any).and.returnValue(createNoContentRemoteDataObject$()); + deletedCommunity = { + dso: Object.assign(new Community(), { + metadata: [{ + key: 'dc.title', + value: 'top level community' + }] + }), + _links: { + parentCommunity: { + href: 'topLevel/parentCommunity' + } + } + }; + communityWithoutParentHref = { + dso: Object.assign(new Community(), { + metadata: [{ + key: 'dc.title', + value: 'top level community' + }] + }), + _links: {} + }; + }); + it('top level community cache refreshed', () => { + scheduler.schedule(() => (comp as any).refreshCache(deletedCommunity)); + scheduler.flush(); + expect(requestServiceStub.removeByHrefSubstring).toHaveBeenCalledWith('communities/search/top'); + }); + it('top level community without parent link, cache not refreshed', () => { + scheduler.schedule(() => (comp as any).refreshCache(communityWithoutParentHref)); + scheduler.flush(); + expect(requestServiceStub.removeByHrefSubstring).not.toHaveBeenCalled(); + }); + }); + + describe('cache refreshed child community', () => { + beforeEach(() => { + (dsoDataService.findByHref as any).and.returnValue(createSuccessfulRemoteDataObject$(parentCommunity)); + deletedCommunity = { + dso: Object.assign(new Community(), { + metadata: [{ + key: 'dc.title', + value: 'child community' + }] + }), + _links: { + parentCommunity: { + href: 'child/parentCommunity' + } + } + }; + }); + it('child level community cache refreshed', () => { + scheduler.schedule(() => (comp as any).refreshCache(deletedCommunity)); + scheduler.flush(); + expect(requestServiceStub.removeByHrefSubstring).toHaveBeenCalledWith('a20da287-e174-466a-9926-f66as300d399'); + }); + }); + }); }); describe('onCancel', () => { diff --git a/src/app/shared/comcol-forms/delete-comcol-page/delete-comcol-page.component.ts b/src/app/shared/comcol-forms/delete-comcol-page/delete-comcol-page.component.ts index 29ec4f7b19..835d302de3 100644 --- a/src/app/shared/comcol-forms/delete-comcol-page/delete-comcol-page.component.ts +++ b/src/app/shared/comcol-forms/delete-comcol-page/delete-comcol-page.component.ts @@ -10,7 +10,9 @@ import {TranslateService} from '@ngx-translate/core'; import {RestResponse} from '../../../core/cache/response.models'; import {hasValue, isEmpty, isNotEmpty} from '../../empty.util'; import {RequestService} from '../../../core/data/request.service'; -import {getRemoteDataPayload, getSucceededRemoteData} from '../../../core/shared/operators'; +import { + getSucceededOrNoContentResponse, +} from '../../../core/shared/operators'; import {Community} from '../../../core/shared/community.model'; import {Collection} from '../../../core/shared/collection.model'; @@ -74,16 +76,17 @@ export class DeleteComColPageComponent implements } private refreshCache(dso: TDomain) { - const parentCommunity = this.parentCommunityUrl(dso as any); - if (!hasValue(parentCommunity)) { + const parentCommunityUrl = this.parentCommunityUrl(dso as any); + if (!hasValue(parentCommunityUrl)) { return; } - this.dsoDataService.findByHref(parentCommunity).pipe( - getSucceededRemoteData(), - getRemoteDataPayload(), - map((pc: TDomain) => isEmpty(pc) ? 'communities/search/top' : pc.id ), - take(1) - ).subscribe((id: string) => this.requestService.removeByHrefSubstring(id)); + this.dsoDataService.findByHref(parentCommunityUrl).pipe( + getSucceededOrNoContentResponse(), + take(1), + ).subscribe((rd: RemoteData) => { + const href = rd.hasSucceeded && !isEmpty(rd.payload.id) ? rd.payload.id : 'communities/search/top'; + this.requestService.removeByHrefSubstring(href) + }); } private parentCommunityUrl(dso: Collection | Community): string {