I am new to writing Jasmine test cases. I have created LoginComponent which will then use AuthService to check the server and return the observable based on the response I will decide and display information appropriately.
As part of writing unit test cases for this component, I need to test valid user and invalid user login.
Scenario1: Invalid login
login method calls AuthService.login() which will be subscribed and if error the message will be displayed on the login page.
Scenario2: Valid Login Here if the resp contains some token we will consider it as authenticated and route to the home screen.
I tried to check the Invalid scenario and facing issues.
login.component.ts
import { HttpErrorResponse, HttpResponse } from '@angular/common/http';
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { AuthService } from '../service/auth.service';
@Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
constructor(private authService: AuthService, private router:Router, private activeRoute:ActivatedRoute) { }
email:string;
password:string;
message:string;
ngOnInit() {
}
submitForm()
{
this.authService.login({username: this.email, password: this.password}).subscribe
(
(resp) =>
{
if(resp['status'] == 200 )
{
sessionStorage.setItem('UserAuthenticated', 'true');
sessionStorage.setItem('Jwt_Token', resp['JWT_Token']);
this.router.navigate(['/dashboard'])
}
},
(errorResp: HttpErrorResponse) =>
{
console.log(errorResp)
this.message = errorResp['error']['errorMessage'];
}
);
}
}
auth.service.ts
import { HttpClient, HttpErrorResponse, HttpResponse } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
import { environment } from 'src/environments/environment';
import { URLMapping } from '../shared/URLMapping';
@Injectable({
providedIn: 'root'
})
export class AuthService {
constructor(private http: HttpClient) { }
login(data:object)
{
return this.http.post(environment.applicationURL URLMapping.LOGIN, data);
}
}
login.component.spec.ts
import { HttpClientModule, HttpErrorResponse } from '@angular/common/http';
import { DebugElement } from '@angular/core';
import { async, ComponentFixture, ComponentFixtureAutoDetect, fakeAsync, TestBed, tick } from '@angular/core/testing';
import { FormsModule } from '@angular/forms';
import { By } from '@angular/platform-browser';
import { RouterTestingModule } from '@angular/router/testing';
import { BehaviorSubject, Observable, of, throwError } from 'rxjs';
import { AuthService } from '../service/auth.service';
import { LoginComponent } from './login.component';
describe('LoginComponent', () => {
let component: LoginComponent;
let fixture: ComponentFixture<LoginComponent>;
let authService: AuthService;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ LoginComponent ],
imports: [FormsModule, HttpClientModule, RouterTestingModule],
providers: [AuthService]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(LoginComponent);
component = fixture.componentInstance;
fixture.detectChanges();
fixture.autoDetectChanges();
});
it('invalid user access', async(() => {
authService = fixture.debugElement.injector.get(AuthService);
authService = TestBed.get(AuthService);
const respObj =new BehaviorSubject( new HttpErrorResponse({
error: { errorMessage: "Invalid credentials"}
}));
component.email = '[email protected]';
component.password = 'pasywdja';
fixture.detectChanges();
spyOn(component, 'submitForm').and.callThrough();
spyOn(authService, 'login').and.returnValue(of(respObj));
component.submitForm();
fixture.detectChanges();
fixture.whenStable().then( () => {
expect(component.submitForm).toHaveBeenCalled();
expect(authService.login).toHaveBeenCalled();
let msgElem = fixture.debugElement.nativeElement.querySelector("#message");
expect(msgElem).not.toBeNull();
console.log("text verify" msgElem.innerHTML)
expect(msgElem.innerHTML).toContain("Invalid credentials")
})
}));
it('route to home when valid login', async(() => {
//routing to be tested when valid service response is
{jWT_Token: "y87y21skj.dh8712haskhdaksdj.haasdyusd", status:200}
}));
});
login.compoonent.html
<div class="container md-6">
<div class="container md-6">
<div class="container md-6">
<h1> Employee Management System</h1>
<form (ngSubmit)= 'submitForm()' #loginForm='ngForm'>
<div class="form-group">
<label for="email">Email address</label>
<input type="email" class="form-control" id="email" aria-describedby="emailHelp" placeholder="Enter email"
name='email' [(ngModel)] ='email' required pattern = "[a-z0-9._% -] @[a-z0-9.-] \.[a-z]{2,4}$" #useremail="ngModel" >
<small id="emailHelp" class="form-text text-muted">We'll never share your email with anyone else.</small>
</div>
<div class="form-group">
<label for="password">Password</label>
<input type="password" class="form-control" id="password" placeholder="Password" name='password' required [(ngModel)] = 'password' #loginPassword="ngModel">
</div>
<div *ngIf="(useremail.invalid && (useremail.dirty || useremail.touched)) || ( loginPassword.touched && loginPassword.invalid)" id="invalidDetails" class="alert alert-danger" role="alert">
Please Enter valid details.
</div>
<div *ngIf="message" id="message" class="alert alert-danger" role="alert">
{{message}}
</div>
<button type="submit" class="btn btn-primary d-flex justify-content-center" [disabled] = '!loginForm.form.valid'>Submit</button>
</form>
</div>
</div>
</div>
Any help or suggestions is greatly appreciated.
CodePudding user response:
You almost had it.
Make the following changes and you should hopefully be good to go (follow the comments):
it('invalid user access', async(() => {
// get rid of 1 of the 2 lines here. They both do the same thing
// I got rid of the first one
// authService = fixture.debugElement.injector.get(AuthService);
authService = TestBed.get(AuthService);
// this should not have BehaviorSubject (it should just be an object)
const respObj = new HttpErrorResponse({
error: { errorMessage: "Invalid credentials"}
});
component.email = '[email protected]';
component.password = 'pasywdja';
fixture.detectChanges();
spyOn(component, 'submitForm').and.callThrough();
// this should not be of, but it should be throwError
// use of for successful observable
// import { throwError } from 'rxjs';
spyOn(authService, 'login').and.returnValue(throwError(respObj));
component.submitForm();
fixture.detectChanges();
fixture.whenStable().then(() => {
expect(component.submitForm).toHaveBeenCalled();
expect(authService.login).toHaveBeenCalled();
let msgElem = fixture.debugElement.nativeElement.querySelector("#message");
expect(msgElem).not.toBeNull();
console.log("text verify" msgElem.innerHTML)
expect(msgElem.innerHTML).toContain("Invalid credentials");
})
}));
I think that will help you test the failure route ^.
To test the success route, it is the same thing but instead of using throwError
, use of
.