aboutsummaryrefslogtreecommitdiff
path: root/Timeline/ClientApp/src/app/user/user-dialog
diff options
context:
space:
mode:
Diffstat (limited to 'Timeline/ClientApp/src/app/user/user-dialog')
-rw-r--r--Timeline/ClientApp/src/app/user/user-dialog/user-dialog.component.css5
-rw-r--r--Timeline/ClientApp/src/app/user/user-dialog/user-dialog.component.html5
-rw-r--r--Timeline/ClientApp/src/app/user/user-dialog/user-dialog.component.spec.ts114
-rw-r--r--Timeline/ClientApp/src/app/user/user-dialog/user-dialog.component.ts43
4 files changed, 167 insertions, 0 deletions
diff --git a/Timeline/ClientApp/src/app/user/user-dialog/user-dialog.component.css b/Timeline/ClientApp/src/app/user/user-dialog/user-dialog.component.css
new file mode 100644
index 00000000..a443e3c0
--- /dev/null
+++ b/Timeline/ClientApp/src/app/user/user-dialog/user-dialog.component.css
@@ -0,0 +1,5 @@
+.container {
+ display: flex;
+ justify-content: center;
+ align-content: center;
+}
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
new file mode 100644
index 00000000..50d6ba56
--- /dev/null
+++ b/Timeline/ClientApp/src/app/user/user-dialog/user-dialog.component.html
@@ -0,0 +1,5 @@
+<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>
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
new file mode 100644
index 00000000..d24c0cd2
--- /dev/null
+++ b/Timeline/ClientApp/src/app/user/user-dialog/user-dialog.component.spec.ts
@@ -0,0 +1,114 @@
+import { Component, Output, EventEmitter } from '@angular/core';
+import { async, ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing';
+import { By } from '@angular/platform-browser';
+import { of } 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';
+
+@Component({
+ /* tslint:disable-next-line:component-selector*/
+ selector: 'mat-progress-spinner',
+ template: ''
+})
+class MatProgressSpinnerStubComponent { }
+
+@Component({
+ selector: 'app-user-login',
+ /* tslint:disable-next-line:use-input-property-decorator*/
+ inputs: ['message'],
+ template: ''
+})
+class UserLoginStubComponent {
+ @Output()
+ login = new EventEmitter<LoginEvent>();
+}
+
+@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>;
+
+ beforeEach(async(() => {
+ mockUserService = jasmine.createSpyObj('UserService', ['validateUserLoginState', 'tryLogin']);
+
+ TestBed.configureTestingModule({
+ declarations: [UserDialogComponent, MatProgressSpinnerStubComponent,
+ UserLoginStubComponent, UserLoginSuccessStubComponent],
+ providers: [{ provide: UserService, useValue: mockUserService }]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(UserDialogComponent);
+ component = fixture.componentInstance;
+ });
+
+ it('progress spinner should work well', fakeAsync(() => {
+ mockUserService.validateUserLoginState.and.returnValue(of(<UserLoginState>{ state: 'nologin' }).pipe(delay(10)));
+ fixture.detectChanges();
+ expect(fixture.debugElement.query(By.css('mat-progress-spinner'))).toBeTruthy();
+ tick(10);
+ fixture.detectChanges();
+ expect(fixture.debugElement.query(By.css('mat-progress-spinner'))).toBeFalsy();
+ }));
+
+ it('nologin 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();
+ });
+
+ it('success should work well', () => {
+ mockUserService.validateUserLoginState.and.returnValue(of(<UserLoginState>{ state: 'success', userInfo: {} }));
+
+ 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();
+ });
+
+ 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'
+ });
+
+ 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();
+ });
+});
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
new file mode 100644
index 00000000..7511de16
--- /dev/null
+++ b/Timeline/ClientApp/src/app/user/user-dialog/user-dialog.component.ts
@@ -0,0 +1,43 @@
+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';
+
+@Component({
+ selector: 'app-user-dialog',
+ templateUrl: './user-dialog.component.html',
+ styleUrls: ['./user-dialog.component.css']
+})
+export class UserDialogComponent implements OnInit {
+
+ constructor(private userService: UserService) { }
+
+ state: 'loading' | 'login' | 'success' = 'loading';
+
+ loginMessage: LoginMessage;
+
+ displayLoginSuccessMessage = false;
+ userInfo: UserInfo;
+
+ ngOnInit() {
+ this.userService.validateUserLoginState().subscribe(result => {
+ if (result.state === 'success') {
+ this.userInfo = result.userInfo;
+ this.state = 'success';
+ } else {
+ this.loginMessage = result.state;
+ this.state = 'login';
+ }
+ });
+ }
+
+ 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;
+ });
+ }
+}