#
Review No. 3 (Tests)
This page contains questions to improve/test your Angular skills (Tests).
#
TestBed, Jasmine, Karma
TestBed
- Configures Angular's testing environment and provides tools for component/service testing.
- Create and test components/services with
TestBed.createComponent
orTestBed.inject
Jasmine
- Defines the test structure and provides assertions.
- Defines
describe
andit
blocks, and the usage ofexpect(value).toBe(expected)
.
Karma
- Runs the tests in a browser and reports results.
Info
If you are using Angular, TestBed, Jasmine, and Karma are already integrated into the Angular testing setup provided by the Angular CLI.
#
toBeTrue() vs toBeTruthy()
- toBeTrue() : Requires the value to be
true
. - toBeTruthy() : Fails for:
false
,0
,''
,null
,undefined
,NaN
.
#
What is NaN ?
NaN = Not-a-Number
console.log(0 / 0); // NaN
console.log(Math.sqrt(-1)); // NaN
console.log(Number('abc')); // NaN
console.log(parseInt('hello')); // NaN
#
Testing a Guard
Guard example:
import { Injectable } from '@angular/core';
import { CanActivate, Router } from '@angular/router';
import { Observable, Subscription } from 'rxjs';
import { UserSessionService } from './100-services/user-session.service';
@Injectable({
providedIn: 'root',
})
export class LoggedInGuard implements CanActivate {
loggedIn: boolean = false;
subscription1: Subscription;
constructor(private next: Router,
private userSessionService: UserSessionService) {
this.subscription1 = this.userSessionService.loginCheck.subscribe( nextVal => {
if (nextVal == 'Y') {
this.loggedIn = true;
} else {
this.loggedIn = false;
}
});
}
canActivate(): Observable<boolean> | Promise<boolean> | boolean {
if (this.loggedIn) {
return true; // logged in so return true
}
this.next.navigate(['/login']);
return false;
}
ngOnDestroy() {
this.subscription1.unsubscribe();
}
}
Guard Test example:
import { TestBed } from '@angular/core/testing';
import { Router } from '@angular/router';
import { LoggedInGuard } from './logged-in.guard';
import { UserSessionService } from './100-services/user-session.service';
import { BehaviorSubject} from 'rxjs';
describe('loggedInGuard', () => {
let loggedInGuard: LoggedInGuard;
let userSessionService: MockUserSessionService;
let router: MockRouter;
beforeEach(() => {
TestBed.configureTestingModule({
providers: [
LoggedInGuard,
{ provide: UserSessionService, useClass: MockUserSessionService},
{ provide: Router, useClass: MockRouter },
],
});
loggedInGuard = TestBed.inject(LoggedInGuard);
userSessionService = TestBed.inject(UserSessionService) as unknown as MockUserSessionService;
router = TestBed.inject(Router) as unknown as MockRouter;
});
it('loggedInGuard should be created', () => {
expect(loggedInGuard).toBeTruthy();
});
it('should allow navigation if user is authenticated', () => {
const result = loggedInGuard.canActivate();
expect(result).toBeTrue(); //navigation allowed
expect(router.navigate).not.toHaveBeenCalled(); //no redirect
});
it('should not allow navigation if user is non authenticated', () => {
userSessionService.loginCheck.next('N');
const result = loggedInGuard.canActivate();
expect(result).toBeFalse(); //navigation not allowed
//we test the redirection to login
expect(router.navigate).toHaveBeenCalledWith(['/login']);
});
});
class MockUserSessionService {
loginCheck = new BehaviorSubject<string>('Y');
}
class MockRouter {
navigate = jasmine.createSpy('navigate');
}
#
Testing a Component
Testing the component :
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { LogoutComponent } from './logout.component';
import { Router } from '@angular/router';
describe('LogoutComponent', () => {
let component: LogoutComponent;
let fixture: ComponentFixture<LogoutComponent>;
let router: Router;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [LogoutComponent], // Declare the component being tested
}).compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(LogoutComponent);
component = fixture.componentInstance;
fixture.detectChanges(); // Initialize component and run lifecycle hooks
router = TestBed.inject(Router);
// Spy on navigateByUrl
spyOn(router, 'navigateByUrl');
// Spy on sessionStorage.setItem (we will know what was done on it)
spyOn(sessionStorage, 'setItem');
});
it('should create the component', () => {
expect(component).toBeTruthy();
});
it('should navigate to "/contacte" page on button click', () => {
component.route_contacte(); // Call the route_contacte() method
expect(router.navigateByUrl).toHaveBeenCalledWith('/contacte');
expect(router.navigateByUrl).toHaveBeenCalledTimes(1);
});
// test a method
it('should add numbers correctly', () => {
component.addNumbers(4, 3);
expect(component.result).toBe(7); // Validate the method logic
});
// test a function
it('should add numbers correctly', () => {
const fctResult = component.addNumbersFct(1, 3);
expect(fctResult).toBe(4); // Validate the method logic
});
it('should call sessionStorage.setItem with correct arguments', () => {
component.logout();
expect(sessionStorage.setItem).toHaveBeenCalledWith('userId', '0');
});
});