Added tests

This commit is contained in:
Giuseppe Digilio
2018-05-15 16:54:27 +02:00
parent 88a05996a6
commit 27a36362cf
7 changed files with 547 additions and 55 deletions

View File

@@ -0,0 +1,117 @@
import { AuthStatusResponse } from '../cache/response-cache.models';
import { ObjectCacheService } from '../cache/object-cache.service';
import { GlobalConfig } from '../../../config/global-config.interface';
import { Store } from '@ngrx/store';
import { CoreState } from '../core.reducers';
import { AuthStatus } from './models/auth-status.model';
import { AuthResponseParsingService } from './auth-response-parsing.service';
import { AuthGetRequest, AuthPostRequest } from '../data/request.models';
describe('ConfigResponseParsingService', () => {
let service: AuthResponseParsingService;
const EnvConfig = {} as GlobalConfig;
const store = {} as Store<CoreState>;
const objectCacheService = new ObjectCacheService(store);
beforeEach(() => {
service = new AuthResponseParsingService(EnvConfig, objectCacheService);
});
describe('parse', () => {
const validRequest = new AuthPostRequest(
'69f375b5-19f4-4453-8c7a-7dc5c55aafbb',
'https://rest.api/dspace-spring-rest/api/authn/login',
'password=test&user=myself@testshib.org');
const validRequest2 = new AuthGetRequest(
'69f375b5-19f4-4453-8c7a-7dc5c55aafbb',
'https://rest.api/dspace-spring-rest/api/authn/status');
const validResponse = {
payload: {
authenticated: true,
id: null,
okay: true,
token: {
accessToken: 'eyJhbGciOiJIUzI1NiJ9.eyJlaWQiOiI0ZGM3MGFiNS1jZDczLTQ5MmYtYjAwNy0zMTc5ZDJkOTI5NmIiLCJzZyI6W10sImV4cCI6MTUyNjMxODMyMn0.ASmvcbJFBfzhN7D5ncloWnaVZr5dLtgTuOgHaCKiimc',
expires: 1526318322000
},
} as AuthStatus,
statusCode: '200'
};
const validResponse1 = {
payload: {},
statusCode: '404'
};
const validResponse2 = {
payload: {
authenticated: true,
id: null,
okay: true,
type: 'status',
_embedded: {
eperson: {
canLogIn: true,
email: 'myself@testshib.org',
groups: [],
handle: null,
id: '4dc70ab5-cd73-492f-b007-3179d2d9296b',
lastActive: '2018-05-14T17:03:31.277+0000',
metadata: [
{
key: 'eperson.firstname',
language: null,
value: 'User'
},
{
key: 'eperson.lastname',
language: null,
value: 'Test'
},
{
key: 'eperson.language',
language: null,
value: 'en'
}
],
name: 'User Test',
netid: 'myself@testshib.org',
requireCertificate: false,
selfRegistered: false,
type: 'eperson',
uuid: '4dc70ab5-cd73-492f-b007-3179d2d9296b',
_links: {
self: 'https://hasselt-dspace.dev01.4science.it/dspace-spring-rest/api/eperson/epersons/4dc70ab5-cd73-492f-b007-3179d2d9296b'
}
}
},
_links: {
eperson: 'https://hasselt-dspace.dev01.4science.it/dspace-spring-rest/api/eperson/epersons/4dc70ab5-cd73-492f-b007-3179d2d9296b',
self: 'https://hasselt-dspace.dev01.4science.it/dspace-spring-rest/api/authn/status'
}
},
statusCode: '200'
};
it('should return a AuthStatusResponse if data contains a valid AuthStatus object as payload', () => {
const response = service.parse(validRequest, validResponse);
expect(response.constructor).toBe(AuthStatusResponse);
});
it('should return a AuthStatusResponse if data contains a valid endpoint response', () => {
const response = service.parse(validRequest2, validResponse2);
expect(response.constructor).toBe(AuthStatusResponse);
});
it('should return a AuthStatusResponse if data contains an empty 404 endpoint response', () => {
const response = service.parse(validRequest, validResponse1);
expect(response.constructor).toBe(AuthStatusResponse);
});
});
});

View File

@@ -12,14 +12,15 @@ import {
LogOutAction,
LogOutErrorAction,
LogOutSuccessAction,
RedirectWhenAuthenticationIsRequiredAction, RedirectWhenTokenExpiredAction,
RedirectWhenAuthenticationIsRequiredAction,
RedirectWhenTokenExpiredAction,
RefreshTokenAction,
RefreshTokenErrorAction,
RefreshTokenSuccessAction, ResetAuthenticationMessagesAction, SetRedirectUrlAction
RefreshTokenSuccessAction,
ResetAuthenticationMessagesAction,
SetRedirectUrlAction
} from './auth.actions';
import { AuthTokenInfo } from './models/auth-token-info.model';
import { Eperson } from '../eperson/models/eperson.model';
import { Group } from '../eperson/models/group.model';
import { EpersonMock } from '../../shared/testing/eperson-mock';
describe('authReducer', () => {

View File

@@ -8,7 +8,7 @@
</div>
</li>
<li *ngIf="!(isAuthenticated | async) && (windowService.isMobileView() | async)" class="nav-item">
<a class="nav-link" routerLink="/login" routerLinkActive="active"><i class="fa fa-sign-in fa-fw" aria-hidden="true"></i> {{ 'nav.login' | translate }}<span class="sr-only">(current)</span></a>
<a id="loginLink" class="nav-link" routerLink="/login" routerLinkActive="active"><i class="fa fa-sign-in fa-fw" aria-hidden="true"></i> {{ 'nav.login' | translate }}<span class="sr-only">(current)</span></a>
</li>
<li *ngIf="(isAuthenticated | async) && !(windowService.isMobileView() | async) && (showAuth | async)" class="nav-item">
<div ngbDropdown placement="bottom-right" class="d-inline-block" [ngClass]="{'float-right': !(windowService.isMobileView() | async)}" @fadeInOut>
@@ -19,7 +19,7 @@
</div>
</li>
<li *ngIf="(isAuthenticated | async) && (windowService.isMobileView() | async)" class="nav-item">
<a class="nav-link" routerLink="/logout" routerLinkActive="active"><i class="fa fa-sign-out fa-fw" aria-hidden="true"></i> {{ 'nav.logout' | translate }}<span class="sr-only">(current)</span></a>
<a id="logoutLink" class="nav-link" routerLink="/logout" routerLinkActive="active"><i class="fa fa-sign-out fa-fw" aria-hidden="true"></i> {{ 'nav.logout' | translate }}<span class="sr-only">(current)</span></a>
</li>
</ul>

View File

@@ -0,0 +1,297 @@
import { CUSTOM_ELEMENTS_SCHEMA, DebugElement } from '@angular/core';
import { async, ComponentFixture, inject, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { Store, StoreModule } from '@ngrx/store';
import { authReducer, AuthState } from '../../core/auth/auth.reducers';
import { EpersonMock } from '../testing/eperson-mock';
import { TranslateModule } from '@ngx-translate/core';
import { AppState } from '../../app.reducer';
import { AuthNavMenuComponent } from './auth-nav-menu.component';
import { HostWindowServiceStub } from '../testing/host-window-service-stub';
import { HostWindowService } from '../host-window.service';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { AuthTokenInfo } from '../../core/auth/models/auth-token-info.model';
describe('AuthNavMenuComponent', () => {
let component: AuthNavMenuComponent;
let deNavMenu: DebugElement;
let deNavMenuItem: DebugElement;
let fixture: ComponentFixture<AuthNavMenuComponent>;
const notAuthState: AuthState = {
authenticated: false,
loaded: false,
loading: false
};
const authState: AuthState = {
authenticated: true,
loaded: true,
loading: false,
authToken: new AuthTokenInfo('test_token'),
user: EpersonMock
};
let routerState = {
url: '/home'
};
describe('when is a not mobile view', () => {
beforeEach(async(() => {
const window = new HostWindowServiceStub(800);
// refine the test module by declaring the test component
TestBed.configureTestingModule({
imports: [
NoopAnimationsModule,
StoreModule.forRoot(authReducer),
TranslateModule.forRoot()
],
declarations: [
AuthNavMenuComponent
],
providers: [
{provide: HostWindowService, useValue: window},
],
schemas: [
CUSTOM_ELEMENTS_SCHEMA
]
})
.compileComponents();
}));
describe('when route is /login and user is not authenticated', () => {
routerState = {
url: '/login'
};
beforeEach(inject([Store], (store: Store<AppState>) => {
store
.subscribe((state) => {
(state as any).router = Object.create({});
(state as any).router.state = routerState;
(state as any).core = Object.create({});
(state as any).core.auth = notAuthState;
});
// create component and test fixture
fixture = TestBed.createComponent(AuthNavMenuComponent);
// get test component from the fixture
component = fixture.componentInstance;
fixture.detectChanges();
const navMenuSelector = '.navbar-nav';
deNavMenu = fixture.debugElement.query(By.css(navMenuSelector));
const navMenuItemSelector = 'li';
deNavMenuItem = deNavMenu.query(By.css(navMenuItemSelector));
}));
it('should not render', () => {
expect(component).toBeTruthy();
expect(deNavMenu.nativeElement).toBeDefined();
expect(deNavMenuItem).toBeNull();
});
});
describe('when route is /logout and user is authenticated', () => {
routerState = {
url: '/logout'
};
beforeEach(inject([Store], (store: Store<AppState>) => {
store
.subscribe((state) => {
(state as any).router = Object.create({});
(state as any).router.state = routerState;
(state as any).core = Object.create({});
(state as any).core.auth = authState;
});
// create component and test fixture
fixture = TestBed.createComponent(AuthNavMenuComponent);
// get test component from the fixture
component = fixture.componentInstance;
fixture.detectChanges();
const navMenuSelector = '.navbar-nav';
deNavMenu = fixture.debugElement.query(By.css(navMenuSelector));
const navMenuItemSelector = 'li';
deNavMenuItem = deNavMenu.query(By.css(navMenuItemSelector));
}));
it('should not render', () => {
expect(component).toBeTruthy();
expect(deNavMenu.nativeElement).toBeDefined();
expect(deNavMenuItem).toBeNull();
});
});
describe('when route is not /login neither /logout', () => {
describe('when user is not authenticated', () => {
beforeEach(inject([Store], (store: Store<AppState>) => {
routerState = {
url: '/home'
};
store
.subscribe((state) => {
(state as any).router = Object.create({});
(state as any).router.state = routerState;
(state as any).core = Object.create({});
(state as any).core.auth = notAuthState;
});
// create component and test fixture
fixture = TestBed.createComponent(AuthNavMenuComponent);
// get test component from the fixture
component = fixture.componentInstance;
fixture.detectChanges();
const navMenuSelector = '.navbar-nav';
deNavMenu = fixture.debugElement.query(By.css(navMenuSelector));
const navMenuItemSelector = 'li';
deNavMenuItem = deNavMenu.query(By.css(navMenuItemSelector));
}));
it('should render login dropdown menu', () => {
const loginDropdownMenu = deNavMenuItem.query(By.css('div[id=loginDropdownMenu]'));
expect(loginDropdownMenu.nativeElement).toBeDefined();
});
});
describe('when user is authenticated', () => {
beforeEach(inject([Store], (store: Store<AppState>) => {
routerState = {
url: '/home'
};
store
.subscribe((state) => {
(state as any).router = Object.create({});
(state as any).router.state = routerState;
(state as any).core = Object.create({});
(state as any).core.auth = authState;
});
// create component and test fixture
fixture = TestBed.createComponent(AuthNavMenuComponent);
// get test component from the fixture
component = fixture.componentInstance;
fixture.detectChanges();
const navMenuSelector = '.navbar-nav';
deNavMenu = fixture.debugElement.query(By.css(navMenuSelector));
const navMenuItemSelector = 'li';
deNavMenuItem = deNavMenu.query(By.css(navMenuItemSelector));
}));
it('should render logout dropdown menu', () => {
const logoutDropdownMenu = deNavMenuItem.query(By.css('div[id=logoutDropdownMenu]'));
expect(logoutDropdownMenu.nativeElement).toBeDefined();
});
})
})
});
describe('when is a mobile view', () => {
beforeEach(async(() => {
const window = new HostWindowServiceStub(300);
// refine the test module by declaring the test component
TestBed.configureTestingModule({
imports: [
NoopAnimationsModule,
StoreModule.forRoot(authReducer),
TranslateModule.forRoot()
],
declarations: [
AuthNavMenuComponent
],
providers: [
{provide: HostWindowService, useValue: window},
],
schemas: [
CUSTOM_ELEMENTS_SCHEMA
]
})
.compileComponents();
}));
describe('when user is not authenticated', () => {
beforeEach(inject([Store], (store: Store<AppState>) => {
store
.subscribe((state) => {
(state as any).router = Object.create({});
(state as any).router.state = routerState;
(state as any).core = Object.create({});
(state as any).core.auth = notAuthState;
});
// create component and test fixture
fixture = TestBed.createComponent(AuthNavMenuComponent);
// get test component from the fixture
component = fixture.componentInstance;
fixture.detectChanges();
const navMenuSelector = '.navbar-nav';
deNavMenu = fixture.debugElement.query(By.css(navMenuSelector));
const navMenuItemSelector = 'li';
deNavMenuItem = deNavMenu.query(By.css(navMenuItemSelector));
}));
it('should render login link', () => {
const loginDropdownMenu = deNavMenuItem.query(By.css('a[id=loginLink]'));
expect(loginDropdownMenu.nativeElement).toBeDefined();
});
});
describe('when user is authenticated', () => {
beforeEach(inject([Store], (store: Store<AppState>) => {
store
.subscribe((state) => {
(state as any).router = Object.create({});
(state as any).router.state = routerState;
(state as any).core = Object.create({});
(state as any).core.auth = authState;
});
// create component and test fixture
fixture = TestBed.createComponent(AuthNavMenuComponent);
// get test component from the fixture
component = fixture.componentInstance;
fixture.detectChanges();
const navMenuSelector = '.navbar-nav';
deNavMenu = fixture.debugElement.query(By.css(navMenuSelector));
const navMenuItemSelector = 'li';
deNavMenuItem = deNavMenu.query(By.css(navMenuItemSelector));
}));
it('should render logout link', inject([Store], (store: Store<AppState>) => {
const logoutDropdownMenu = deNavMenuItem.query(By.css('a[id=logoutLink]'));
expect(logoutDropdownMenu.nativeElement).toBeDefined();
}));
})
})
});

View File

@@ -1,33 +1,34 @@
/* tslint:disable:no-unused-variable */
/*import { CUSTOM_ELEMENTS_SCHEMA, DebugElement } from '@angular/core';
import { ComponentFixture, TestBed, async } from '@angular/core/testing';
import { FormBuilder, FormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms';
import { MaterialModule } from '@angular/material';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { async, ComponentFixture, inject, TestBed } from '@angular/core/testing';
import { FormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms';
import { By } from '@angular/platform-browser';
import { Store, StoreModule } from '@ngrx/store';
import { go } from '@ngrx/router-store';
// reducers
import { reducer } from '../../app.reducers';
// models
import { User } from '../../core/models/user';
// services
import { MOCK_USER } from '../../core/services/user.service';
// this component to test
import { LogInComponent } from './log-in.component';
import { authReducer } from '../../core/auth/auth.reducers';
import { EpersonMock } from '../testing/eperson-mock';
import { Eperson } from '../../core/eperson/models/eperson.model';
import { TranslateModule } from '@ngx-translate/core';
import { AuthService } from '../../core/auth/auth.service';
import { AuthServiceStub } from '../testing/auth-service-stub';
import { AppState } from '../../app.reducer';
describe('LogInComponent', () => {
let component: LogInComponent;
let fixture: ComponentFixture<LogInComponent>;
let page: Page;
let user: User = new User();
let user: Eperson;
const authState = {
authenticated: false,
loaded: false,
loading: false,
};
beforeEach(() => {
user = MOCK_USER;
user = EpersonMock;
});
beforeEach(async(() => {
@@ -35,27 +36,37 @@ describe('LogInComponent', () => {
TestBed.configureTestingModule({
imports: [
FormsModule,
MaterialModule,
ReactiveFormsModule,
StoreModule.provideStore(reducer)
StoreModule.forRoot(authReducer),
TranslateModule.forRoot()
],
declarations: [
LogInComponent
],
providers: [
{provide: AuthService, useClass: AuthServiceStub}
],
schemas: [
CUSTOM_ELEMENTS_SCHEMA
]
})
.compileComponents();
.compileComponents();
}));
beforeEach(inject([Store], (store: Store<AppState>) => {
store
.subscribe((state) => {
(state as any).core = Object.create({});
(state as any).core.auth = authState;
});
// create component and test fixture
fixture = TestBed.createComponent(LogInComponent);
// get test component from the fixture
component = fixture.componentInstance;
}));
beforeEach(() => {
// create page
page = new Page(component, fixture);
@@ -63,7 +74,8 @@ describe('LogInComponent', () => {
fixture.whenStable().then(() => {
page.addPageElements();
});
});
}));
it('should create a FormGroup comprised of FormControls', () => {
fixture.detectChanges();
@@ -74,8 +86,8 @@ describe('LogInComponent', () => {
fixture.detectChanges();
// set FormControl values
component.form.controls['email'].setValue(user.email);
component.form.controls['password'].setValue(user.password);
component.form.controls.email.setValue('user');
component.form.controls.password.setValue('password');
// submit form
component.submit();
@@ -90,7 +102,6 @@ describe('LogInComponent', () => {
*
* @class Page
*/
/*
class Page {
public emailInput: HTMLInputElement;
@@ -103,16 +114,14 @@ class Page {
const store = injector.get(Store);
// add spies
this.navigateSpy = spyOn(store, 'dispatch');
this.navigateSpy = spyOn(store, 'dispatch');
}
public addPageElements() {
const emailInputSelector = 'input[formcontrolname=\'email\']';
// console.log(this.fixture.debugElement.query(By.css(emailInputSelector)));
this.emailInput = this.fixture.debugElement.query(By.css(emailInputSelector)).nativeElement;
const passwordInputSelector = 'input[formcontrolname=\'password\']';
this.passwordInput = this.fixture.debugElement.query(By.css(passwordInputSelector)).nativeElement;
}
}
*/

View File

@@ -1,46 +1,108 @@
/* tslint:disable:no-unused-variable */
/*import { DebugElement, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { Router } from '@angular/router';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { async, ComponentFixture, inject, TestBed } from '@angular/core/testing';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
// import ngrx
import { Store, StoreModule } from '@ngrx/store';
// reducers
import { reducer } from '../../app.reducers';
import { authReducer } from '../../core/auth/auth.reducers';
import { EpersonMock } from '../testing/eperson-mock';
import { Eperson } from '../../core/eperson/models/eperson.model';
import { TranslateModule } from '@ngx-translate/core';
import { Router } from '@angular/router';
import { AppState } from '../../app.reducer';
import { LogOutComponent } from './log-out.component';
import { RouterStub } from '../testing/router-stub';
// test this component
import { SignOutComponent } from './log-out.component';
describe('LogOutComponent', () => {
describe('Component: Signout', () => {
let component: SignOutComponent;
let fixture: ComponentFixture<SignOutComponent>;
let component: LogOutComponent;
let fixture: ComponentFixture<LogOutComponent>;
let page: Page;
let user: Eperson;
const authState = {
authenticated: false,
loaded: false,
loading: false,
};
const routerStub = new RouterStub();
beforeEach(() => {
user = EpersonMock;
});
beforeEach(async(() => {
// refine the test module by declaring the test component
TestBed.configureTestingModule({
imports: [
StoreModule.provideStore(reducer)
FormsModule,
ReactiveFormsModule,
StoreModule.forRoot(authReducer),
TranslateModule.forRoot()
],
declarations: [
SignOutComponent
LogOutComponent
],
providers: [
{provide: Router, useValue: routerStub},
],
schemas: [
CUSTOM_ELEMENTS_SCHEMA
]
})
.compileComponents();
.compileComponents();
}));
beforeEach(inject([Store], (store: Store<AppState>) => {
store
.subscribe((state) => {
(state as any).core = Object.create({});
(state as any).core.auth = authState;
});
// create component and test fixture
fixture = TestBed.createComponent(SignOutComponent);
fixture = TestBed.createComponent(LogOutComponent);
// get test component from the fixture
component = fixture.componentInstance;
// create page
page = new Page(component, fixture);
}));
it('should create an instance', () => {
expect(component).toBeTruthy();
expect(component).toBeTruthy();
});
it('should log out', () => {
fixture.detectChanges();
// submit form
component.logOut();
// verify Store.dispatch() is invoked
expect(page.navigateSpy.calls.any()).toBe(true, 'Store.dispatch not invoked');
});
});
*/
/**
* I represent the DOM elements and attach spies.
*
* @class Page
*/
class Page {
public navigateSpy: jasmine.Spy;
constructor(private component: LogOutComponent, private fixture: ComponentFixture<LogOutComponent>) {
// use injector to get services
const injector = fixture.debugElement.injector;
const store = injector.get(Store);
// add spies
this.navigateSpy = spyOn(store, 'dispatch');
}
}

View File

@@ -0,0 +1,6 @@
export class AuthServiceStub {
public redirectToPreviousUrl() {
return;
}
}