diff options
Diffstat (limited to 'Timeline/ClientApp/src/app/user/user-dialog')
3 files changed, 55 insertions, 85 deletions
diff --git a/Timeline/ClientApp/src/app/user/user-dialog/user-dialog.component.html b/Timeline/ClientApp/src/app/user/user-dialog/user-dialog.component.html index 50d6ba56..58dff0e4 100644 --- a/Timeline/ClientApp/src/app/user/user-dialog/user-dialog.component.html +++ b/Timeline/ClientApp/src/app/user/user-dialog/user-dialog.component.html @@ -1,5 +1,4 @@ -<div [ngSwitch]="state" class="container"> - <mat-progress-spinner *ngSwitchCase="'loading'" mode="indeterminate" diameter="50"></mat-progress-spinner> - <app-user-login *ngSwitchCase="'login'" (login)="login($event)" [message]="loginMessage"></app-user-login> - <app-user-login-success *ngSwitchCase="'success'" [userInfo]="userInfo" [displayLoginSuccessMessage]="displayLoginSuccessMessage"></app-user-login-success> +<div class="container"> + <mat-progress-spinner *ngIf="isLoading" mode="indeterminate" diameter="50"></mat-progress-spinner> + <router-outlet name="user"></router-outlet> </div> diff --git a/Timeline/ClientApp/src/app/user/user-dialog/user-dialog.component.spec.ts b/Timeline/ClientApp/src/app/user/user-dialog/user-dialog.component.spec.ts index d24c0cd2..c56e1ed1 100644 --- a/Timeline/ClientApp/src/app/user/user-dialog/user-dialog.component.spec.ts +++ b/Timeline/ClientApp/src/app/user/user-dialog/user-dialog.component.spec.ts @@ -1,13 +1,13 @@ -import { Component, Output, EventEmitter } from '@angular/core'; +import { Component } from '@angular/core'; import { async, ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; -import { of } from 'rxjs'; +import { Router, Event } from '@angular/router'; +import { of, Observable } from 'rxjs'; import { delay } from 'rxjs/operators'; -import { UserInfo } from '../user-info'; import { UserDialogComponent } from './user-dialog.component'; -import { UserService, UserLoginState } from '../user-service/user.service'; -import { LoginEvent } from '../user-login/user-login.component'; +import { createMockInternalUserService } from '../internal-user-service/internal-user.service.mock'; +import { InternalUserService, UserLoginState } from '../internal-user-service/internal-user.service'; @Component({ /* tslint:disable-next-line:component-selector*/ @@ -17,36 +17,30 @@ import { LoginEvent } from '../user-login/user-login.component'; class MatProgressSpinnerStubComponent { } @Component({ - selector: 'app-user-login', - /* tslint:disable-next-line:use-input-property-decorator*/ - inputs: ['message'], + /* tslint:disable-next-line:component-selector*/ + selector: 'router-outlet', template: '' }) -class UserLoginStubComponent { - @Output() - login = new EventEmitter<LoginEvent>(); -} +class RouterOutletStubComponent { } -@Component({ - selector: 'app-user-login-success', - /* tslint:disable-next-line:use-input-property-decorator*/ - inputs: ['userInfo', 'displayLoginSuccessMessage'], - template: '' -}) -class UserLoginSuccessStubComponent { } describe('UserDialogComponent', () => { let component: UserDialogComponent; let fixture: ComponentFixture<UserDialogComponent>; - let mockUserService: jasmine.SpyObj<UserService>; + let mockInternalUserService: jasmine.SpyObj<InternalUserService>; + beforeEach(async(() => { - mockUserService = jasmine.createSpyObj('UserService', ['validateUserLoginState', 'tryLogin']); + mockInternalUserService = createMockInternalUserService(); TestBed.configureTestingModule({ - declarations: [UserDialogComponent, MatProgressSpinnerStubComponent, - UserLoginStubComponent, UserLoginSuccessStubComponent], - providers: [{ provide: UserService, useValue: mockUserService }] + declarations: [UserDialogComponent, MatProgressSpinnerStubComponent, RouterOutletStubComponent], + providers: [{ provide: InternalUserService, useValue: mockInternalUserService }, + { // for the workaround + provide: Router, useValue: { + events: new Observable<Event>() + } + }] }) .compileComponents(); })); @@ -57,7 +51,7 @@ describe('UserDialogComponent', () => { }); it('progress spinner should work well', fakeAsync(() => { - mockUserService.validateUserLoginState.and.returnValue(of(<UserLoginState>{ state: 'nologin' }).pipe(delay(10))); + mockInternalUserService.refreshAndGetUserState.and.returnValue(of(<UserLoginState>'nologin').pipe(delay(10))); fixture.detectChanges(); expect(fixture.debugElement.query(By.css('mat-progress-spinner'))).toBeTruthy(); tick(10); @@ -66,49 +60,29 @@ describe('UserDialogComponent', () => { })); it('nologin should work well', () => { - mockUserService.validateUserLoginState.and.returnValue(of(<UserLoginState>{ state: 'nologin' })); + mockInternalUserService.refreshAndGetUserState.and.returnValue(of(<UserLoginState>'nologin')); fixture.detectChanges(); - expect(mockUserService.validateUserLoginState).toHaveBeenCalled(); - expect(fixture.debugElement.query(By.css('app-user-login'))).toBeTruthy(); - expect(fixture.debugElement.query(By.css('app-user-login-success'))).toBeFalsy(); + expect(mockInternalUserService.refreshAndGetUserState).toHaveBeenCalled(); + expect(mockInternalUserService.userRouteNavigate).toHaveBeenCalledWith(['login', { reason: 'nologin' }]); }); - it('success should work well', () => { - mockUserService.validateUserLoginState.and.returnValue(of(<UserLoginState>{ state: 'success', userInfo: {} })); + it('invalid login should work well', () => { + mockInternalUserService.refreshAndGetUserState.and.returnValue(of(<UserLoginState>'invalidlogin')); fixture.detectChanges(); - expect(mockUserService.validateUserLoginState).toHaveBeenCalled(); - expect(fixture.debugElement.query(By.css('app-user-login'))).toBeFalsy(); - expect(fixture.debugElement.query(By.css('app-user-login-success'))).toBeTruthy(); + expect(mockInternalUserService.refreshAndGetUserState).toHaveBeenCalled(); + expect(mockInternalUserService.userRouteNavigate).toHaveBeenCalledWith(['login', { reason: 'invalidlogin' }]); }); - it('login should work well', () => { - mockUserService.validateUserLoginState.and.returnValue(of(<UserLoginState>{ state: 'nologin' })); - - fixture.detectChanges(); - expect(mockUserService.validateUserLoginState).toHaveBeenCalled(); - expect(fixture.debugElement.query(By.css('app-user-login'))).toBeTruthy(); - expect(fixture.debugElement.query(By.css('app-user-login-success'))).toBeFalsy(); - - mockUserService.tryLogin.withArgs('user', 'user').and.returnValue(of(<UserInfo>{ - username: 'user', - roles: ['user'] - })); - - (fixture.debugElement.query(By.css('app-user-login')).componentInstance as - UserLoginStubComponent).login.emit(<LoginEvent>{ - username: 'user', - password: 'user' - }); + it('success should work well', () => { + mockInternalUserService.refreshAndGetUserState.and.returnValue(of(<UserLoginState>'success')); fixture.detectChanges(); - expect(mockUserService.tryLogin).toHaveBeenCalledWith('user', 'user'); - - expect(fixture.debugElement.query(By.css('app-user-login'))).toBeFalsy(); - expect(fixture.debugElement.query(By.css('app-user-login-success'))).toBeTruthy(); + expect(mockInternalUserService.refreshAndGetUserState).toHaveBeenCalled(); + expect(mockInternalUserService.userRouteNavigate).toHaveBeenCalledWith(['success', { reason: 'already' }]); }); }); diff --git a/Timeline/ClientApp/src/app/user/user-dialog/user-dialog.component.ts b/Timeline/ClientApp/src/app/user/user-dialog/user-dialog.component.ts index 7511de16..498ffaa1 100644 --- a/Timeline/ClientApp/src/app/user/user-dialog/user-dialog.component.ts +++ b/Timeline/ClientApp/src/app/user/user-dialog/user-dialog.component.ts @@ -1,43 +1,40 @@ -import { Component, OnInit } from '@angular/core'; -import { UserInfo } from '../user-info'; -import { UserService } from '../user-service/user.service'; -import { LoginEvent, LoginMessage } from '../user-login/user-login.component'; +import { Component, OnInit, OnDestroy, ViewChild } from '@angular/core'; +import { InternalUserService } from '../internal-user-service/internal-user.service'; +import { RouterOutlet, Router, ActivationStart } from '@angular/router'; @Component({ selector: 'app-user-dialog', templateUrl: './user-dialog.component.html', styleUrls: ['./user-dialog.component.css'] }) -export class UserDialogComponent implements OnInit { +export class UserDialogComponent implements OnInit, OnDestroy { - constructor(private userService: UserService) { } + constructor(private userService: InternalUserService, private router: Router) { } - state: 'loading' | 'login' | 'success' = 'loading'; + @ViewChild(RouterOutlet) outlet: RouterOutlet; - loginMessage: LoginMessage; - - displayLoginSuccessMessage = false; - userInfo: UserInfo; + isLoading = true; ngOnInit() { - this.userService.validateUserLoginState().subscribe(result => { - if (result.state === 'success') { - this.userInfo = result.userInfo; - this.state = 'success'; + // this is a workaround for a bug. see https://github.com/angular/angular/issues/20694 + this.router.events.subscribe(e => { + if (e instanceof ActivationStart && e.snapshot.outlet === 'user') { + this.outlet.deactivate(); + } + }); + + + this.userService.refreshAndGetUserState().subscribe(result => { + this.isLoading = false; + if (result === 'success') { + this.userService.userRouteNavigate(['success', { reason: 'already' }]); } else { - this.loginMessage = result.state; - this.state = 'login'; + this.userService.userRouteNavigate(['login', { reason: result }]); } }); } - login(event: LoginEvent) { - this.userService.tryLogin(event.username, event.password).subscribe(result => { - this.userInfo = result; - this.displayLoginSuccessMessage = true; - this.state = 'success'; - }, (error: Error) => { - this.loginMessage = error.message; - }); + ngOnDestroy() { + this.userService.userRouteNavigate(null); } } |