diff options
| author | crupest <crupest@outlook.com> | 2019-03-06 23:14:45 +0800 | 
|---|---|---|
| committer | crupest <crupest@outlook.com> | 2019-03-06 23:14:45 +0800 | 
| commit | 83672dcdced6e0d42fa570d69c91417b3ea88b51 (patch) | |
| tree | 6f35150c47f5c7fa1d2be3177d84e728ce6dcf71 /Timeline/ClientApp/src/app/user | |
| parent | 61844a348b2934321567b1457e6d05f318fc8b7e (diff) | |
| download | timeline-83672dcdced6e0d42fa570d69c91417b3ea88b51.tar.gz timeline-83672dcdced6e0d42fa570d69c91417b3ea88b51.tar.bz2 timeline-83672dcdced6e0d42fa570d69c91417b3ea88b51.zip  | |
Write all unit tests.
Diffstat (limited to 'Timeline/ClientApp/src/app/user')
5 files changed, 256 insertions, 16 deletions
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 884a3710..d24c0cd2 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,25 +1,114 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +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'; -xdescribe('UserDialogComponent', () => { +@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 ] +      declarations: [UserDialogComponent, MatProgressSpinnerStubComponent, +        UserLoginStubComponent, UserLoginSuccessStubComponent], +      providers: [{ provide: UserService, useValue: mockUserService }]      }) -    .compileComponents(); +      .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('should create', () => { -    expect(component).toBeTruthy(); +  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-login-success/user-login-success.component.html b/Timeline/ClientApp/src/app/user/user-login-success/user-login-success.component.html index 943c137f..e156f0f8 100644 --- a/Timeline/ClientApp/src/app/user/user-login-success/user-login-success.component.html +++ b/Timeline/ClientApp/src/app/user/user-login-success/user-login-success.component.html @@ -2,4 +2,4 @@    Login succeeds!  </p>  <p class="mat-body">You have been login as <span class="username">{{ userInfo.username }}</span>.</p> -<p class="mat-body">Your roles are {{ userInfo.roles.join(', ') }}.</p> +<p class="mat-body">Your roles are <span class="roles">{{ userInfo.roles.join(', ') }}</span>.</p> 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 bdcd354b..ba015ae6 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,25 +1,39 @@  import { async, ComponentFixture, TestBed } from '@angular/core/testing';  import { UserLoginSuccessComponent } from './user-login-success.component'; +import { By } from '@angular/platform-browser';  describe('UserLoginSuccessComponent', () => {    let component: UserLoginSuccessComponent;    let fixture: ComponentFixture<UserLoginSuccessComponent>; +  const mockUserInfo = { +    username: 'crupest', +    roles: ['superman', 'coder'] +  }; +    beforeEach(async(() => {      TestBed.configureTestingModule({ -      declarations: [ UserLoginSuccessComponent ] +      declarations: [UserLoginSuccessComponent]      }) -    .compileComponents(); +      .compileComponents();    }));    beforeEach(() => {      fixture = TestBed.createComponent(UserLoginSuccessComponent);      component = fixture.componentInstance; +    component.userInfo = mockUserInfo;      fixture.detectChanges();    });    it('should create', () => {      expect(component).toBeTruthy();    }); + +  it('should work well', () => { +    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(', ')); +  });  }); 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 b606b7b4..acd13721 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,6 +1,9 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +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 { UserLoginComponent } from './user-login.component'; +import { UserLoginComponent, LoginEvent } from './user-login.component';  describe('UserLoginComponent', () => {    let component: UserLoginComponent; @@ -8,9 +11,11 @@ describe('UserLoginComponent', () => {    beforeEach(async(() => {      TestBed.configureTestingModule({ -      declarations: [ UserLoginComponent ] +      declarations: [UserLoginComponent], +      imports: [ReactiveFormsModule], +      schemas: [NO_ERRORS_SCHEMA]      }) -    .compileComponents(); +      .compileComponents();    }));    beforeEach(() => { @@ -22,4 +27,34 @@ describe('UserLoginComponent', () => {    it('should create', () => {      expect(component).toBeTruthy();    }); + +  it('reactive form should work well', () => { +    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; + +    usernameInput.value = 'user'; +    usernameInput.dispatchEvent(new Event('input')); +    passwordInput.value = 'user'; +    passwordInput.dispatchEvent(new Event('input')); + +    fixture.detectChanges(); + +    expect(component.form.value).toEqual({ +      username: 'user', +      password: 'user' +    }); +  }); + +  it('login event should work well', fakeAsync(() => { +    let userCredential: LoginEvent; +    component.login.subscribe((e: LoginEvent) => { userCredential = e; }); +    fixture.detectChanges(); +    const mockValue = { +      username: 'user', +      password: 'user' +    }; +    component.form.setValue(mockValue); +    component.onLoginButtonClick(); +    expect(userCredential).toEqual(mockValue); +  }));  }); diff --git a/Timeline/ClientApp/src/app/user/user-service/user.service.spec.ts b/Timeline/ClientApp/src/app/user/user-service/user.service.spec.ts index b9221b90..28cfefd7 100644 --- a/Timeline/ClientApp/src/app/user/user-service/user.service.spec.ts +++ b/Timeline/ClientApp/src/app/user/user-service/user.service.spec.ts @@ -1,12 +1,114 @@  import { TestBed } from '@angular/core/testing'; +import { HttpRequest } from '@angular/common/http'; +import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; -import { UserService } from './user.service'; +import { UserInfo } from '../user-info'; +import { +  UserService, UserCredentials, CreateTokenResult, +  UserLoginState, TokenValidationRequest, TokenValidationResult +} from './user.service'; -xdescribe('UserService', () => { -  beforeEach(() => TestBed.configureTestingModule({})); +describe('UserService', () => { +  const tokenCreateUrl = '/api/User/CreateToken'; + +  beforeEach(() => TestBed.configureTestingModule({ +    imports: [HttpClientTestingModule] +  }));    it('should be created', () => {      const service: UserService = TestBed.get(UserService);      expect(service).toBeTruthy();    }); + +  it('should be nologin at first', () => { +    const service: UserService = TestBed.get(UserService); +    service.validateUserLoginState().subscribe(result => { +      expect(result.state).toBe('nologin'); +    }); +  }); + +  it('login should work well', () => { +    const service: UserService = TestBed.get(UserService); + +    const mockUserInfo: UserInfo = { +      username: 'user', +      roles: ['user', 'other'] +    }; + +    service.tryLogin('user', 'user').subscribe(result => { +      expect(result).toEqual(mockUserInfo); +    }); + +    const httpController = TestBed.get(HttpTestingController) as HttpTestingController; + +    httpController.expectOne((request: HttpRequest<UserCredentials>) => +      request.url === tokenCreateUrl && +      request.body.username === 'user' && +      request.body.password === 'user').flush(<CreateTokenResult>{ +        token: 'test-token', +        userInfo: mockUserInfo +      }); + +    httpController.verify(); +  }); + +  describe('validateUserLoginState', () => { +    let service: UserService; +    let httpController: HttpTestingController; + +    const mockUserInfo: UserInfo = { +      username: 'user', +      roles: ['user', 'other'] +    }; + +    const mockToken = 'mock-token'; + +    const tokenValidateRequestMatcher = (req: HttpRequest<TokenValidationRequest>) => { +      return req.url === '/api/User/ValidateToken' && req.body.token === mockToken; +    } + +    beforeEach(() => { +      service = TestBed.get(UserService); +      httpController = TestBed.get(HttpTestingController); + +      service.tryLogin('user', 'user').subscribe(); // subscribe to activate login + +      httpController.expectOne(tokenCreateUrl).flush(<CreateTokenResult>{ +        token: mockToken, +        userInfo: mockUserInfo +      }); +    }); + +    it('success should work well', () => { +      service.validateUserLoginState().subscribe((result: UserLoginState) => { +        expect(result).toEqual(<UserLoginState>{ +          state: 'success', +          userInfo: mockUserInfo +        }); +      }); + +      httpController.expectOne(tokenValidateRequestMatcher).flush(<TokenValidationResult>{ +        isValid: true, +        userInfo: mockUserInfo +      }); + +      httpController.verify(); +    }); + +    it('invalid should work well', () => { +      service.validateUserLoginState().subscribe((result: UserLoginState) => { +        expect(result).toEqual(<UserLoginState>{ +          state: 'invalidlogin' +        }); +      }); + +      httpController.expectOne(tokenValidateRequestMatcher).flush(<TokenValidationResult>{ +        isValid: false +      }); + +      httpController.verify(); +    }); +  }); + +  // TODO: test on error situations.  });  | 
