aboutsummaryrefslogtreecommitdiff
path: root/Timeline
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2019-03-11 00:07:59 +0800
committercrupest <crupest@outlook.com>2019-03-11 00:07:59 +0800
commit31199282e1ccf72bb464117ae68668aed91e2530 (patch)
tree0dbce8aa1953d06237e80761440ab21172c95db9 /Timeline
parente72a1cc3f98e45aee6eb29d3281118fa8373233f (diff)
downloadtimeline-31199282e1ccf72bb464117ae68668aed91e2530.tar.gz
timeline-31199282e1ccf72bb464117ae68668aed91e2530.tar.bz2
timeline-31199282e1ccf72bb464117ae68668aed91e2530.zip
Write unit tests.
Diffstat (limited to 'Timeline')
-rw-r--r--Timeline/ClientApp/src/app/test-utilities/activated-route.mock.ts66
-rw-r--r--Timeline/ClientApp/src/app/user/internal-user-service/internal-user.service.mock.ts (renamed from Timeline/ClientApp/src/app/user/internal-user-service/mock-internal-user-service.ts)0
-rw-r--r--Timeline/ClientApp/src/app/user/mock-activated-route.ts43
-rw-r--r--Timeline/ClientApp/src/app/user/user-dialog/user-dialog.component.spec.ts2
-rw-r--r--Timeline/ClientApp/src/app/user/user-login-success/user-login-success.component.spec.ts40
-rw-r--r--Timeline/ClientApp/src/app/user/user-login/user-login.component.spec.ts74
-rw-r--r--Timeline/ClientApp/src/app/user/user-login/user-login.component.ts6
-rw-r--r--Timeline/ClientApp/src/app/user/user.module.ts2
-rw-r--r--Timeline/ClientApp/src/app/utilities/debounce-click.directive.spec.ts (renamed from Timeline/ClientApp/src/app/utility/debounce-click.directive.spec.ts)0
-rw-r--r--Timeline/ClientApp/src/app/utilities/debounce-click.directive.ts (renamed from Timeline/ClientApp/src/app/utility/debounce-click.directive.ts)0
-rw-r--r--Timeline/ClientApp/src/app/utilities/utility.module.ts (renamed from Timeline/ClientApp/src/app/utility/utility.module.ts)0
11 files changed, 165 insertions, 68 deletions
diff --git a/Timeline/ClientApp/src/app/test-utilities/activated-route.mock.ts b/Timeline/ClientApp/src/app/test-utilities/activated-route.mock.ts
new file mode 100644
index 00000000..1743e615
--- /dev/null
+++ b/Timeline/ClientApp/src/app/test-utilities/activated-route.mock.ts
@@ -0,0 +1,66 @@
+import { ParamMap } from '@angular/router';
+
+import { Observable, BehaviorSubject } from 'rxjs';
+import { map } from 'rxjs/operators';
+
+export interface ParamMapCreator { [name: string]: string | string[]; }
+
+export class MockActivatedRouteSnapshot {
+
+ private paramMapInternal: ParamMap;
+
+ constructor({ mockParamMap }: { mockParamMap: ParamMapCreator } = { mockParamMap: {} }) {
+ this.paramMapInternal = {
+ keys: Object.keys(mockParamMap),
+ get(name: string): string | null {
+ const param = mockParamMap[name];
+ if (typeof param === 'string') {
+ return param;
+ } else if (param instanceof Array) {
+ if (param.length === 0) {
+ return null;
+ }
+ return param[0];
+ }
+ return null;
+ },
+ getAll(name: string): string[] {
+ const param = mockParamMap[name];
+ if (typeof param === 'string') {
+ return [param];
+ } else if (param instanceof Array) {
+ return param;
+ }
+ return [];
+ },
+ has(name: string): boolean {
+ return mockParamMap.hasOwnProperty(name);
+ }
+ };
+ }
+
+ get paramMap(): ParamMap {
+ return this.paramMapInternal;
+ }
+}
+
+export class MockActivatedRoute {
+
+ snapshot$ = new BehaviorSubject<MockActivatedRouteSnapshot>(new MockActivatedRouteSnapshot());
+
+ get paramMap(): Observable<ParamMap> {
+ return this.snapshot$.pipe(map(snapshot => snapshot.paramMap));
+ }
+
+ get snapshot(): MockActivatedRouteSnapshot {
+ return this.snapshot$.value;
+ }
+
+ pushSnapshot(snapshot: MockActivatedRouteSnapshot) {
+ this.snapshot$.next(snapshot);
+ }
+
+ pushSnapshotWithParamMap(mockParamMap: ParamMapCreator) {
+ this.pushSnapshot(new MockActivatedRouteSnapshot({mockParamMap}));
+ }
+}
diff --git a/Timeline/ClientApp/src/app/user/internal-user-service/mock-internal-user-service.ts b/Timeline/ClientApp/src/app/user/internal-user-service/internal-user.service.mock.ts
index f4a85262..f4a85262 100644
--- a/Timeline/ClientApp/src/app/user/internal-user-service/mock-internal-user-service.ts
+++ b/Timeline/ClientApp/src/app/user/internal-user-service/internal-user.service.mock.ts
diff --git a/Timeline/ClientApp/src/app/user/mock-activated-route.ts b/Timeline/ClientApp/src/app/user/mock-activated-route.ts
deleted file mode 100644
index 9e516e83..00000000
--- a/Timeline/ClientApp/src/app/user/mock-activated-route.ts
+++ /dev/null
@@ -1,43 +0,0 @@
-import { ParamMap } from '@angular/router';
-
-interface MockActivatedRoute {
- snapshot: MockActivatedRouteSnapshot;
-}
-
-interface MockActivatedRouteSnapshot {
- paramMap: ParamMap;
-}
-
-export function createMockActivatedRoute(mockParamMap: { [name: string]: string | string[] }): MockActivatedRoute {
- return {
- snapshot: {
- paramMap: {
- keys: Object.keys(mockParamMap),
- get(name: string): string | null {
- const param = mockParamMap[name];
- if (typeof param === 'string') {
- return param;
- } else if (param instanceof Array) {
- if (param.length === 0) {
- return null;
- }
- return param[0];
- }
- return null;
- },
- getAll(name: string): string[] {
- const param = mockParamMap[name];
- if (typeof param === 'string') {
- return [param];
- } else if (param instanceof Array) {
- return param;
- }
- return [];
- },
- has(name: string): boolean {
- return mockParamMap.hasOwnProperty(name);
- }
- }
- }
- }
-}
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 ca7c024d..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
@@ -6,7 +6,7 @@ import { of, Observable } from 'rxjs';
import { delay } from 'rxjs/operators';
import { UserDialogComponent } from './user-dialog.component';
-import { createMockInternalUserService } from '../internal-user-service/mock-internal-user-service';
+import { createMockInternalUserService } from '../internal-user-service/internal-user.service.mock';
import { InternalUserService, UserLoginState } from '../internal-user-service/internal-user.service';
@Component({
diff --git a/Timeline/ClientApp/src/app/user/user-login-success/user-login-success.component.spec.ts b/Timeline/ClientApp/src/app/user/user-login-success/user-login-success.component.spec.ts
index ba015ae6..1efbb5c7 100644
--- a/Timeline/ClientApp/src/app/user/user-login-success/user-login-success.component.spec.ts
+++ b/Timeline/ClientApp/src/app/user/user-login-success/user-login-success.component.spec.ts
@@ -1,20 +1,39 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { By } from '@angular/platform-browser';
+import { ActivatedRoute } from '@angular/router';
+
+import { MockActivatedRoute } from 'src/app/test-utilities/activated-route.mock';
+import { createMockInternalUserService } from '../internal-user-service/internal-user.service.mock';
import { UserLoginSuccessComponent } from './user-login-success.component';
-import { By } from '@angular/platform-browser';
+import { InternalUserService } from '../internal-user-service/internal-user.service';
+
describe('UserLoginSuccessComponent', () => {
let component: UserLoginSuccessComponent;
let fixture: ComponentFixture<UserLoginSuccessComponent>;
+ let mockInternalUserService: jasmine.SpyObj<InternalUserService>;
+ let mockActivatedRoute: MockActivatedRoute;
+
const mockUserInfo = {
username: 'crupest',
roles: ['superman', 'coder']
};
beforeEach(async(() => {
+ mockInternalUserService = createMockInternalUserService();
+ mockActivatedRoute = new MockActivatedRoute();
+
+ // mock currentUserInfo property. because it only has a getter so cast it to any first.
+ (<any>mockInternalUserService).currentUserInfo = mockUserInfo;
+
TestBed.configureTestingModule({
- declarations: [UserLoginSuccessComponent]
+ declarations: [UserLoginSuccessComponent],
+ providers: [
+ { provide: InternalUserService, useValue: mockInternalUserService },
+ { provide: ActivatedRoute, useValue: mockActivatedRoute }
+ ]
})
.compileComponents();
}));
@@ -22,18 +41,29 @@ describe('UserLoginSuccessComponent', () => {
beforeEach(() => {
fixture = TestBed.createComponent(UserLoginSuccessComponent);
component = fixture.componentInstance;
- component.userInfo = mockUserInfo;
- fixture.detectChanges();
});
it('should create', () => {
+ fixture.detectChanges();
expect(component).toBeTruthy();
});
- it('should work well', () => {
+ it('user info should work well', () => {
+ fixture.detectChanges();
+
+ expect((fixture.debugElement.query(By.css('p.login-success-message')))).toBeFalsy();
+
expect((fixture.debugElement.query(By.css('span.username')).nativeElement as HTMLSpanElement).textContent)
.toBe(mockUserInfo.username);
expect((fixture.debugElement.query(By.css('span.roles')).nativeElement as HTMLSpanElement).textContent)
.toBe(mockUserInfo.roles.join(', '));
});
+
+ it('login success message should display well', () => {
+ mockActivatedRoute.pushSnapshotWithParamMap({ reason: 'login' });
+
+ fixture.detectChanges();
+
+ expect((fixture.debugElement.query(By.css('p.login-success-message')))).toBeTruthy();
+ });
});
diff --git a/Timeline/ClientApp/src/app/user/user-login/user-login.component.spec.ts b/Timeline/ClientApp/src/app/user/user-login/user-login.component.spec.ts
index 3d431ce7..9c9ee1dc 100644
--- a/Timeline/ClientApp/src/app/user/user-login/user-login.component.spec.ts
+++ b/Timeline/ClientApp/src/app/user/user-login/user-login.component.spec.ts
@@ -1,28 +1,33 @@
import { NO_ERRORS_SCHEMA } from '@angular/core';
-import { async, ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing';
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ReactiveFormsModule } from '@angular/forms';
import { By } from '@angular/platform-browser';
import { ActivatedRoute } from '@angular/router';
-import { createMockInternalUserService } from '../internal-user-service/mock-internal-user-service';
-import { createMockActivatedRoute } from '../mock-activated-route';
-import { UserLoginComponent, LoginEvent } from './user-login.component';
+import { of, throwError } from 'rxjs';
+
+import { createMockInternalUserService } from '../internal-user-service/internal-user.service.mock';
+import { MockActivatedRoute } from '../../test-utilities/activated-route.mock';
+import { UserLoginComponent } from './user-login.component';
import { InternalUserService } from '../internal-user-service/internal-user.service';
+import { UserInfo } from '../entities';
describe('UserLoginComponent', () => {
let component: UserLoginComponent;
let fixture: ComponentFixture<UserLoginComponent>;
let mockInternalUserService: jasmine.SpyObj<InternalUserService>;
+ let mockActivatedRoute: MockActivatedRoute;
beforeEach(async(() => {
mockInternalUserService = createMockInternalUserService();
+ mockActivatedRoute = new MockActivatedRoute();
TestBed.configureTestingModule({
declarations: [UserLoginComponent],
providers: [
- {provide: InternalUserService, useValue: mockInternalUserService},
- {provide: ActivatedRoute, useValue:} // TODO: custom route snapshot param later.
- ]
+ { provide: InternalUserService, useValue: mockInternalUserService },
+ { provide: ActivatedRoute, useValue: mockActivatedRoute }
+ ],
imports: [ReactiveFormsModule],
schemas: [NO_ERRORS_SCHEMA]
})
@@ -32,14 +37,16 @@ describe('UserLoginComponent', () => {
beforeEach(() => {
fixture = TestBed.createComponent(UserLoginComponent);
component = fixture.componentInstance;
- fixture.detectChanges();
});
it('should create', () => {
+ fixture.detectChanges();
expect(component).toBeTruthy();
});
it('reactive form should work well', () => {
+ fixture.detectChanges();
+
const usernameInput = fixture.debugElement.query(By.css('input[type=text]')).nativeElement as HTMLInputElement;
const passwordInput = fixture.debugElement.query(By.css('input[type=password]')).nativeElement as HTMLInputElement;
@@ -56,16 +63,57 @@ describe('UserLoginComponent', () => {
});
});
- it('login event should work well', fakeAsync(() => {
- let userCredential: LoginEvent;
- component.login.subscribe((e: LoginEvent) => { userCredential = e; });
+ it('login should work well', () => {
fixture.detectChanges();
+
const mockValue = {
username: 'user',
password: 'user'
};
+
+ mockInternalUserService.tryLogin.withArgs(mockValue).and.returnValue(of(<UserInfo>{ username: 'user', roles: ['user'] }));
+
component.form.setValue(mockValue);
component.onLoginButtonClick();
- expect(userCredential).toEqual(mockValue);
- }));
+
+ expect(mockInternalUserService.tryLogin).toHaveBeenCalledWith(mockValue);
+ expect(mockInternalUserService.userRouteNavigate).toHaveBeenCalledWith(['success', { reason: 'login' }]);
+ });
+
+ describe('message display', () => {
+ it('nologin reason should display', () => {
+ mockActivatedRoute.pushSnapshotWithParamMap({ reason: 'nologin' });
+ fixture.detectChanges();
+ expect(component.message).toBe('nologin');
+ expect((fixture.debugElement.query(By.css('p.mat-body')).nativeElement as
+ HTMLParagraphElement).textContent).toBe('You haven\'t login.');
+ });
+
+ it('invalid login reason should display', () => {
+ mockActivatedRoute.pushSnapshotWithParamMap({ reason: 'invalidlogin' });
+ fixture.detectChanges();
+ expect(component.message).toBe('invalidlogin');
+ expect((fixture.debugElement.query(By.css('p.mat-body')).nativeElement as
+ HTMLParagraphElement).textContent).toBe('Your login is no longer valid.');
+ });
+
+ it('custom error message should display', () => {
+ const customMessage = 'custom message';
+
+ fixture.detectChanges();
+
+ const mockValue = {
+ username: 'user',
+ password: 'user'
+ };
+ mockInternalUserService.tryLogin.withArgs(mockValue).and.returnValue(throwError(new Error(customMessage)));
+ component.form.setValue(mockValue);
+ component.onLoginButtonClick();
+
+ fixture.detectChanges();
+ expect(component.message).toBe(customMessage);
+ expect((fixture.debugElement.query(By.css('p.mat-body')).nativeElement as
+ HTMLParagraphElement).textContent).toBe(customMessage);
+ });
+ });
});
diff --git a/Timeline/ClientApp/src/app/user/user-login/user-login.component.ts b/Timeline/ClientApp/src/app/user/user-login/user-login.component.ts
index 082f879c..79a788de 100644
--- a/Timeline/ClientApp/src/app/user/user-login/user-login.component.ts
+++ b/Timeline/ClientApp/src/app/user/user-login/user-login.component.ts
@@ -1,4 +1,4 @@
-import { Component, Output, OnInit, EventEmitter } from '@angular/core';
+import { Component, OnInit } from '@angular/core';
import { FormGroup, FormControl } from '@angular/forms';
import { ActivatedRoute } from '@angular/router';
@@ -6,10 +6,6 @@ import { InternalUserService } from '../internal-user-service/internal-user.serv
export type LoginMessage = 'nologin' | 'invalidlogin' | string;
-export class LoginEvent {
- username: string;
- password: string;
-}
@Component({
selector: 'app-user-login',
diff --git a/Timeline/ClientApp/src/app/user/user.module.ts b/Timeline/ClientApp/src/app/user/user.module.ts
index 1e70d33d..c399c9e0 100644
--- a/Timeline/ClientApp/src/app/user/user.module.ts
+++ b/Timeline/ClientApp/src/app/user/user.module.ts
@@ -10,7 +10,7 @@ import {
import { UserDialogComponent } from './user-dialog/user-dialog.component';
import { UserLoginComponent } from './user-login/user-login.component';
import { UserLoginSuccessComponent } from './user-login-success/user-login-success.component';
-import { UtilityModule } from '../utility/utility.module';
+import { UtilityModule } from '../utilities/utility.module';
import { RouterModule } from '@angular/router';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
diff --git a/Timeline/ClientApp/src/app/utility/debounce-click.directive.spec.ts b/Timeline/ClientApp/src/app/utilities/debounce-click.directive.spec.ts
index 75710d0c..75710d0c 100644
--- a/Timeline/ClientApp/src/app/utility/debounce-click.directive.spec.ts
+++ b/Timeline/ClientApp/src/app/utilities/debounce-click.directive.spec.ts
diff --git a/Timeline/ClientApp/src/app/utility/debounce-click.directive.ts b/Timeline/ClientApp/src/app/utilities/debounce-click.directive.ts
index feb0404e..feb0404e 100644
--- a/Timeline/ClientApp/src/app/utility/debounce-click.directive.ts
+++ b/Timeline/ClientApp/src/app/utilities/debounce-click.directive.ts
diff --git a/Timeline/ClientApp/src/app/utility/utility.module.ts b/Timeline/ClientApp/src/app/utilities/utility.module.ts
index dd686bf7..dd686bf7 100644
--- a/Timeline/ClientApp/src/app/utility/utility.module.ts
+++ b/Timeline/ClientApp/src/app/utilities/utility.module.ts