diff --git a/src/app/core/end-user-agreement/end-user-agreement.guard.spec.ts b/src/app/core/end-user-agreement/end-user-agreement.guard.spec.ts
new file mode 100644
index 0000000000..589b227b5a
--- /dev/null
+++ b/src/app/core/end-user-agreement/end-user-agreement.guard.spec.ts
@@ -0,0 +1,48 @@
+import { EndUserAgreementGuard } from './end-user-agreement.guard';
+import { EndUserAgreementService } from './end-user-agreement.service';
+import { Router, UrlTree } from '@angular/router';
+import { of as observableOf } from 'rxjs';
+
+describe('EndUserAgreementGuard', () => {
+ let guard: EndUserAgreementGuard;
+
+ let endUserAgreementService: EndUserAgreementService;
+ let router: Router;
+
+ beforeEach(() => {
+ endUserAgreementService = jasmine.createSpyObj('endUserAgreementService', {
+ hasCurrentUserAcceptedAgreement: observableOf(true)
+ });
+ router = jasmine.createSpyObj('router', {
+ navigateByUrl: {},
+ parseUrl: new UrlTree()
+ });
+
+ guard = new EndUserAgreementGuard(endUserAgreementService, router);
+ });
+
+ describe('canActivate', () => {
+ describe('when the user has accepted the agreement', () => {
+ it('should return true', (done) => {
+ guard.canActivate(undefined, undefined).subscribe((result) => {
+ expect(result).toEqual(true);
+ done();
+ });
+ });
+ });
+
+ describe('when the user hasn\'t accepted the agreement', () => {
+ beforeEach(() => {
+ (endUserAgreementService.hasCurrentUserAcceptedAgreement as jasmine.Spy).and.returnValue(observableOf(false));
+ });
+
+ it('should navigate the user with a redirect url', (done) => {
+ const redirect = 'redirect/url';
+ guard.canActivate(undefined, Object.assign({ url: redirect })).subscribe(() => {
+ expect(router.navigateByUrl).toHaveBeenCalledWith(jasmine.anything(), { state: { redirect } });
+ done();
+ });
+ });
+ });
+ });
+});
diff --git a/src/app/core/end-user-agreement/end-user-agreement.service.spec.ts b/src/app/core/end-user-agreement/end-user-agreement.service.spec.ts
new file mode 100644
index 0000000000..a292b2371c
--- /dev/null
+++ b/src/app/core/end-user-agreement/end-user-agreement.service.spec.ts
@@ -0,0 +1,144 @@
+import {
+ END_USER_AGREEMENT_COOKIE,
+ END_USER_AGREEMENT_METADATA_FIELD,
+ EndUserAgreementService
+} from './end-user-agreement.service';
+import { CookieServiceMock } from '../../shared/mocks/cookie.service.mock';
+import { of as observableOf } from 'rxjs';
+import { EPerson } from '../eperson/models/eperson.model';
+import { createSuccessfulRemoteDataObject$ } from '../../shared/remote-data.utils';
+
+describe('EndUserAgreementService', () => {
+ let service: EndUserAgreementService;
+
+ let userWithMetadata: EPerson;
+ let userWithoutMetadata: EPerson;
+
+ let cookie;
+ let authService;
+ let ePersonService;
+
+ beforeEach(() => {
+ userWithMetadata = Object.assign(new EPerson(), {
+ metadata: {
+ [END_USER_AGREEMENT_METADATA_FIELD]: [
+ {
+ value: 'true'
+ }
+ ]
+ }
+ });
+ userWithoutMetadata = Object.assign(new EPerson());
+
+ cookie = new CookieServiceMock();
+ authService = jasmine.createSpyObj('authService', {
+ isAuthenticated: observableOf(true),
+ getAuthenticatedUserFromStore: observableOf(userWithMetadata)
+ });
+ ePersonService = jasmine.createSpyObj('ePersonService', {
+ update: createSuccessfulRemoteDataObject$(userWithMetadata)
+ });
+
+ service = new EndUserAgreementService(cookie, authService, ePersonService);
+ });
+
+ describe('when the cookie is set to true', () => {
+ beforeEach(() => {
+ cookie.set(END_USER_AGREEMENT_COOKIE, true);
+ });
+
+ it('hasCurrentUserAcceptedAgreement should return true', (done) => {
+ service.hasCurrentUserAcceptedAgreement().subscribe((result) => {
+ expect(result).toEqual(true);
+ done();
+ });
+ });
+
+ it('isCookieAccepted should return true', () => {
+ expect(service.isCookieAccepted()).toEqual(true);
+ });
+
+ it('removeCookieAccepted should remove the cookie', () => {
+ service.removeCookieAccepted();
+ expect(cookie.get(END_USER_AGREEMENT_COOKIE)).toBeUndefined();
+ });
+ });
+
+ describe('when the cookie isn\'t set', () => {
+ describe('and the user is authenticated', () => {
+ beforeEach(() => {
+ (authService.isAuthenticated as jasmine.Spy).and.returnValue(observableOf(true));
+ });
+
+ describe('and the user contains agreement metadata', () => {
+ beforeEach(() => {
+ (authService.getAuthenticatedUserFromStore as jasmine.Spy).and.returnValue(observableOf(userWithMetadata));
+ });
+
+ it('hasCurrentUserAcceptedAgreement should return true', (done) => {
+ service.hasCurrentUserAcceptedAgreement().subscribe((result) => {
+ expect(result).toEqual(true);
+ done();
+ });
+ });
+ });
+
+ describe('and the user doesn\'t contain agreement metadata', () => {
+ beforeEach(() => {
+ (authService.getAuthenticatedUserFromStore as jasmine.Spy).and.returnValue(observableOf(userWithoutMetadata));
+ });
+
+ it('hasCurrentUserAcceptedAgreement should return false', (done) => {
+ service.hasCurrentUserAcceptedAgreement().subscribe((result) => {
+ expect(result).toEqual(false);
+ done();
+ });
+ });
+ });
+
+ it('setUserAcceptedAgreement should update the user with new metadata', (done) => {
+ service.setUserAcceptedAgreement(true).subscribe(() => {
+ expect(ePersonService.update).toHaveBeenCalledWith(jasmine.objectContaining({
+ metadata: jasmine.objectContaining({
+ [END_USER_AGREEMENT_METADATA_FIELD]: [
+ {
+ value: 'true'
+ }
+ ]
+ })
+ }));
+ done();
+ });
+ });
+ });
+
+ describe('and the user is not authenticated', () => {
+ beforeEach(() => {
+ (authService.isAuthenticated as jasmine.Spy).and.returnValue(observableOf(false));
+ });
+
+ it('hasCurrentUserAcceptedAgreement should return false', (done) => {
+ service.hasCurrentUserAcceptedAgreement().subscribe((result) => {
+ expect(result).toEqual(false);
+ done();
+ });
+ });
+
+ it('setUserAcceptedAgreement should set the cookie to true', (done) => {
+ service.setUserAcceptedAgreement(true).subscribe(() => {
+ expect(cookie.get(END_USER_AGREEMENT_COOKIE)).toEqual(true);
+ done();
+ });
+ });
+ });
+
+ it('isCookieAccepted should return false', () => {
+ expect(service.isCookieAccepted()).toEqual(false);
+ });
+
+ it('setCookieAccepted should set the cookie', () => {
+ service.setCookieAccepted(true);
+ expect(cookie.get(END_USER_AGREEMENT_COOKIE)).toEqual(true);
+ });
+ });
+});
diff --git a/src/app/info/end-user-agreement/end-user-agreement-content/end-user-agreement-content.component.spec.ts b/src/app/info/end-user-agreement/end-user-agreement-content/end-user-agreement-content.component.spec.ts
index c95e60846e..d2290cd01c 100644
--- a/src/app/info/end-user-agreement/end-user-agreement-content/end-user-agreement-content.component.spec.ts
+++ b/src/app/info/end-user-agreement/end-user-agreement-content/end-user-agreement-content.component.spec.ts
@@ -1,5 +1,7 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { EndUserAgreementContentComponent } from './end-user-agreement-content.component';
+import { TranslateModule } from '@ngx-translate/core';
+import { NO_ERRORS_SCHEMA } from '@angular/core';
describe('EndUserAgreementContentComponent', () => {
let component: EndUserAgreementContentComponent;
@@ -7,9 +9,10 @@ describe('EndUserAgreementContentComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
- declarations: [ EndUserAgreementContentComponent ]
- })
- .compileComponents();
+ imports: [ TranslateModule.forRoot() ],
+ declarations: [ EndUserAgreementContentComponent ],
+ schemas: [NO_ERRORS_SCHEMA]
+ }).compileComponents();
}));
beforeEach(() => {
diff --git a/src/app/info/end-user-agreement/end-user-agreement.component.html b/src/app/info/end-user-agreement/end-user-agreement.component.html
index 628718cdcd..2338bfa460 100644
--- a/src/app/info/end-user-agreement/end-user-agreement.component.html
+++ b/src/app/info/end-user-agreement/end-user-agreement.component.html
@@ -6,8 +6,8 @@
-
-
+
+
diff --git a/src/app/info/end-user-agreement/end-user-agreement.component.spec.ts b/src/app/info/end-user-agreement/end-user-agreement.component.spec.ts
index 6b87a0fccb..5d6b3f904c 100644
--- a/src/app/info/end-user-agreement/end-user-agreement.component.spec.ts
+++ b/src/app/info/end-user-agreement/end-user-agreement.component.spec.ts
@@ -1,15 +1,58 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { EndUserAgreementComponent } from './end-user-agreement.component';
+import { NO_ERRORS_SCHEMA } from '@angular/core';
+import { EndUserAgreementService } from '../../core/end-user-agreement/end-user-agreement.service';
+import { NotificationsService } from '../../shared/notifications/notifications.service';
+import { TranslateModule } from '@ngx-translate/core';
+import { AuthService } from '../../core/auth/auth.service';
+import { Router } from '@angular/router';
+import { of as observableOf } from 'rxjs';
+import { Store } from '@ngrx/store';
+import { By } from '@angular/platform-browser';
+import { LogOutAction } from '../../core/auth/auth.actions';
describe('EndUserAgreementComponent', () => {
let component: EndUserAgreementComponent;
let fixture: ComponentFixture;
+ let endUserAgreementService: EndUserAgreementService;
+ let notificationsService: NotificationsService;
+ let authService: AuthService;
+ let store;
+ let router: Router;
+
+ let redirectUrl;
+
+ function init() {
+ endUserAgreementService = jasmine.createSpyObj('endUserAgreementService', {
+ hasCurrentUserAcceptedAgreement: observableOf(false),
+ setUserAcceptedAgreement: observableOf(true)
+ });
+ notificationsService = jasmine.createSpyObj('notificationsService', ['success', 'error']);
+ authService = jasmine.createSpyObj('authService', {
+ isAuthenticated: observableOf(true)
+ });
+ store = jasmine.createSpyObj('store', ['dispatch']);
+ router = jasmine.createSpyObj('router', ['navigate', 'navigateByUrl']);
+
+ redirectUrl = 'redirect/url';
+ window.history.pushState({ redirect: redirectUrl }, '');
+ }
+
beforeEach(async(() => {
+ init();
TestBed.configureTestingModule({
- declarations: [ EndUserAgreementComponent ]
- })
- .compileComponents();
+ imports: [ TranslateModule.forRoot() ],
+ declarations: [ EndUserAgreementComponent ],
+ providers: [
+ { provide: EndUserAgreementService, useValue: endUserAgreementService },
+ { provide: NotificationsService, useValue: notificationsService },
+ { provide: AuthService, useValue: authService },
+ { provide: Store, useValue: store },
+ { provide: Router, useValue: router }
+ ],
+ schemas: [NO_ERRORS_SCHEMA]
+ }).compileComponents();
}));
beforeEach(() => {
@@ -18,7 +61,89 @@ describe('EndUserAgreementComponent', () => {
fixture.detectChanges();
});
- it('should create', () => {
- expect(component).toBeTruthy();
+ describe('when the user hasn\'t accepted the agreement', () => {
+ beforeEach(() => {
+ (endUserAgreementService.hasCurrentUserAcceptedAgreement as jasmine.Spy).and.returnValue(observableOf(false));
+ component.ngOnInit();
+ fixture.detectChanges();
+ });
+
+ it('should initialize the accepted property', () => {
+ expect(component.accepted).toEqual(false);
+ });
+
+ it('should disable the save button', () => {
+ const button = fixture.debugElement.query(By.css('#button-save')).nativeElement;
+ expect(button.disabled).toBeTruthy();
+ });
+ });
+
+ describe('when the user has accepted the agreement', () => {
+ beforeEach(() => {
+ (endUserAgreementService.hasCurrentUserAcceptedAgreement as jasmine.Spy).and.returnValue(observableOf(true));
+ component.ngOnInit();
+ fixture.detectChanges();
+ });
+
+ it('should initialize the accepted property', () => {
+ expect(component.accepted).toEqual(true);
+ });
+
+ it('should enable the save button', () => {
+ const button = fixture.debugElement.query(By.css('#button-save')).nativeElement;
+ expect(button.disabled).toBeFalsy();
+ });
+
+ describe('submit', () => {
+ describe('when accepting the agreement was successful', () => {
+ beforeEach(() => {
+ (endUserAgreementService.setUserAcceptedAgreement as jasmine.Spy).and.returnValue(observableOf(true));
+ component.submit();
+ });
+
+ it('should display a success notification', () => {
+ expect(notificationsService.success).toHaveBeenCalled();
+ });
+
+ it('should navigate the user to the redirect url', () => {
+ expect(router.navigateByUrl).toHaveBeenCalledWith(redirectUrl);
+ });
+ });
+
+ describe('when accepting the agreement was unsuccessful', () => {
+ beforeEach(() => {
+ (endUserAgreementService.setUserAcceptedAgreement as jasmine.Spy).and.returnValue(observableOf(false));
+ component.submit();
+ });
+
+ it('should display an error notification', () => {
+ expect(notificationsService.error).toHaveBeenCalled();
+ });
+ });
+ });
+ });
+
+ describe('cancel', () => {
+ describe('when the user is authenticated', () => {
+ beforeEach(() => {
+ (authService.isAuthenticated as jasmine.Spy).and.returnValue(observableOf(true));
+ component.cancel();
+ });
+
+ it('should logout the user', () => {
+ expect(store.dispatch).toHaveBeenCalledWith(new LogOutAction());
+ });
+ });
+
+ describe('when the user is not authenticated', () => {
+ beforeEach(() => {
+ (authService.isAuthenticated as jasmine.Spy).and.returnValue(observableOf(false));
+ component.cancel();
+ });
+
+ it('should navigate the user to the homepage', () => {
+ expect(router.navigate).toHaveBeenCalledWith(['home']);
+ });
+ });
});
});
diff --git a/src/app/info/privacy/privacy-content/privacy-content.component.spec.ts b/src/app/info/privacy/privacy-content/privacy-content.component.spec.ts
index eca0659147..a77e809dc3 100644
--- a/src/app/info/privacy/privacy-content/privacy-content.component.spec.ts
+++ b/src/app/info/privacy/privacy-content/privacy-content.component.spec.ts
@@ -1,5 +1,7 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { PrivacyContentComponent } from './privacy-content.component';
+import { TranslateModule } from '@ngx-translate/core';
+import { NO_ERRORS_SCHEMA } from '@angular/core';
describe('PrivacyContentComponent', () => {
let component: PrivacyContentComponent;
@@ -7,9 +9,10 @@ describe('PrivacyContentComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
- declarations: [ PrivacyContentComponent ]
- })
- .compileComponents();
+ imports: [ TranslateModule.forRoot() ],
+ declarations: [ PrivacyContentComponent ],
+ schemas: [NO_ERRORS_SCHEMA]
+ }).compileComponents();
}));
beforeEach(() => {
diff --git a/src/app/info/privacy/privacy.component.spec.ts b/src/app/info/privacy/privacy.component.spec.ts
index b7daa30029..a3d47e82f9 100644
--- a/src/app/info/privacy/privacy.component.spec.ts
+++ b/src/app/info/privacy/privacy.component.spec.ts
@@ -1,5 +1,7 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { PrivacyComponent } from './privacy.component';
+import { TranslateModule } from '@ngx-translate/core';
+import { NO_ERRORS_SCHEMA } from '@angular/core';
describe('PrivacyComponent', () => {
let component: PrivacyComponent;
@@ -7,9 +9,10 @@ describe('PrivacyComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
- declarations: [ PrivacyComponent ]
- })
- .compileComponents();
+ imports: [ TranslateModule.forRoot() ],
+ declarations: [ PrivacyComponent ],
+ schemas: [NO_ERRORS_SCHEMA]
+ }).compileComponents();
}));
beforeEach(() => {
diff --git a/src/app/register-page/create-profile/create-profile.component.spec.ts b/src/app/register-page/create-profile/create-profile.component.spec.ts
index a435e1143e..00c2eef99d 100644
--- a/src/app/register-page/create-profile/create-profile.component.spec.ts
+++ b/src/app/register-page/create-profile/create-profile.component.spec.ts
@@ -18,6 +18,10 @@ import { EPerson } from '../../core/eperson/models/eperson.model';
import { AuthenticateAction } from '../../core/auth/auth.actions';
import { RouterStub } from '../../shared/testing/router.stub';
import { NotificationsServiceStub } from '../../shared/testing/notifications-service.stub';
+import {
+ END_USER_AGREEMENT_METADATA_FIELD,
+ EndUserAgreementService
+} from '../../core/end-user-agreement/end-user-agreement.service';
describe('CreateProfileComponent', () => {
let comp: CreateProfileComponent;
@@ -28,40 +32,80 @@ describe('CreateProfileComponent', () => {
let ePersonDataService: EPersonDataService;
let notificationsService;
let store: Store;
+ let endUserAgreementService: EndUserAgreementService;
const registration = Object.assign(new Registration(), {email: 'test@email.org', token: 'test-token'});
- const values = {
- metadata: {
- 'eperson.firstname': [
- {
- value: 'First'
- }
- ],
- 'eperson.lastname': [
- {
- value: 'Last'
- },
- ],
- 'eperson.phone': [
- {
- value: 'Phone'
- }
- ],
- 'eperson.language': [
- {
- value: 'en'
- }
- ]
- },
- email: 'test@email.org',
- password: 'password',
- canLogIn: true,
- requireCertificate: false
- };
- const eperson = Object.assign(new EPerson(), values);
+ let values;
+ let eperson: EPerson;
+ let valuesWithAgreement;
+ let epersonWithAgreement: EPerson;
beforeEach(async(() => {
+ values = {
+ metadata: {
+ 'eperson.firstname': [
+ {
+ value: 'First'
+ }
+ ],
+ 'eperson.lastname': [
+ {
+ value: 'Last'
+ },
+ ],
+ 'eperson.phone': [
+ {
+ value: 'Phone'
+ }
+ ],
+ 'eperson.language': [
+ {
+ value: 'en'
+ }
+ ]
+ },
+ email: 'test@email.org',
+ password: 'password',
+ canLogIn: true,
+ requireCertificate: false
+ };
+ eperson = Object.assign(new EPerson(), values);
+ valuesWithAgreement = {
+ metadata: {
+ 'eperson.firstname': [
+ {
+ value: 'First'
+ }
+ ],
+ 'eperson.lastname': [
+ {
+ value: 'Last'
+ },
+ ],
+ 'eperson.phone': [
+ {
+ value: 'Phone'
+ }
+ ],
+ 'eperson.language': [
+ {
+ value: 'en'
+ }
+ ],
+ [END_USER_AGREEMENT_METADATA_FIELD]: [
+ {
+ value: 'true'
+ }
+ ]
+ },
+ email: 'test@email.org',
+ password: 'password',
+ canLogIn: true,
+ requireCertificate: false
+ };
+ epersonWithAgreement = Object.assign(new EPerson(), valuesWithAgreement);
+
route = {data: observableOf({registration: registration})};
router = new RouterStub();
notificationsService = new NotificationsServiceStub();
@@ -74,6 +118,11 @@ describe('CreateProfileComponent', () => {
dispatch: {},
});
+ endUserAgreementService = jasmine.createSpyObj('endUserAgreementService', {
+ isCookieAccepted: false,
+ removeCookieAccepted: {}
+ });
+
TestBed.configureTestingModule({
imports: [CommonModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), ReactiveFormsModule],
declarations: [CreateProfileComponent],
@@ -84,6 +133,7 @@ describe('CreateProfileComponent', () => {
{provide: EPersonDataService, useValue: ePersonDataService},
{provide: FormBuilder, useValue: new FormBuilder()},
{provide: NotificationsService, useValue: notificationsService},
+ {provide: EndUserAgreementService, useValue: endUserAgreementService},
],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
}).compileComponents();
@@ -131,6 +181,41 @@ describe('CreateProfileComponent', () => {
expect(notificationsService.success).toHaveBeenCalled();
});
+ describe('when the end-user-agreement cookie is accepted', () => {
+ beforeEach(() => {
+ (endUserAgreementService.isCookieAccepted as jasmine.Spy).and.returnValue(true);
+ });
+
+ it('should submit an eperson with agreement metadata for creation and log in on success', () => {
+ comp.firstName.patchValue('First');
+ comp.lastName.patchValue('Last');
+ comp.contactPhone.patchValue('Phone');
+ comp.language.patchValue('en');
+ comp.password = 'password';
+ comp.isInValidPassword = false;
+
+ comp.submitEperson();
+
+ expect(ePersonDataService.createEPersonForToken).toHaveBeenCalledWith(epersonWithAgreement, 'test-token');
+ expect(store.dispatch).toHaveBeenCalledWith(new AuthenticateAction('test@email.org', 'password'));
+ expect(router.navigate).toHaveBeenCalledWith(['/home']);
+ expect(notificationsService.success).toHaveBeenCalled();
+ });
+
+ it('should remove the cookie', () => {
+ comp.firstName.patchValue('First');
+ comp.lastName.patchValue('Last');
+ comp.contactPhone.patchValue('Phone');
+ comp.language.patchValue('en');
+ comp.password = 'password';
+ comp.isInValidPassword = false;
+
+ comp.submitEperson();
+
+ expect(endUserAgreementService.removeCookieAccepted).toHaveBeenCalled();
+ });
+ });
+
it('should submit an eperson for creation and stay on page on error', () => {
(ePersonDataService.createEPersonForToken as jasmine.Spy).and.returnValue(observableOf(new RestResponse(false, 500, 'Error')));
diff --git a/src/app/shared/mocks/cookie.service.mock.ts b/src/app/shared/mocks/cookie.service.mock.ts
index f94f3d4a7d..17e1b36981 100644
--- a/src/app/shared/mocks/cookie.service.mock.ts
+++ b/src/app/shared/mocks/cookie.service.mock.ts
@@ -16,7 +16,8 @@ export class CookieServiceMock {
return this.cookies.get(name);
}
- remove() {
+ remove(name) {
+ this.cookies.delete(name);
return jasmine.createSpy('remove');
}