diff --git a/client/src/app/core/containers/app.component.spec.ts b/client/src/app/core/containers/app.component.spec.ts index 49336f78e39111fb5200f7f60fc55ed08c608e96..ad205840c6623e5ecf5d50c8abb035939390e6f5 100644 --- a/client/src/app/core/containers/app.component.spec.ts +++ b/client/src/app/core/containers/app.component.spec.ts @@ -7,6 +7,8 @@ import { provideMockStore, MockStore } from '@ngrx/store/testing'; import { AppComponent } from './app.component'; import { AppConfigService } from 'src/app/app-config.service'; import * as authActions from 'src/app/auth/auth.actions'; +import * as attributeActions from '../../metamodel/actions/attribute.actions'; +import * as instanceActions from '../../metamodel/actions/instance.actions'; describe('AppComponent', () => { let component: AppComponent; @@ -31,37 +33,47 @@ describe('AppComponent', () => { config = TestBed.inject(AppConfigService); })); - it('should create the app', () => { + it('should create the component', () => { expect(component).toBeDefined(); }); - it('authenticationEnabled() should give authentication enabled config key value', () => { + it('should execute ngOnInit lifecycle', (done) => { + const spy = jest.spyOn(store, 'dispatch'); + component.ngOnInit(); + Promise.resolve(null).then(function() { + expect(spy).toHaveBeenCalledTimes(1); + expect(spy).toHaveBeenCalledWith(instanceActions.loadInstanceList()); + done(); + }); + }); + + it('#authenticationEnabled() should return authentication enabled config key value', () => { config.authenticationEnabled = true; expect(component.authenticationEnabled()).toBeTruthy(); }); - it('login() should dispatch login action', () => { + it('#login() should dispatch login action', () => { const spy = jest.spyOn(store, 'dispatch'); component.login(); expect(spy).toHaveBeenCalledTimes(1); expect(spy).toHaveBeenCalledWith(authActions.login()); }); - it('logout() should dispatch logout action', () => { + it('#logout() should dispatch logout action', () => { const spy = jest.spyOn(store, 'dispatch'); component.logout(); expect(spy).toHaveBeenCalledTimes(1); expect(spy).toHaveBeenCalledWith(authActions.logout()); }); - it('openEditProfile() should dispatch open edit profile action', () => { + it('#openEditProfile() should dispatch open edit profile action', () => { const spy = jest.spyOn(store, 'dispatch'); component.openEditProfile(); expect(spy).toHaveBeenCalledTimes(1); expect(spy).toHaveBeenCalledWith(authActions.openEditProfile()); }); - it('isAnisAdmin() should return observable true if user is authenticated', () => { + it('#isAnisAdmin() should return observable true if user is authenticated', () => { component.userRoles = of(['user']); component.isAnisAdmin().subscribe(isAuthenticated => expect(isAuthenticated).toBeFalsy()); component.userRoles = of(['user', 'anis_admin']); diff --git a/client/src/app/core/containers/app.component.ts b/client/src/app/core/containers/app.component.ts index a13a317e99275634ec5bf57f9d3814f74161e874..713bf7fe3adf636e17b656cca37f99325a42a995 100644 --- a/client/src/app/core/containers/app.component.ts +++ b/client/src/app/core/containers/app.component.ts @@ -21,13 +21,17 @@ import * as instanceSelector from 'src/app/metamodel/selectors/instance.selector import { UserProfile } from '../../auth/user-profile.model'; import { AppConfigService } from '../../app-config.service'; +/** + * @class + * @classdesc App container. + */ @Component({ selector: 'app-root', templateUrl: './app.component.html' }) export class AppComponent implements OnInit { public anisClientVersion: string = '3.7.0'; - public year = (new Date()).getFullYear(); + public year: number = (new Date()).getFullYear(); public instanceListIsLoading: Observable<boolean>; public instanceListIsLoaded: Observable<boolean>; public isAuthenticated: Observable<boolean>; @@ -43,26 +47,47 @@ export class AppComponent implements OnInit { } ngOnInit() { + // Create a micro task that is processed after the current synchronous code + // This micro task prevent the expression has changed after view init error Promise.resolve(null).then(() => this.store.dispatch(instanceActions.loadInstanceList())); } + /** + * Checks if authentication is enabled. + * + * @return boolean + */ authenticationEnabled(): boolean { return this.config.authenticationEnabled; } + /** + * Checks if authentication is enabled. + */ login(): void { this.store.dispatch(authActions.login()); } + /** + * Dispatches action to log in. + */ logout(): void { this.store.dispatch(authActions.logout()); } + /** + * Dispatches action to open profile editor. + */ openEditProfile(): void { this.store.dispatch(authActions.openEditProfile()); } - isAnisAdmin() { + /** + * Checks if user is ANIS administrator. + * + * @return Observable<boolean> + */ + isAnisAdmin(): Observable<boolean> { return this.userRoles.pipe( map(roles => roles.includes('anis_admin')) ); diff --git a/client/src/app/core/containers/not-found-page.component.spec.ts b/client/src/app/core/containers/not-found-page.component.spec.ts index 96dabccdf7c2923c7fd8b31e450f5b092d6addaa..07458183633d906d2b1ce5c2b1cb5f580a041896 100644 --- a/client/src/app/core/containers/not-found-page.component.spec.ts +++ b/client/src/app/core/containers/not-found-page.component.spec.ts @@ -18,7 +18,7 @@ describe('NotFoundPageComponent', () => { component = fixture.componentInstance; })); - it('should create the not found page component', () => { + it('should create the component', () => { expect(component).toBeDefined(); }); }); diff --git a/client/src/app/core/containers/not-found-page.component.ts b/client/src/app/core/containers/not-found-page.component.ts index ffddb6ac578034e457491a59f3553741ca12cfd2..1e4a0b51a83cd97c8a71fad941cbddfa1a2cd902 100644 --- a/client/src/app/core/containers/not-found-page.component.ts +++ b/client/src/app/core/containers/not-found-page.component.ts @@ -9,12 +9,12 @@ import { Component } from '@angular/core'; -@Component({ - selector: 'app-not-found-page', - templateUrl: 'not-found-page.component.html' -}) /** * @class * @classdesc Not found page container. */ +@Component({ + selector: 'app-not-found-page', + templateUrl: 'not-found-page.component.html' +}) export class NotFoundPageComponent { } diff --git a/client/src/app/core/containers/unauthorized.component.html b/client/src/app/core/containers/unauthorized.component.html index becf4b8eb909051595b0a3a2e989989a8c6558f0..0f725cf52e46f708e499b2b941f5c0a26066a944 100644 --- a/client/src/app/core/containers/unauthorized.component.html +++ b/client/src/app/core/containers/unauthorized.component.html @@ -1,8 +1,8 @@ <main role="main" class="container-fluid pb-4"> <div class="container"> <div class="text-center"> - <img class="mb-4" src="assets/cesam_anis80.png" alt=""> - + <img class="mb-4" src="assets/cesam_anis80.png" alt="ANIS logo"> + <p> You are not authorized to navigate to this interface (403).<br /> Please contact the administrator to increase your access rights. diff --git a/client/src/app/core/containers/unauthorized.component.spec.ts b/client/src/app/core/containers/unauthorized.component.spec.ts index 51a3acc62289172bc5dbbf79227cb3b40da9af16..7d383e5bbb1b02b378af7bb7dc01c480987965d0 100644 --- a/client/src/app/core/containers/unauthorized.component.spec.ts +++ b/client/src/app/core/containers/unauthorized.component.spec.ts @@ -18,7 +18,7 @@ describe('UnauthorizedComponent', () => { component = fixture.componentInstance; })); - it('should create the unauthorized component', () => { + it('should create the component', () => { expect(component).toBeDefined(); }); }); diff --git a/client/src/app/core/containers/unauthorized.component.ts b/client/src/app/core/containers/unauthorized.component.ts index 6567df192b3a61a8eb72d622f9efa38193459d22..ad4d069214ca321fbb10a2b87fd2a3df7268f776 100644 --- a/client/src/app/core/containers/unauthorized.component.ts +++ b/client/src/app/core/containers/unauthorized.component.ts @@ -1,5 +1,18 @@ +/** + * This file is part of Anis Client. + * + * @copyright Laboratoire d'Astrophysique de Marseille / CNRS + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + import { Component } from '@angular/core'; +/** + * @class + * @classdesc Unauthorized container. + */ @Component({ selector: 'app-unauthorized', templateUrl: 'unauthorized.component.html' diff --git a/client/src/app/core/core.module.ts b/client/src/app/core/core.module.ts index 45581a8c53bd35ba20747f1e8fe72d2bfdacb1df..76633d13679147649ab2094c02e23956de6c4893 100644 --- a/client/src/app/core/core.module.ts +++ b/client/src/app/core/core.module.ts @@ -11,15 +11,20 @@ import { NgModule, Optional, SkipSelf } from '@angular/core'; import { CommonModule } from '@angular/common'; import { RouterModule } from '@angular/router'; +import { ToastrModule } from 'ngx-toastr'; + import { AppComponent } from './containers/app.component'; import { NotFoundPageComponent } from './containers/not-found-page.component'; -import { ToastrModule } from 'ngx-toastr'; export const COMPONENTS = [ AppComponent, NotFoundPageComponent ]; +/** + * @class + * @classdesc Core module. + */ @NgModule({ imports: [ CommonModule,