83635: Feedback and test cases

This commit is contained in:
Kristof De Langhe
2021-10-07 13:53:02 +02:00
parent 03ddde9a97
commit 881eb92fa1
9 changed files with 635 additions and 6 deletions

View File

@@ -0,0 +1,95 @@
import { ItemRequestDataService } from './item-request-data.service';
import { HALEndpointService } from '../shared/hal-endpoint.service';
import { RequestService } from './request.service';
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
import { of as observableOf } from 'rxjs';
import { createSuccessfulRemoteDataObject$ } from '../../shared/remote-data.utils';
import { ItemRequest } from '../shared/item-request.model';
import { PostRequest } from './request.models';
import { RequestCopyEmail } from '../../request-copy/email-request-copy/request-copy-email.model';
import { RestRequestMethod } from './rest-request-method';
describe('ItemRequestDataService', () => {
let service: ItemRequestDataService;
let requestService: RequestService;
let rdbService: RemoteDataBuildService;
let halService: HALEndpointService;
const restApiEndpoint = 'rest/api/endpoint/';
const requestId = 'request-id';
let itemRequest: ItemRequest;
beforeEach(() => {
itemRequest = Object.assign(new ItemRequest(), {
token: 'item-request-token',
});
requestService = jasmine.createSpyObj('requestService', {
generateRequestId: requestId,
send: '',
});
rdbService = jasmine.createSpyObj('rdbService', {
buildFromRequestUUID: createSuccessfulRemoteDataObject$(itemRequest),
});
halService = jasmine.createSpyObj('halService', {
getEndpoint: observableOf(restApiEndpoint),
});
service = new ItemRequestDataService(requestService, rdbService, null, null, halService, null, null, null);
});
describe('requestACopy', () => {
it('should send a POST request containing the provided item request', (done) => {
service.requestACopy(itemRequest).subscribe(() => {
expect(requestService.send).toHaveBeenCalledWith(new PostRequest(requestId, restApiEndpoint, itemRequest));
done();
});
});
});
describe('grant', () => {
let email: RequestCopyEmail;
beforeEach(() => {
email = new RequestCopyEmail('subject', 'message');
});
it('should send a PUT request containing the correct properties', (done) => {
service.grant(itemRequest.token, email, true).subscribe(() => {
expect(requestService.send).toHaveBeenCalledWith(jasmine.objectContaining({
method: RestRequestMethod.PUT,
body: JSON.stringify({
acceptRequest: true,
responseMessage: email.message,
subject: email.subject,
suggestOpenAccess: true,
}),
}));
done();
});
});
});
describe('deny', () => {
let email: RequestCopyEmail;
beforeEach(() => {
email = new RequestCopyEmail('subject', 'message');
});
it('should send a PUT request containing the correct properties', (done) => {
service.deny(itemRequest.token, email).subscribe(() => {
expect(requestService.send).toHaveBeenCalledWith(jasmine.objectContaining({
method: RestRequestMethod.PUT,
body: JSON.stringify({
acceptRequest: false,
responseMessage: email.message,
subject: email.subject,
suggestOpenAccess: false,
}),
}));
done();
});
});
});
});

View File

@@ -7,7 +7,7 @@ import { CacheableObject } from '../cache/object-cache.reducer';
import { HALLink } from './hal-link.model';
/**
* Model class for a Configuration Property
* Model class for an ItemRequest
*/
@typedObject
export class ItemRequest implements CacheableObject {

View File

@@ -0,0 +1,177 @@
import { DenyRequestCopyComponent } from './deny-request-copy.component';
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { VarDirective } from '../../shared/utils/var.directive';
import { TranslateModule, TranslateService } from '@ngx-translate/core';
import { RouterTestingModule } from '@angular/router/testing';
import { NO_ERRORS_SCHEMA } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { AuthService } from '../../core/auth/auth.service';
import { ItemDataService } from '../../core/data/item-data.service';
import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
import { ItemRequestDataService } from '../../core/data/item-request-data.service';
import { NotificationsService } from '../../shared/notifications/notifications.service';
import { of as observableOf } from 'rxjs';
import {
createFailedRemoteDataObject$,
createSuccessfulRemoteDataObject,
createSuccessfulRemoteDataObject$
} from '../../shared/remote-data.utils';
import { ItemRequest } from '../../core/shared/item-request.model';
import { EPerson } from '../../core/eperson/models/eperson.model';
import { Item } from '../../core/shared/item.model';
import { RequestCopyEmail } from '../email-request-copy/request-copy-email.model';
describe('DenyRequestCopyComponent', () => {
let component: DenyRequestCopyComponent;
let fixture: ComponentFixture<DenyRequestCopyComponent>;
let router: Router;
let route: ActivatedRoute;
let authService: AuthService;
let translateService: TranslateService;
let itemDataService: ItemDataService;
let nameService: DSONameService;
let itemRequestService: ItemRequestDataService;
let notificationsService: NotificationsService;
let itemRequest: ItemRequest;
let user: EPerson;
let item: Item;
let itemName: string;
let itemUrl: string;
beforeEach(waitForAsync(() => {
itemRequest = Object.assign(new ItemRequest(), {
token: 'item-request-token',
requestName: 'requester name'
});
user = Object.assign(new EPerson(), {
metadata: {
'eperson.firstname': [
{
value: 'first'
}
],
'eperson.lastname': [
{
value: 'last'
}
]
},
email: 'user-email',
});
itemName = 'item-name';
itemUrl = 'item-url';
item = Object.assign(new Item(), {
id: 'item-id',
metadata: {
'dc.identifier.uri': [
{
value: itemUrl
}
],
'dc.title': [
{
value: itemName
}
]
}
});
router = jasmine.createSpyObj('router', {
navigateByUrl: jasmine.createSpy('navigateByUrl'),
});
route = jasmine.createSpyObj('route', {}, {
data: observableOf({
request: createSuccessfulRemoteDataObject(itemRequest),
}),
});
authService = jasmine.createSpyObj('authService', {
isAuthenticated: observableOf(true),
getAuthenticatedUserFromStore: observableOf(user),
});
itemDataService = jasmine.createSpyObj('itemDataService', {
findById: createSuccessfulRemoteDataObject$(item),
});
nameService = jasmine.createSpyObj('nameService', {
getName: itemName,
});
itemRequestService = jasmine.createSpyObj('itemRequestService', {
deny: createSuccessfulRemoteDataObject$(itemRequest),
});
notificationsService = jasmine.createSpyObj('notificationsService', ['success', 'error']);
TestBed.configureTestingModule({
declarations: [DenyRequestCopyComponent, VarDirective],
imports: [TranslateModule.forRoot(), RouterTestingModule.withRoutes([])],
providers: [
{ provide: Router, useValue: router },
{ provide: ActivatedRoute, useValue: route },
{ provide: AuthService, useValue: authService },
{ provide: ItemDataService, useValue: itemDataService },
{ provide: DSONameService, useValue: nameService },
{ provide: ItemRequestDataService, useValue: itemRequestService },
{ provide: NotificationsService, useValue: notificationsService },
],
schemas: [NO_ERRORS_SCHEMA]
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(DenyRequestCopyComponent);
component = fixture.componentInstance;
fixture.detectChanges();
translateService = (component as any).translateService;
spyOn(translateService, 'get').and.returnValue(observableOf('translated-message'));
});
it('message$ should be parameterized correctly', (done) => {
component.message$.subscribe(() => {
expect(translateService.get).toHaveBeenCalledWith(jasmine.anything(), Object.assign({
recipientName: itemRequest.requestName,
itemUrl: itemUrl,
itemName: itemName,
authorName: user.name,
authorEmail: user.email,
}));
done();
});
});
describe('deny', () => {
let email: RequestCopyEmail;
describe('when the request is successful', () => {
beforeEach(() => {
email = new RequestCopyEmail('subject', 'message');
(itemRequestService.deny as jasmine.Spy).and.returnValue(createSuccessfulRemoteDataObject$(itemRequest));
component.deny(email);
});
it('should display a success notification', () => {
expect(notificationsService.success).toHaveBeenCalled();
});
it('should navigate to the homepage', () => {
expect(router.navigateByUrl).toHaveBeenCalledWith('/');
});
});
describe('when the request is unsuccessful', () => {
beforeEach(() => {
email = new RequestCopyEmail('subject', 'message');
(itemRequestService.deny as jasmine.Spy).and.returnValue(createFailedRemoteDataObject$());
component.deny(email);
});
it('should display a success notification', () => {
expect(notificationsService.error).toHaveBeenCalled();
});
it('should not navigate', () => {
expect(router.navigateByUrl).not.toHaveBeenCalled();
});
});
});
});

View File

@@ -0,0 +1,47 @@
import { EmailRequestCopyComponent } from './email-request-copy.component';
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { VarDirective } from '../../shared/utils/var.directive';
import { TranslateModule } from '@ngx-translate/core';
import { RouterTestingModule } from '@angular/router/testing';
import { NO_ERRORS_SCHEMA } from '@angular/core';
import { Location } from '@angular/common';
import { RequestCopyEmail } from './request-copy-email.model';
describe('EmailRequestCopyComponent', () => {
let component: EmailRequestCopyComponent;
let fixture: ComponentFixture<EmailRequestCopyComponent>;
let location: Location;
beforeEach(waitForAsync(() => {
location = jasmine.createSpyObj('location', ['back']);
TestBed.configureTestingModule({
declarations: [EmailRequestCopyComponent, VarDirective],
imports: [TranslateModule.forRoot(), RouterTestingModule.withRoutes([])],
providers: [
{ provide: Location, useValue: location },
],
schemas: [NO_ERRORS_SCHEMA]
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(EmailRequestCopyComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('return should navigate to the previous page', () => {
component.return();
expect(location.back).toHaveBeenCalled();
});
it('submit should emit an email object', () => {
spyOn(component.send, 'emit').and.stub();
component.subject = 'test-subject';
component.message = 'test-message';
component.submit();
expect(component.send.emit).toHaveBeenCalledWith(new RequestCopyEmail('test-subject', 'test-message'));
});
});

View File

@@ -1,7 +1,7 @@
<div class="container" *ngVar="(itemRequestRD$ | async) as itemRequestRD">
<h3 class="mb-4">{{'grant-deny-request-copy.header' | translate}}</h3>
<div *ngIf="itemRequestRD && itemRequestRD.hasSucceeded">
<p>{{'grant-deny-request-copy.intro1' | translate:{ name: (itemName$ | async) } }}</p>
<p [innerHTML]="'grant-deny-request-copy.intro1' | translate:{ url: (itemUrl$ | async), name: (itemName$ | async) }"></p>
<p>{{'grant-deny-request-copy.intro2' | translate}}</p>
<div class="btn-group ">

View File

@@ -0,0 +1,123 @@
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { VarDirective } from '../../shared/utils/var.directive';
import { TranslateModule } from '@ngx-translate/core';
import { RouterTestingModule } from '@angular/router/testing';
import { NO_ERRORS_SCHEMA } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { AuthService } from '../../core/auth/auth.service';
import { ItemDataService } from '../../core/data/item-data.service';
import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
import { of as observableOf } from 'rxjs';
import {
createSuccessfulRemoteDataObject,
createSuccessfulRemoteDataObject$
} from '../../shared/remote-data.utils';
import { ItemRequest } from '../../core/shared/item-request.model';
import { Item } from '../../core/shared/item.model';
import { GrantDenyRequestCopyComponent } from './grant-deny-request-copy.component';
import { getItemPageRoute } from '../../item-page/item-page-routing-paths';
import { getRequestCopyDenyRoute, getRequestCopyGrantRoute } from '../request-copy-routing-paths';
describe('GrantDenyRequestCopyComponent', () => {
let component: GrantDenyRequestCopyComponent;
let fixture: ComponentFixture<GrantDenyRequestCopyComponent>;
let router: Router;
let route: ActivatedRoute;
let authService: AuthService;
let itemDataService: ItemDataService;
let nameService: DSONameService;
let itemRequest: ItemRequest;
let item: Item;
let itemName: string;
let itemUrl: string;
beforeEach(waitForAsync(() => {
itemRequest = Object.assign(new ItemRequest(), {
token: 'item-request-token',
requestName: 'requester name'
});
itemName = 'item-name';
item = Object.assign(new Item(), {
id: 'item-id',
metadata: {
'dc.identifier.uri': [
{
value: itemUrl
}
],
'dc.title': [
{
value: itemName
}
]
}
});
itemUrl = getItemPageRoute(item);
route = jasmine.createSpyObj('route', {}, {
data: observableOf({
request: createSuccessfulRemoteDataObject(itemRequest),
}),
});
authService = jasmine.createSpyObj('authService', {
isAuthenticated: observableOf(true),
});
itemDataService = jasmine.createSpyObj('itemDataService', {
findById: createSuccessfulRemoteDataObject$(item),
});
nameService = jasmine.createSpyObj('nameService', {
getName: itemName,
});
TestBed.configureTestingModule({
declarations: [GrantDenyRequestCopyComponent, VarDirective],
imports: [TranslateModule.forRoot(), RouterTestingModule.withRoutes([])],
providers: [
{ provide: ActivatedRoute, useValue: route },
{ provide: AuthService, useValue: authService },
{ provide: ItemDataService, useValue: itemDataService },
{ provide: DSONameService, useValue: nameService },
],
schemas: [NO_ERRORS_SCHEMA]
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(GrantDenyRequestCopyComponent);
component = fixture.componentInstance;
fixture.detectChanges();
router = (component as any).router;
spyOn(router, 'navigateByUrl').and.stub();
});
it('should initialise itemName$', (done) => {
component.itemName$.subscribe((result) => {
expect(result).toEqual(itemName);
done();
});
});
it('should initialise itemUrl$', (done) => {
component.itemUrl$.subscribe((result) => {
expect(result).toEqual(itemUrl);
done();
});
});
it('should initialise denyRoute$', (done) => {
component.denyRoute$.subscribe((result) => {
expect(result).toEqual(getRequestCopyDenyRoute(itemRequest.token));
done();
});
});
it('should initialise grantRoute$', (done) => {
component.grantRoute$.subscribe((result) => {
expect(result).toEqual(getRequestCopyGrantRoute(itemRequest.token));
done();
});
});
});

View File

@@ -14,6 +14,7 @@ import { getRequestCopyDenyRoute, getRequestCopyGrantRoute } from '../request-co
import { Item } from '../../core/shared/item.model';
import { ItemDataService } from '../../core/data/item-data.service';
import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
import { getItemPageRoute } from '../../item-page/item-page-routing-paths';
@Component({
selector: 'ds-grant-deny-request-copy',
@@ -39,6 +40,11 @@ export class GrantDenyRequestCopyComponent implements OnInit {
*/
itemName$: Observable<string>;
/**
* The url of the item
*/
itemUrl$: Observable<string>;
/**
* The route to the page for denying access to the item
*/
@@ -73,6 +79,10 @@ export class GrantDenyRequestCopyComponent implements OnInit {
getFirstSucceededRemoteDataPayload(),
map((item) => this.nameService.getName(item)),
);
this.itemUrl$ = this.itemRD$.pipe(
getFirstSucceededRemoteDataPayload(),
map((item) => getItemPageRoute(item)),
);
this.denyRoute$ = this.itemRequestRD$.pipe(
getFirstSucceededRemoteDataPayload(),

View File

@@ -0,0 +1,177 @@
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { VarDirective } from '../../shared/utils/var.directive';
import { TranslateModule, TranslateService } from '@ngx-translate/core';
import { RouterTestingModule } from '@angular/router/testing';
import { NO_ERRORS_SCHEMA } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { AuthService } from '../../core/auth/auth.service';
import { ItemDataService } from '../../core/data/item-data.service';
import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
import { ItemRequestDataService } from '../../core/data/item-request-data.service';
import { NotificationsService } from '../../shared/notifications/notifications.service';
import { of as observableOf } from 'rxjs';
import {
createFailedRemoteDataObject$,
createSuccessfulRemoteDataObject,
createSuccessfulRemoteDataObject$
} from '../../shared/remote-data.utils';
import { ItemRequest } from '../../core/shared/item-request.model';
import { EPerson } from '../../core/eperson/models/eperson.model';
import { Item } from '../../core/shared/item.model';
import { RequestCopyEmail } from '../email-request-copy/request-copy-email.model';
import { GrantRequestCopyComponent } from './grant-request-copy.component';
describe('GrantRequestCopyComponent', () => {
let component: GrantRequestCopyComponent;
let fixture: ComponentFixture<GrantRequestCopyComponent>;
let router: Router;
let route: ActivatedRoute;
let authService: AuthService;
let translateService: TranslateService;
let itemDataService: ItemDataService;
let nameService: DSONameService;
let itemRequestService: ItemRequestDataService;
let notificationsService: NotificationsService;
let itemRequest: ItemRequest;
let user: EPerson;
let item: Item;
let itemName: string;
let itemUrl: string;
beforeEach(waitForAsync(() => {
itemRequest = Object.assign(new ItemRequest(), {
token: 'item-request-token',
requestName: 'requester name'
});
user = Object.assign(new EPerson(), {
metadata: {
'eperson.firstname': [
{
value: 'first'
}
],
'eperson.lastname': [
{
value: 'last'
}
]
},
email: 'user-email',
});
itemName = 'item-name';
itemUrl = 'item-url';
item = Object.assign(new Item(), {
id: 'item-id',
metadata: {
'dc.identifier.uri': [
{
value: itemUrl
}
],
'dc.title': [
{
value: itemName
}
]
}
});
router = jasmine.createSpyObj('router', {
navigateByUrl: jasmine.createSpy('navigateByUrl'),
});
route = jasmine.createSpyObj('route', {}, {
data: observableOf({
request: createSuccessfulRemoteDataObject(itemRequest),
}),
});
authService = jasmine.createSpyObj('authService', {
isAuthenticated: observableOf(true),
getAuthenticatedUserFromStore: observableOf(user),
});
itemDataService = jasmine.createSpyObj('itemDataService', {
findById: createSuccessfulRemoteDataObject$(item),
});
nameService = jasmine.createSpyObj('nameService', {
getName: itemName,
});
itemRequestService = jasmine.createSpyObj('itemRequestService', {
grant: createSuccessfulRemoteDataObject$(itemRequest),
});
notificationsService = jasmine.createSpyObj('notificationsService', ['success', 'error']);
TestBed.configureTestingModule({
declarations: [GrantRequestCopyComponent, VarDirective],
imports: [TranslateModule.forRoot(), RouterTestingModule.withRoutes([])],
providers: [
{ provide: Router, useValue: router },
{ provide: ActivatedRoute, useValue: route },
{ provide: AuthService, useValue: authService },
{ provide: ItemDataService, useValue: itemDataService },
{ provide: DSONameService, useValue: nameService },
{ provide: ItemRequestDataService, useValue: itemRequestService },
{ provide: NotificationsService, useValue: notificationsService },
],
schemas: [NO_ERRORS_SCHEMA]
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(GrantRequestCopyComponent);
component = fixture.componentInstance;
fixture.detectChanges();
translateService = (component as any).translateService;
spyOn(translateService, 'get').and.returnValue(observableOf('translated-message'));
});
it('message$ should be parameterized correctly', (done) => {
component.message$.subscribe(() => {
expect(translateService.get).toHaveBeenCalledWith(jasmine.anything(), Object.assign({
recipientName: itemRequest.requestName,
itemUrl: itemUrl,
itemName: itemName,
authorName: user.name,
authorEmail: user.email,
}));
done();
});
});
describe('grant', () => {
let email: RequestCopyEmail;
describe('when the request is successful', () => {
beforeEach(() => {
email = new RequestCopyEmail('subject', 'message');
(itemRequestService.grant as jasmine.Spy).and.returnValue(createSuccessfulRemoteDataObject$(itemRequest));
component.grant(email);
});
it('should display a success notification', () => {
expect(notificationsService.success).toHaveBeenCalled();
});
it('should navigate to the homepage', () => {
expect(router.navigateByUrl).toHaveBeenCalledWith('/');
});
});
describe('when the request is unsuccessful', () => {
beforeEach(() => {
email = new RequestCopyEmail('subject', 'message');
(itemRequestService.grant as jasmine.Spy).and.returnValue(createFailedRemoteDataObject$());
component.grant(email);
});
it('should display a success notification', () => {
expect(notificationsService.error).toHaveBeenCalled();
});
it('should not navigate', () => {
expect(router.navigateByUrl).not.toHaveBeenCalled();
});
});
});
});

View File

@@ -1206,7 +1206,7 @@
"deny-request-copy.email.message": "Dear {{ recipientName }},\nIn response to your request I regret to inform you that it's not possible to send you a copy of the file(s) you have requested, concerning the document: \"{{ itemUrl }}\" ({{ itemName }}), of which I am author (or co-author).\n\nBest regards,\n{{ authorName }} <{{ authorEmail }}>",
"deny-request-copy.email.message": "Dear {{ recipientName }},\nIn response to your request I regret to inform you that it's not possible to send you a copy of the file(s) you have requested, concerning the document: \"{{ itemUrl }}\" ({{ itemName }}), of which I am an author.\n\nBest regards,\n{{ authorName }} <{{ authorEmail }}>",
"deny-request-copy.email.subject": "Request copy of document",
@@ -1467,13 +1467,13 @@
"grant-deny-request-copy.header": "Document copy request",
"grant-deny-request-copy.intro1": "IF YOU ARE THE AUTHOR (OR AN AUTHOR) OF DOCUMENT \"{{ name }}\" use the buttons to answer the user's request.",
"grant-deny-request-copy.intro1": "If you are one of the authors of the document <a href='{{ url }}'>{{ name }}</a>, then please use one of the options below to respond to the user's request.",
"grant-deny-request-copy.intro2": "This repository will propose an appropriate model reply, which you may edit.",
"grant-deny-request-copy.intro2": "After choosing an option, you will be presented with a suggested email reply which you may edit.",
"grant-request-copy.email.message": "Dear {{ recipientName }},\nIn response to your request I have the pleasure to send you in attachment a copy of the file(s) concerning the document: \"{{ itemUrl }}\" ({{ itemName }}), of which I am author (or co-author).\n\nBest regards,\n{{ authorName }} <{{ authorEmail }}>",
"grant-request-copy.email.message": "Dear {{ recipientName }},\nIn response to your request I have the pleasure to send you in attachment a copy of the file(s) concerning the document: \"{{ itemUrl }}\" ({{ itemName }}), of which I am an author.\n\nBest regards,\n{{ authorName }} <{{ authorEmail }}>",
"grant-request-copy.email.subject": "Request copy of document",