diff options
author | crupest <crupest@outlook.com> | 2019-03-09 23:40:06 +0800 |
---|---|---|
committer | crupest <crupest@outlook.com> | 2019-03-09 23:40:06 +0800 |
commit | e72a1cc3f98e45aee6eb29d3281118fa8373233f (patch) | |
tree | 22bb24a7ecf57b694d131ec6e6f34ef8cce6bb0c /Timeline | |
parent | 76300141a6411c05d585994d5f19938bfe45838e (diff) | |
download | timeline-e72a1cc3f98e45aee6eb29d3281118fa8373233f.tar.gz timeline-e72a1cc3f98e45aee6eb29d3281118fa8373233f.tar.bz2 timeline-e72a1cc3f98e45aee6eb29d3281118fa8373233f.zip |
Half work!
Diffstat (limited to 'Timeline')
5 files changed, 106 insertions, 77 deletions
diff --git a/Timeline/ClientApp/src/app/user/internal-user-service/internal-user.service.spec.ts b/Timeline/ClientApp/src/app/user/internal-user-service/internal-user.service.spec.ts index 4a2c78f8..8aadd873 100644 --- a/Timeline/ClientApp/src/app/user/internal-user-service/internal-user.service.spec.ts +++ b/Timeline/ClientApp/src/app/user/internal-user-service/internal-user.service.spec.ts @@ -1,14 +1,13 @@ import { TestBed } from '@angular/core/testing'; import { HttpRequest } from '@angular/common/http'; import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; +import { Router } from '@angular/router'; import { UserInfo, UserCredentials } from '../entities'; -import { - InternalUserService, CreateTokenResult, - UserLoginState, TokenValidationRequest, TokenValidationResult -} from './internal-user.service'; +import { CreateTokenRequest, CreateTokenResponse, ValidateTokenRequest, ValidateTokenResponse } from './http-entities'; +import { InternalUserService, UserLoginState } from './internal-user.service'; -describe('UserService', () => { +describe('InternalUserService', () => { const tokenCreateUrl = '/api/User/CreateToken'; const mockUserCredentials: UserCredentials = { @@ -17,7 +16,8 @@ describe('UserService', () => { }; beforeEach(() => TestBed.configureTestingModule({ - imports: [HttpClientTestingModule] + imports: [HttpClientTestingModule], + providers: [{ provide: Router, useValue: null }] })); it('should be created', () => { @@ -27,8 +27,9 @@ describe('UserService', () => { it('should be nologin at first', () => { const service: InternalUserService = TestBed.get(InternalUserService); + expect(service.currentUserInfo).toBe(null); service.refreshAndGetUserState().subscribe(result => { - expect(result.state).toBe('nologin'); + expect(result).toBe('nologin'); }); }); @@ -46,14 +47,16 @@ describe('UserService', () => { const httpController = TestBed.get(HttpTestingController) as HttpTestingController; - httpController.expectOne((request: HttpRequest<UserCredentials>) => + httpController.expectOne((request: HttpRequest<CreateTokenRequest>) => request.url === tokenCreateUrl && request.body.username === 'user' && - request.body.password === 'user').flush(<CreateTokenResult>{ + request.body.password === 'user').flush(<CreateTokenResponse>{ token: 'test-token', userInfo: mockUserInfo }); + expect(service.currentUserInfo).toEqual(mockUserInfo); + httpController.verify(); }); @@ -68,7 +71,7 @@ describe('UserService', () => { const mockToken = 'mock-token'; - const tokenValidateRequestMatcher = (req: HttpRequest<TokenValidationRequest>) => { + const tokenValidateRequestMatcher = (req: HttpRequest<ValidateTokenRequest>) => { return req.url === '/api/User/ValidateToken' && req.body.token === mockToken; }; @@ -78,7 +81,7 @@ describe('UserService', () => { service.tryLogin(mockUserCredentials).subscribe(); // subscribe to activate login - httpController.expectOne(tokenCreateUrl).flush(<CreateTokenResult>{ + httpController.expectOne(tokenCreateUrl).flush(<CreateTokenResponse>{ token: mockToken, userInfo: mockUserInfo }); @@ -86,13 +89,10 @@ describe('UserService', () => { it('success should work well', () => { service.refreshAndGetUserState().subscribe((result: UserLoginState) => { - expect(result).toEqual(<UserLoginState>{ - state: 'success', - userInfo: mockUserInfo - }); + expect(result).toEqual(<UserLoginState>'success'); }); - httpController.expectOne(tokenValidateRequestMatcher).flush(<TokenValidationResult>{ + httpController.expectOne(tokenValidateRequestMatcher).flush(<ValidateTokenResponse>{ isValid: true, userInfo: mockUserInfo }); @@ -102,14 +102,10 @@ describe('UserService', () => { it('invalid should work well', () => { service.refreshAndGetUserState().subscribe((result: UserLoginState) => { - expect(result).toEqual(<UserLoginState>{ - state: 'invalidlogin' - }); + expect(result).toEqual(<UserLoginState>'invalidlogin'); }); - httpController.expectOne(tokenValidateRequestMatcher).flush(<TokenValidationResult>{ - isValid: false - }); + httpController.expectOne(tokenValidateRequestMatcher).flush(<ValidateTokenResponse>{ isValid: false }); httpController.verify(); }); 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/mock-internal-user-service.ts new file mode 100644 index 00000000..f4a85262 --- /dev/null +++ b/Timeline/ClientApp/src/app/user/internal-user-service/mock-internal-user-service.ts @@ -0,0 +1,5 @@ +import { InternalUserService } from './internal-user.service'; + +export function createMockInternalUserService(): jasmine.SpyObj<InternalUserService> { + return jasmine.createSpyObj('InternalUserService', ['userRouteNavigate', 'refreshAndGetUserState', 'tryLogin']); +} diff --git a/Timeline/ClientApp/src/app/user/mock-activated-route.ts b/Timeline/ClientApp/src/app/user/mock-activated-route.ts new file mode 100644 index 00000000..9e516e83 --- /dev/null +++ b/Timeline/ClientApp/src/app/user/mock-activated-route.ts @@ -0,0 +1,43 @@ +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 dd7af6ca..ca7c024d 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 '../entities'; import { UserDialogComponent } from './user-dialog.component'; +import { createMockInternalUserService } from '../internal-user-service/mock-internal-user-service'; import { InternalUserService, UserLoginState } from '../internal-user-service/internal-user.service'; -import { LoginEvent } from '../user-login/user-login.component'; @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<InternalUserService>; + let mockInternalUserService: jasmine.SpyObj<InternalUserService>; + beforeEach(async(() => { - mockUserService = jasmine.createSpyObj('UserService', ['validateUserLoginState', 'tryLogin']); + mockInternalUserService = createMockInternalUserService(); TestBed.configureTestingModule({ - declarations: [UserDialogComponent, MatProgressSpinnerStubComponent, - UserLoginStubComponent, UserLoginSuccessStubComponent], - providers: [{ provide: InternalUserService, 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.refreshAndGetUserState.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.refreshAndGetUserState.and.returnValue(of(<UserLoginState>{ state: 'nologin' })); + mockInternalUserService.refreshAndGetUserState.and.returnValue(of(<UserLoginState>'nologin')); fixture.detectChanges(); - expect(mockUserService.refreshAndGetUserState).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.refreshAndGetUserState.and.returnValue(of(<UserLoginState>{ state: 'success', userInfo: {} })); + it('invalid login should work well', () => { + mockInternalUserService.refreshAndGetUserState.and.returnValue(of(<UserLoginState>'invalidlogin')); fixture.detectChanges(); - expect(mockUserService.refreshAndGetUserState).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.refreshAndGetUserState.and.returnValue(of(<UserLoginState>{ state: 'nologin' })); - - fixture.detectChanges(); - expect(mockUserService.refreshAndGetUserState).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-login/user-login.component.spec.ts b/Timeline/ClientApp/src/app/user/user-login/user-login.component.spec.ts index acd13721..3d431ce7 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 @@ -2,16 +2,27 @@ import { NO_ERRORS_SCHEMA } from '@angular/core'; import { async, ComponentFixture, TestBed, fakeAsync, tick } 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 { InternalUserService } from '../internal-user-service/internal-user.service'; describe('UserLoginComponent', () => { let component: UserLoginComponent; let fixture: ComponentFixture<UserLoginComponent>; + let mockInternalUserService: jasmine.SpyObj<InternalUserService>; beforeEach(async(() => { + mockInternalUserService = createMockInternalUserService(); + TestBed.configureTestingModule({ declarations: [UserLoginComponent], + providers: [ + {provide: InternalUserService, useValue: mockInternalUserService}, + {provide: ActivatedRoute, useValue:} // TODO: custom route snapshot param later. + ] imports: [ReactiveFormsModule], schemas: [NO_ERRORS_SCHEMA] }) |