98535: Added missing tests to the new advanced workflow components

This commit is contained in:
Alexandre Vryghem
2023-01-18 13:45:04 +01:00
parent fe61bb7b6b
commit 572f5ac4c5
6 changed files with 288 additions and 40 deletions

View File

@@ -1,6 +1,6 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { AdvancedWorkflowActionPageComponent } from './advanced-workflow-action-page.component';
import { ActivatedRoute, convertToParamMap } from '@angular/router';
import { ActivatedRoute } from '@angular/router';
import { TranslateModule } from '@ngx-translate/core';
describe('AdvancedWorkflowActionPageComponent', () => {
@@ -20,9 +20,9 @@ describe('AdvancedWorkflowActionPageComponent', () => {
provide: ActivatedRoute,
useValue: {
snapshot: {
queryParams: convertToParamMap({
queryParams: {
workflow: 'testaction',
}),
},
},
},
},

View File

@@ -1,6 +1,9 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { AdvancedWorkflowActionRatingComponent } from './advanced-workflow-action-rating.component';
import { ActivatedRoute, convertToParamMap, Router } from '@angular/router';
import {
AdvancedWorkflowActionRatingComponent,
ADVANCED_WORKFLOW_TASK_OPTION_RATING
} from './advanced-workflow-action-rating.component';
import { ActivatedRoute, Router } from '@angular/router';
import { of as observableOf } from 'rxjs';
import { ClaimedTaskDataService } from '../../../core/tasks/claimed-task-data.service';
import { NotificationsService } from '../../../shared/notifications/notifications.service';
@@ -17,10 +20,19 @@ import { TranslateModule } from '@ngx-translate/core';
import { VarDirective } from '../../../shared/utils/var.directive';
import { RatingModule } from 'ngx-bootstrap/rating';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { WorkflowItem } from '../../../core/submission/models/workflowitem.model';
import { createSuccessfulRemoteDataObject$, createSuccessfulRemoteDataObject } from '../../../shared/remote-data.utils';
import { Item } from '../../../core/shared/item.model';
import { NO_ERRORS_SCHEMA } from '@angular/core';
import { ProcessTaskResponse } from '../../../core/tasks/models/process-task-response';
import { RatingAdvancedWorkflowInfo } from '../../../core/tasks/models/rating-advanced-workflow-info.model';
const claimedTaskId = '2';
const workflowId = '1';
describe('AdvancedWorkflowActionRatingComponent', () => {
const workflowItem: WorkflowItem = new WorkflowItem();
workflowItem.item = createSuccessfulRemoteDataObject$(new Item());
let component: AdvancedWorkflowActionRatingComponent;
let fixture: ComponentFixture<AdvancedWorkflowActionRatingComponent>;
@@ -52,11 +64,13 @@ describe('AdvancedWorkflowActionRatingComponent', () => {
useValue: {
data: observableOf({
id: workflowId,
wfi: createSuccessfulRemoteDataObject(workflowItem),
}),
snapshot: {
queryParams: convertToParamMap({
queryParams: {
claimedTask: claimedTaskId,
workflow: 'testaction',
}),
},
},
},
},
@@ -67,6 +81,7 @@ describe('AdvancedWorkflowActionRatingComponent', () => {
{ provide: WorkflowActionDataService, useValue: workflowActionDataService },
{ provide: WorkflowItemDataService, useValue: workflowItemDataService },
],
schemas: [NO_ERRORS_SCHEMA],
}).compileComponents();
});
@@ -80,7 +95,96 @@ describe('AdvancedWorkflowActionRatingComponent', () => {
fixture.debugElement.nativeElement.remove();
});
it('should create', () => {
expect(component).toBeTruthy();
describe('performAction', () => {
let ratingAdvancedWorkflowInfo: RatingAdvancedWorkflowInfo;
beforeEach(() => {
ratingAdvancedWorkflowInfo = new RatingAdvancedWorkflowInfo();
ratingAdvancedWorkflowInfo.maxValue = 5;
spyOn(component, 'getAdvancedInfo').and.returnValue(ratingAdvancedWorkflowInfo);
spyOn(component, 'previousPage');
// The form validators are set in the HTML code so the getAdvancedInfo needs to return a value
fixture.detectChanges();
});
describe('with required review', () => {
beforeEach(() => {
ratingAdvancedWorkflowInfo.descriptionRequired = true;
fixture.detectChanges();
});
it('should call the claimedTaskDataService with the rating and the required description when it has been rated and return to the mydspace page', () => {
spyOn(claimedTaskDataService, 'submitTask').and.returnValue(observableOf(new ProcessTaskResponse(true)));
component.ratingForm.setValue({
review: 'Good job!',
rating: 4,
});
component.performAction();
expect(claimedTaskDataService.submitTask).toHaveBeenCalledWith(claimedTaskId, {
[ADVANCED_WORKFLOW_TASK_OPTION_RATING]: true,
review: 'Good job!',
score: 4,
});
expect(notificationService.success).toHaveBeenCalled();
expect(component.previousPage).toHaveBeenCalled();
});
it('should not call the claimedTaskDataService when the required description is empty', () => {
spyOn(claimedTaskDataService, 'submitTask').and.returnValue(observableOf(new ProcessTaskResponse(true)));
component.ratingForm.setValue({
review: '',
rating: 4,
});
component.performAction();
expect(claimedTaskDataService.submitTask).not.toHaveBeenCalled();
expect(notificationService.success).not.toHaveBeenCalled();
expect(component.previousPage).not.toHaveBeenCalled();
});
});
describe('with an optional review', () => {
beforeEach(() => {
ratingAdvancedWorkflowInfo.descriptionRequired = false;
fixture.detectChanges();
});
it('should call the claimedTaskDataService with the optional review when provided and return to the mydspace page', () => {
spyOn(claimedTaskDataService, 'submitTask').and.returnValue(observableOf(new ProcessTaskResponse(true)));
component.ratingForm.setValue({
review: 'Good job!',
rating: 4,
});
component.performAction();
expect(claimedTaskDataService.submitTask).toHaveBeenCalledWith(claimedTaskId, {
[ADVANCED_WORKFLOW_TASK_OPTION_RATING]: true,
review: 'Good job!',
score: 4,
});
expect(notificationService.success).toHaveBeenCalled();
expect(component.previousPage).toHaveBeenCalled();
});
it('should call the claimedTaskDataService when the optional description is empty and return to the mydspace page', () => {
spyOn(claimedTaskDataService, 'submitTask').and.returnValue(observableOf(new ProcessTaskResponse(true)));
component.ratingForm.setValue({
review: '',
rating: 4,
});
component.performAction();
expect(claimedTaskDataService.submitTask).toHaveBeenCalledWith(claimedTaskId, {
[ADVANCED_WORKFLOW_TASK_OPTION_RATING]: true,
score: 4,
});
expect(notificationService.success).toHaveBeenCalled();
expect(component.previousPage).toHaveBeenCalled();
});
});
});
});

View File

@@ -1,6 +1,9 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { AdvancedWorkflowActionSelectReviewerComponent } from './advanced-workflow-action-select-reviewer.component';
import { ActivatedRoute, convertToParamMap } from '@angular/router';
import {
AdvancedWorkflowActionSelectReviewerComponent,
ADVANCED_WORKFLOW_TASK_OPTION_SELECT_REVIEWER
} from './advanced-workflow-action-select-reviewer.component';
import { ActivatedRoute } from '@angular/router';
import { WorkflowItemDataService } from '../../../core/submission/workflowitem-data.service';
import { WorkflowItemDataServiceStub } from '../../../shared/testing/workflow-item-data-service.stub';
import { RouterTestingModule } from '@angular/router/testing';
@@ -14,10 +17,19 @@ import { TranslateModule } from '@ngx-translate/core';
import { ClaimedTaskDataService } from '../../../core/tasks/claimed-task-data.service';
import { ClaimedTaskDataServiceStub } from '../../../shared/testing/claimed-task-data-service.stub';
import { of as observableOf } from 'rxjs';
import { WorkflowItem } from '../../../core/submission/models/workflowitem.model';
import { createSuccessfulRemoteDataObject$, createSuccessfulRemoteDataObject } from '../../../shared/remote-data.utils';
import { Item } from '../../../core/shared/item.model';
import { EPersonMock, EPersonMock2 } from '../../../shared/testing/eperson.mock';
import { ProcessTaskResponse } from '../../../core/tasks/models/process-task-response';
import { NO_ERRORS_SCHEMA } from '@angular/core';
const claimedTaskId = '2';
const workflowId = '1';
describe('AdvancedWorkflowActionSelectReviewerComponent', () => {
const workflowItem: WorkflowItem = new WorkflowItem();
workflowItem.item = createSuccessfulRemoteDataObject$(new Item());
let component: AdvancedWorkflowActionSelectReviewerComponent;
let fixture: ComponentFixture<AdvancedWorkflowActionSelectReviewerComponent>;
@@ -46,11 +58,13 @@ describe('AdvancedWorkflowActionSelectReviewerComponent', () => {
useValue: {
data: observableOf({
id: workflowId,
wfi: createSuccessfulRemoteDataObject(workflowItem),
}),
snapshot: {
queryParams: convertToParamMap({
queryParams: {
claimedTask: claimedTaskId,
workflow: 'testaction',
}),
},
},
},
},
@@ -60,6 +74,7 @@ describe('AdvancedWorkflowActionSelectReviewerComponent', () => {
{ provide: WorkflowActionDataService, useValue: workflowActionDataService },
{ provide: WorkflowItemDataService, useValue: workflowItemDataService },
],
schemas: [NO_ERRORS_SCHEMA],
}).compileComponents();
});
@@ -67,9 +82,49 @@ describe('AdvancedWorkflowActionSelectReviewerComponent', () => {
fixture = TestBed.createComponent(AdvancedWorkflowActionSelectReviewerComponent);
component = fixture.componentInstance;
fixture.detectChanges();
spyOn(component, 'previousPage');
});
it('should create', () => {
expect(component).toBeTruthy();
afterEach(() => {
fixture.debugElement.nativeElement.remove();
});
describe('performAction', () => {
it('should call the claimedTaskDataService with the list of selected ePersons', () => {
spyOn(claimedTaskDataService, 'submitTask').and.returnValue(observableOf(new ProcessTaskResponse(true)));
component.selectedReviewers = [EPersonMock, EPersonMock2];
component.performAction();
expect(claimedTaskDataService.submitTask).toHaveBeenCalledWith(claimedTaskId, {
[ADVANCED_WORKFLOW_TASK_OPTION_SELECT_REVIEWER]: true,
eperson: [EPersonMock.id, EPersonMock2.id],
});
expect(notificationService.success).toHaveBeenCalled();
expect(component.previousPage).toHaveBeenCalled();
});
it('should not call the claimedTaskDataService with the list of selected ePersons when it\'s empty', () => {
spyOn(claimedTaskDataService, 'submitTask').and.returnValue(observableOf(new ProcessTaskResponse(true)));
component.selectedReviewers = [];
component.performAction();
expect(claimedTaskDataService.submitTask).not.toHaveBeenCalled();
});
it('should not call the return to mydspace page when the request failed', () => {
spyOn(claimedTaskDataService, 'submitTask').and.returnValue(observableOf(new ProcessTaskResponse(false)));
component.selectedReviewers = [EPersonMock, EPersonMock2];
component.performAction();
expect(claimedTaskDataService.submitTask).toHaveBeenCalledWith(claimedTaskId, {
[ADVANCED_WORKFLOW_TASK_OPTION_SELECT_REVIEWER]: true,
eperson: [EPersonMock.id, EPersonMock2.id],
});
expect(notificationService.error).toHaveBeenCalled();
expect(component.previousPage).not.toHaveBeenCalled();
});
});
});

View File

@@ -1,6 +1,6 @@
import { CommonModule } from '@angular/common';
import { NO_ERRORS_SCHEMA, SimpleChange } from '@angular/core';
import { ComponentFixture, fakeAsync, flush, inject, TestBed, waitForAsync } from '@angular/core/testing';
import { NO_ERRORS_SCHEMA, SimpleChange, DebugElement } from '@angular/core';
import { ComponentFixture, fakeAsync, flush, TestBed, waitForAsync } from '@angular/core/testing';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { BrowserModule, By } from '@angular/platform-browser';
import { Router } from '@angular/router';
@@ -31,6 +31,7 @@ import { NotificationsServiceStub } from '../../../../shared/testing/notificatio
import { RouterMock } from '../../../../shared/mocks/router.mock';
import { PaginationService } from '../../../../core/pagination/pagination.service';
import { PaginationServiceStub } from '../../../../shared/testing/pagination-service.stub';
import { EpersonDtoModel } from '../../../../core/eperson/models/eperson-dto.model';
describe('ReviewersListComponent', () => {
let component: ReviewersListComponent;
@@ -45,6 +46,8 @@ describe('ReviewersListComponent', () => {
let epersonMembers;
let subgroupMembers;
let paginationService;
let ePersonDtoModel1: EpersonDtoModel;
let ePersonDtoModel2: EpersonDtoModel;
beforeEach(waitForAsync(() => {
activeGroup = GroupMock;
@@ -56,7 +59,7 @@ describe('ReviewersListComponent', () => {
activeGroup: activeGroup,
epersonMembers: epersonMembers,
subgroupMembers: subgroupMembers,
findAllByHref(href: string): Observable<RemoteData<PaginatedList<EPerson>>> {
findAllByHref(_href: string): Observable<RemoteData<PaginatedList<EPerson>>> {
return createSuccessfulRemoteDataObject$(buildPaginatedList<EPerson>(new PageInfo(), groupsDataServiceStub.getEPersonMembers()));
},
searchByScope(scope: string, query: string): Observable<RemoteData<PaginatedList<EPerson>>> {
@@ -119,7 +122,6 @@ describe('ReviewersListComponent', () => {
findById(id: string) {
for (const group of allGroups) {
if (group.id === id) {
console.log('found', group);
return createSuccessfulRemoteDataObject$(group);
}
}
@@ -167,9 +169,12 @@ describe('ReviewersListComponent', () => {
fixture.debugElement.nativeElement.remove();
}));
it('should create ReviewersListComponent', inject([ReviewersListComponent], (comp: ReviewersListComponent) => {
expect(comp).toBeDefined();
}));
beforeEach(() => {
ePersonDtoModel1 = new EpersonDtoModel();
ePersonDtoModel1.eperson = EPersonMock;
ePersonDtoModel2 = new EpersonDtoModel();
ePersonDtoModel2.eperson = EPersonMock2;
});
describe('when no group is selected', () => {
beforeEach(() => {
@@ -179,18 +184,18 @@ describe('ReviewersListComponent', () => {
fixture.detectChanges();
});
it('should show no epersons because no group is selected', () => {
const epersonIdsFound = fixture.debugElement.queryAll(By.css('#ePeopleMembersOfGroup tr td:first-child'));
expect(epersonIdsFound.length).toEqual(0);
epersonMembers.map((eperson: EPerson) => {
expect(epersonIdsFound.find((foundEl) => {
return (foundEl.nativeElement.textContent.trim() === eperson.uuid);
it('should show no ePersons because no group is selected', () => {
const ePersonIdsFound = fixture.debugElement.queryAll(By.css('#ePeopleMembersOfGroup tr td:first-child'));
expect(ePersonIdsFound.length).toEqual(0);
epersonMembers.map((ePerson: EPerson) => {
expect(ePersonIdsFound.find((foundEl) => {
return (foundEl.nativeElement.textContent.trim() === ePerson.uuid);
})).not.toBeTruthy();
});
});
});
describe('when group is selected', () => {
describe('when a group is selected', () => {
beforeEach(() => {
component.ngOnChanges({
groupId: new SimpleChange(undefined, GroupMock.id, true)
@@ -198,15 +203,50 @@ describe('ReviewersListComponent', () => {
fixture.detectChanges();
});
it('should show all eperson members of group', () => {
const epersonIdsFound = fixture.debugElement.queryAll(By.css('#ePeopleMembersOfGroup tr td:first-child'));
expect(epersonIdsFound.length).toEqual(1);
epersonMembers.map((eperson: EPerson) => {
expect(epersonIdsFound.find((foundEl) => {
return (foundEl.nativeElement.textContent.trim() === eperson.uuid);
it('should show all ePerson members of group', () => {
const ePersonIdsFound = fixture.debugElement.queryAll(By.css('#ePeopleMembersOfGroup tr td:first-child'));
expect(ePersonIdsFound.length).toEqual(1);
epersonMembers.map((ePerson: EPerson) => {
expect(ePersonIdsFound.find((foundEl: DebugElement) => {
return (foundEl.nativeElement.textContent.trim() === ePerson.uuid);
})).toBeTruthy();
});
});
});
it('should replace the value when a new member is added when multipleReviewers is false', () => {
spyOn(component.selectedReviewersUpdated, 'emit');
component.multipleReviewers = false;
component.selectedReviewers = [ePersonDtoModel1];
component.addMemberToGroup(ePersonDtoModel2);
expect(component.selectedReviewers).toEqual([ePersonDtoModel2]);
expect(component.selectedReviewersUpdated.emit).toHaveBeenCalledWith([ePersonDtoModel2.eperson]);
});
it('should add the value when a new member is added when multipleReviewers is true', () => {
spyOn(component.selectedReviewersUpdated, 'emit');
component.multipleReviewers = true;
component.selectedReviewers = [ePersonDtoModel1];
component.addMemberToGroup(ePersonDtoModel2);
expect(component.selectedReviewers).toEqual([ePersonDtoModel1, ePersonDtoModel2]);
expect(component.selectedReviewersUpdated.emit).toHaveBeenCalledWith([ePersonDtoModel1.eperson, ePersonDtoModel2.eperson]);
});
it('should delete the member when present', () => {
spyOn(component.selectedReviewersUpdated, 'emit');
ePersonDtoModel1.memberOfGroup = true;
component.selectedReviewers = [ePersonDtoModel1];
component.deleteMemberFromGroup(ePersonDtoModel1);
expect(component.selectedReviewers).toEqual([]);
expect(ePersonDtoModel1.memberOfGroup).toBeFalse();
expect(component.selectedReviewersUpdated.emit).toHaveBeenCalledWith([]);
});
});

View File

@@ -5,7 +5,7 @@ import { MockComponent } from 'ng-mocks';
import { DSOSelectorComponent } from '../../../shared/dso-selector/dso-selector/dso-selector.component';
import { ClaimedTaskDataService } from '../../../core/tasks/claimed-task-data.service';
import { ClaimedTaskDataServiceStub } from '../../../shared/testing/claimed-task-data-service.stub';
import { ActivatedRoute, convertToParamMap } from '@angular/router';
import { ActivatedRoute } from '@angular/router';
import { of as observableOf } from 'rxjs';
import { WorkflowItemDataService } from '../../../core/submission/workflowitem-data.service';
import { RouterTestingModule } from '@angular/router/testing';
@@ -54,9 +54,9 @@ describe('AdvancedWorkflowActionComponent', () => {
id: workflowId,
}),
snapshot: {
queryParams: convertToParamMap({
queryParams: {
workflow: 'testaction',
}),
},
},
},
},

View File

@@ -2,6 +2,15 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';
import { AdvancedWorkflowActionsLoaderComponent } from './advanced-workflow-actions-loader.component';
import { Router } from '@angular/router';
import { RouterStub } from '../../../shared/testing/router.stub';
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { AdvancedWorkflowActionsDirective } from './advanced-workflow-actions.directive';
import {
rendersAdvancedWorkflowTaskOption
} from '../../../shared/mydspace-actions/claimed-task/switcher/claimed-task-actions-decorator';
import { By } from '@angular/platform-browser';
import { PAGE_NOT_FOUND_PATH } from '../../../app-routing-paths';
const ADVANCED_WORKFLOW_ACTION_TEST = 'testaction';
describe('AdvancedWorkflowActionsLoaderComponent', () => {
let component: AdvancedWorkflowActionsLoaderComponent;
@@ -14,21 +23,61 @@ describe('AdvancedWorkflowActionsLoaderComponent', () => {
await TestBed.configureTestingModule({
declarations: [
AdvancedWorkflowActionsDirective,
AdvancedWorkflowActionsLoaderComponent,
],
providers: [
{ provide: Router, useValue: router },
],
}).overrideComponent(AdvancedWorkflowActionsLoaderComponent, {
set: {
changeDetection: ChangeDetectionStrategy.Default,
entryComponents: [AdvancedWorkflowActionTestComponent],
},
}).compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(AdvancedWorkflowActionsLoaderComponent);
component = fixture.componentInstance;
component.type = ADVANCED_WORKFLOW_ACTION_TEST;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
afterEach(() => {
fixture.debugElement.nativeElement.remove();
});
describe('When the component is rendered', () => {
it('should display the AdvancedWorkflowActionTestComponent when the type has been defined in a rendersAdvancedWorkflowTaskOption', () => {
spyOn(component, 'getComponentByWorkflowTaskOption').and.returnValue(AdvancedWorkflowActionTestComponent);
component.ngOnInit();
fixture.detectChanges();
expect(component.getComponentByWorkflowTaskOption).toHaveBeenCalledWith(ADVANCED_WORKFLOW_ACTION_TEST);
expect(fixture.debugElement.query(By.css('#AdvancedWorkflowActionsLoaderComponent'))).not.toBeNull();
expect(router.navigate).not.toHaveBeenCalled();
});
it('should redirect to page not found when the type has not been defined in a rendersAdvancedWorkflowTaskOption', () => {
spyOn(component, 'getComponentByWorkflowTaskOption').and.returnValue(undefined);
component.type = 'nonexistingaction';
component.ngOnInit();
fixture.detectChanges();
expect(component.getComponentByWorkflowTaskOption).toHaveBeenCalledWith('nonexistingaction');
expect(router.navigate).toHaveBeenCalledWith([PAGE_NOT_FOUND_PATH]);
});
});
});
@rendersAdvancedWorkflowTaskOption(ADVANCED_WORKFLOW_ACTION_TEST)
@Component({
// tslint:disable-next-line:component-selector
selector: '',
template: '<span id="AdvancedWorkflowActionsLoaderComponent"></span>',
})
class AdvancedWorkflowActionTestComponent {
}