1
0

[CSTPER-3620] Workflow Actions refresh entire MyDSpace page instead of just WorkflowItem

Fixed test after angular 10 migration
This commit is contained in:
Alessandro Martelli
2021-01-29 18:45:41 +01:00
parent 5ef5a27e2b
commit c65dfc7303
12 changed files with 55 additions and 51 deletions

View File

@@ -14,12 +14,16 @@ import { ClaimedTaskSearchResultDetailElementComponent } from '../shared/object-
import { ItemSearchResultListElementSubmissionComponent } from '../shared/object-list/my-dspace-result-list-element/item-search-result/item-search-result-list-element-submission.component';
import { WorkflowItemSearchResultListElementComponent } from '../shared/object-list/my-dspace-result-list-element/workflow-item-search-result/workflow-item-search-result-list-element.component';
import { PoolSearchResultDetailElementComponent } from '../shared/object-detail/my-dspace-result-detail-element/pool-search-result/pool-search-result-detail-element.component';
import { ClaimedApprovedSearchResultListElementComponent } from '../shared/object-list/my-dspace-result-list-element/claimed-search-result/claimed-approved-search-result/claimed-approved-search-result-list-element.component';
import { ClaimedDeclinedSearchResultListElementComponent } from '../shared/object-list/my-dspace-result-list-element/claimed-search-result/claimed-declined-search-result/claimed-declined-search-result-list-element.component';
const ENTRY_COMPONENTS = [
// put only entry components that use custom decorator
WorkspaceItemSearchResultListElementComponent,
WorkflowItemSearchResultListElementComponent,
ClaimedSearchResultListElementComponent,
ClaimedApprovedSearchResultListElementComponent,
ClaimedDeclinedSearchResultListElementComponent,
PoolSearchResultListElementComponent,
ItemSearchResultDetailElementComponent,
WorkspaceItemSearchResultDetailElementComponent,

View File

@@ -1,18 +1,17 @@
import { HttpHeaders } from '@angular/common/http';
import { Observable } from 'rxjs';
import { distinctUntilChanged, filter, map, mergeMap, tap } from 'rxjs/operators';
import { distinctUntilChanged, filter, find, map, mergeMap, switchMap, tap } from 'rxjs/operators';
import { DataService } from '../data/data.service';
import { DeleteRequest, PostRequest, TaskDeleteRequest, TaskPostRequest } from '../data/request.models';
import { isNotEmpty } from '../../shared/empty.util';
import { DeleteRequest, FindListOptions, PostRequest, TaskDeleteRequest, TaskPostRequest } from '../data/request.models';
import { hasValue, isNotEmpty } from '../../shared/empty.util';
import { HttpOptions } from '../dspace-rest/dspace-rest.service';
import { ProcessTaskResponse } from './models/process-task-response';
import { getFirstCompletedRemoteData, getFirstSucceededRemoteData } from '../shared/operators';
import { CacheableObject } from '../cache/object-cache.reducer';
import { RemoteData } from '../data/remote-data';
import { FollowLinkConfig } from '../../shared/utils/follow-link-config.model';
import { HttpOptions } from '../dspace-rest/dspace-rest.service';
/**
* An abstract class that provides methods to handle task requests.
@@ -131,14 +130,14 @@ export abstract class TasksService<T extends CacheableObject> extends DataServic
* @param linksToFollow
* links to follow
*/
public searchTask(searchMethod: string, options: FindListOptions = {}, ...linksToFollow: Array<FollowLinkConfig<T>>): Observable<RemoteData<T>> {
public searchTask(searchMethod: string, options: FindListOptions = {}, ...linksToFollow: FollowLinkConfig<T>[]): Observable<RemoteData<T>> {
const hrefObs = this.getSearchByHref(searchMethod, options, ...linksToFollow);
return hrefObs.pipe(
find((href: string) => hasValue(href)),
switchMap((href) => this.findByHref(href).pipe(
getFirstSucceededRemoteData(),
tap(() => {
this.requestService.setStaleByHrefSubstring(searchMethod)
this.requestService.setStaleByHrefSubstring(searchMethod);
}))),
);
}

View File

@@ -1,4 +1,4 @@
import {Injector, OnDestroy} from '@angular/core';
import { Component, Injector, OnDestroy } from '@angular/core';
import { ClaimedTask } from '../../../../core/tasks/models/claimed-task-object.model';
import { ClaimedTaskDataService } from '../../../../core/tasks/claimed-task-data.service';
import { DSpaceObject} from '../../../../core/shared/dspace-object.model';
@@ -10,7 +10,7 @@ import { RequestService} from '../../../../core/data/request.service';
import { Observable} from 'rxjs';
import { RemoteData} from '../../../../core/data/remote-data';
import { WorkflowItem} from '../../../../core/submission/models/workflowitem.model';
import {switchMap, take} from 'rxjs/operators';
import { switchMap, take } from 'rxjs/operators';
import { CLAIMED_TASK } from '../../../../core/tasks/models/claimed-task-object.resource-type';
import { getFirstSucceededRemoteDataPayload } from '../../../../core/shared/operators';
import { Item } from '../../../../core/shared/item.model';
@@ -23,10 +23,10 @@ import { MyDSpaceReloadableActionsComponent } from '../../mydspace-reloadable-ac
* - Add a @rendersWorkflowTaskOption annotation to your component providing the same enum value
* - Optionally overwrite createBody if the request body requires more than just the option
*/
// @Component({
// selector: 'ds-calim-task-action-abstract',
// template: ''
// })
@Component({
selector: 'ds-claimed-task-action-abstract',
template: ''
})
export abstract class ClaimedTaskActionsAbstractComponent extends MyDSpaceReloadableActionsComponent<ClaimedTask, ClaimedTaskDataService> implements OnDestroy {
/**
@@ -74,7 +74,7 @@ export abstract class ClaimedTaskActionsAbstractComponent extends MyDSpaceReload
}
actionExecution(): Observable<any> {
return this.objectDataService.submitTask(this.object.id, this.createbody())
return this.objectDataService.submitTask(this.object.id, this.createbody());
}
initObjects(object: ClaimedTask) {

View File

@@ -1,6 +1,4 @@
import { ChangeDetectionStrategy, Injector, NO_ERRORS_SCHEMA } from '@angular/core';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core';
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { FormBuilder, FormGroup, ReactiveFormsModule } from '@angular/forms';
import { By } from '@angular/platform-browser';
@@ -39,7 +37,7 @@ let mockPoolTaskDataService: PoolTaskDataService;
describe('ClaimedTaskActionsRejectComponent', () => {
const object = Object.assign(new ClaimedTask(), { id: 'claimed-task-1' });
const claimedTaskService = jasmine.createSpyObj('claimedTaskService', {
submitTask: observableOf(new ProcessTaskResponse(true))
submitTask: of(new ProcessTaskResponse(true))
});
beforeEach(waitForAsync(() => {

View File

@@ -1,5 +1,5 @@
import { ChangeDetectionStrategy, Injector, NO_ERRORS_SCHEMA } from '@angular/core';
import { async, ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { ComponentFixture, fakeAsync, TestBed, waitForAsync } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
@@ -31,7 +31,7 @@ let mockPoolTaskDataService: PoolTaskDataService;
describe('ClaimedTaskActionsReturnToPoolComponent', () => {
const object = Object.assign(new ClaimedTask(), { id: 'claimed-task-1' });
const claimedTaskService = jasmine.createSpyObj('claimedTaskService', {
returnToPoolTask: observableOf(new ProcessTaskResponse(true))
returnToPoolTask: of(new ProcessTaskResponse(true))
});
beforeEach(waitForAsync(() => {
@@ -91,7 +91,7 @@ describe('ClaimedTaskActionsReturnToPoolComponent', () => {
});
it('should call claimedTaskService\'s returnToPoolTask', () => {
expect(claimedTaskService.returnToPoolTask).toHaveBeenCalledWith(object.id)
expect(claimedTaskService.returnToPoolTask).toHaveBeenCalledWith(object.id);
});
});

View File

@@ -1,13 +1,11 @@
import { ClaimedTaskActionsLoaderComponent } from './claimed-task-actions-loader.component';
import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing';
import { ChangeDetectionStrategy, ComponentFactoryResolver, Injector, NO_ERRORS_SCHEMA } from '@angular/core';
import * as decorators from './claimed-task-actions-decorator';
import { ChangeDetectionStrategy, Injector, NO_ERRORS_SCHEMA } from '@angular/core';
import { ClaimedTaskActionsDirective } from './claimed-task-actions.directive';
import { ClaimedTask } from '../../../../core/tasks/models/claimed-task-object.model';
import { TranslateModule } from '@ngx-translate/core';
import { ClaimedTaskActionsEditMetadataComponent } from '../edit-metadata/claimed-task-actions-edit-metadata.component';
import { ClaimedTaskDataService } from '../../../../core/tasks/claimed-task-data.service';
import { spyOnExported } from '../../../testing/utils.test';
import { NotificationsService } from '../../../notifications/notifications.service';
import { NotificationsServiceStub } from '../../../testing/notifications-service.stub';
import { Router } from '@angular/router';
@@ -22,7 +20,6 @@ const searchService = getMockSearchService();
const requestService = getMockRequestService();
//xdescribe
describe('ClaimedTaskActionsLoaderComponent', () => {
let comp: ClaimedTaskActionsLoaderComponent;
let fixture: ComponentFixture<ClaimedTaskActionsLoaderComponent>;
@@ -42,8 +39,7 @@ describe('ClaimedTaskActionsLoaderComponent', () => {
{ provide: Router, useValue: new RouterStub() },
{ provide: SearchService, useValue: searchService },
{ provide: RequestService, useValue: requestService },
{ provide: PoolTaskDataService, useValue: {} },
ComponentFactoryResolver
{ provide: PoolTaskDataService, useValue: {} }
]
}).overrideComponent(ClaimedTaskActionsLoaderComponent, {
set: {
@@ -56,16 +52,16 @@ describe('ClaimedTaskActionsLoaderComponent', () => {
beforeEach(waitForAsync(() => {
fixture = TestBed.createComponent(ClaimedTaskActionsLoaderComponent);
comp = fixture.componentInstance;
comp.object = object;
comp.option = option;
spyOnExported(decorators, 'getComponentByWorkflowTaskOption').and.returnValue(ClaimedTaskActionsEditMetadataComponent);
spyOn(comp, 'getComponentByWorkflowTaskOption').and.returnValue(ClaimedTaskActionsEditMetadataComponent);
fixture.detectChanges();
}));
describe('When the component is rendered', () => {
it('should call the getComponentByWorkflowTaskOption function with the right option', () => {
expect(decorators.getComponentByWorkflowTaskOption).toHaveBeenCalledWith(option);
expect(comp.getComponentByWorkflowTaskOption).toHaveBeenCalledWith(option);
});
});
});

View File

@@ -59,7 +59,8 @@ export class ClaimedTaskActionsLoaderComponent implements OnInit, OnDestroy {
* Fetch, create and initialize the relevant component
*/
ngOnInit(): void {
const comp = getComponentByWorkflowTaskOption(this.option);
const comp = this.getComponentByWorkflowTaskOption(this.option);
if (hasValue(comp)) {
const componentFactory = this.componentFactoryResolver.resolveComponentFactory(comp);
@@ -75,6 +76,10 @@ export class ClaimedTaskActionsLoaderComponent implements OnInit, OnDestroy {
}
}
getComponentByWorkflowTaskOption(option: string) {
return getComponentByWorkflowTaskOption(option);
}
/**
* Unsubscribe from open subscriptions
*/

View File

@@ -1,5 +1,5 @@
import { Router } from '@angular/router';
import { EventEmitter, Injector, Input, Output } from '@angular/core';
import { Component, EventEmitter, Injector, Input, Output } from '@angular/core';
import { find, take, tap } from 'rxjs/operators';
@@ -23,10 +23,10 @@ export interface MyDSpaceActionsResult {
/**
* Abstract class for all different representations of mydspace actions
*/
// @Component({
// selector: 'ds-mydspace-actions-abstract',
// template: ''
// })
@Component({
selector: 'ds-mydspace-actions-abstract',
template: ''
})
export abstract class MyDSpaceActionsComponent<T extends DSpaceObject, TService extends DataService<T>> {
/**

View File

@@ -1,5 +1,5 @@
import { Router } from '@angular/router';
import { Injector, OnInit } from '@angular/core';
import { Component, Injector, OnInit } from '@angular/core';
import { map, switchMap, tap} from 'rxjs/operators';
@@ -18,11 +18,14 @@ import { ProcessTaskResponse } from '../../core/tasks/models/process-task-respon
import { getFirstCompletedRemoteData } from '../../core/shared/operators';
import { getSearchResultFor } from '../search/search-result-element-decorator';
import { MyDSpaceActionsComponent } from './mydspace-actions';
import {Subscription} from 'rxjs/internal/Subscription';
/**
* Abstract class for all different representations of mydspace actions
*/
@Component({
selector: 'ds-mydspace-reloadable-actions',
template: ''
})
export abstract class MyDSpaceReloadableActionsComponent<T extends DSpaceObject, TService extends DataService<T>>
extends MyDSpaceActionsComponent<T, TService> implements OnInit {
@@ -71,7 +74,7 @@ export abstract class MyDSpaceReloadableActionsComponent<T extends DSpaceObject,
this.handleReloadableActionResponse(res.hasSucceeded, reloadedObject);
return reloadedObject;
})
)
);
} else {
this.processing$.next(false);
this.handleReloadableActionResponse(res.hasSucceeded, null);
@@ -131,13 +134,13 @@ export abstract class MyDSpaceReloadableActionsComponent<T extends DSpaceObject,
return this.reloadObjectExecution().pipe(
switchMap((res) => {
if (res instanceof RemoteData) {
return of(res).pipe(getFirstCompletedRemoteData(), map((completed) => completed.payload))
return of(res).pipe(getFirstCompletedRemoteData(), map((completed) => completed.payload));
} else {
return of(res);
}
})).pipe(map((dso) => {
return dso ? this.convertReloadedObject(dso) : dso;
}))
}));
}
}

View File

@@ -5,10 +5,8 @@ import { ListableObject } from '../listable-object.model';
import { GenericConstructor } from '../../../../core/shared/generic-constructor';
import { Context } from '../../../../core/shared/context.model';
import { ViewMode } from '../../../../core/shared/view-mode.model';
import * as listableObjectDecorators from './listable-object.decorator';
import { ItemListElementComponent } from '../../../object-list/item-list-element/item-types/item/item-list-element.component';
import { ListableObjectDirective } from './listable-object.directive';
import { spyOnExported } from '../../../testing/utils.test';
import { TranslateModule } from '@ngx-translate/core';
import { By } from '@angular/platform-browser';
import { Item } from '../../../../core/shared/item.model';
@@ -23,7 +21,6 @@ class TestType extends ListableObject {
}
}
//xdescribe
describe('ListableObjectComponentLoaderComponent', () => {
let comp: ListableObjectComponentLoaderComponent;
let fixture: ComponentFixture<ListableObjectComponentLoaderComponent>;
@@ -33,7 +30,7 @@ describe('ListableObjectComponentLoaderComponent', () => {
imports: [TranslateModule.forRoot()],
declarations: [ListableObjectComponentLoaderComponent, ItemListElementComponent, ListableObjectDirective],
schemas: [NO_ERRORS_SCHEMA],
providers: [ComponentFactoryResolver]
providers: []
}).overrideComponent(ListableObjectComponentLoaderComponent, {
set: {
changeDetection: ChangeDetectionStrategy.Default,
@@ -49,14 +46,14 @@ describe('ListableObjectComponentLoaderComponent', () => {
comp.object = new TestType();
comp.viewMode = testViewMode;
comp.context = testContext;
spyOnExported(listableObjectDecorators, 'getListableObjectComponent').and.returnValue(ItemListElementComponent);
spyOn(comp, 'getComponent').and.returnValue(ItemListElementComponent as any);
fixture.detectChanges();
}));
describe('When the component is rendered', () => {
it('should call the getListableObjectComponent function with the right types, view mode and context', () => {
expect(listableObjectDecorators.getListableObjectComponent).toHaveBeenCalledWith([testType], testViewMode, testContext);
expect(comp.getComponent).toHaveBeenCalledWith([testType], testViewMode, testContext);
});
});
@@ -130,7 +127,7 @@ describe('ListableObjectComponentLoaderComponent', () => {
tick();
expect((comp as any).instantiateComponent).toHaveBeenCalledWith(reloadedObject);
}))
}));
});

View File

@@ -111,7 +111,9 @@ export class ListableObjectComponentLoaderComponent implements OnInit, OnDestroy
this.initBadges();
const componentFactory = this.componentFactoryResolver.resolveComponentFactory(this.getComponent(object));
const component = this.getComponent(object.getRenderTypes(), this.viewMode, this.context);
const componentFactory = this.componentFactoryResolver.resolveComponentFactory(component);
const viewContainerRef = this.listableObjectDirective.viewContainerRef;
viewContainerRef.clear();
@@ -160,7 +162,7 @@ export class ListableObjectComponentLoaderComponent implements OnInit, OnDestroy
* Fetch the component depending on the item's relationship type, view mode and context
* @returns {GenericConstructor<Component>}
*/
private getComponent(object): GenericConstructor<Component> {
return getListableObjectComponent(object.getRenderTypes(), this.viewMode, this.context);
getComponent(object, viewMode: ViewMode, context: Context): GenericConstructor<Component> {
return getListableObjectComponent(object.getRenderTypes(), viewMode, context);
}
}

View File

@@ -1,5 +1,5 @@
import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core';
import { ComponentFixture, TestBed, waitForAsyncfakeAsync, tick } from '@angular/core/testing';
import { ComponentFixture, TestBed, tick, waitForAsync, fakeAsync} from '@angular/core/testing';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { of as observableOf } from 'rxjs';
@@ -105,7 +105,7 @@ describe('ClaimedTaskSearchResultDetailElementComponent', () => {
const actionPayload: any = { reloadedObject: {}};
const actionsComponent = fixture.debugElement.query(By.css('ds-claimed-task-actions'));
actionsComponent.triggerEventHandler('processCompleted', actionPayload)
actionsComponent.triggerEventHandler('processCompleted', actionPayload);
tick();
expect(component.reloadedObject.emit).toHaveBeenCalledWith(actionPayload.reloadedObject);