Reputation: 147
I am currently writing a jasmine test case to test that a logout menu component works correctly.
Here is my TS file.
import { Component, OnInit } from '@angular/core';
import { Observable, of } from 'rxjs';
import { MatDialog } from '@angular/material/dialog'
import { Router } from '@angular/router';
import { RecursiveAstVisitor } from '@angular/compiler/src/output/output_ast';
//import { faChalkboard, faExclamationTriangle, IconDefinition } from '@fortawesome/free-solid-svg-icons';
import { take } from 'rxjs/operators';
import { AuthenticationService } from 'src/app/services/shared/authentication.service';
import { LoginService } from 'src/app/services/shared/login.service';
@Component({
selector: 'app-navbar-user-info',
templateUrl: './navbar-user-info.component.html',
styleUrls: ['./navbar-user-info.component.scss']
})
export class NavbarUserInfoComponent implements OnInit {
// notificationIcon: IconDefinition;
// //RID Icon
// faExclamationTriangle = faExclamationTriangle;
// //Whiteboard Icon
// faChalkboard = faChalkboard;
totalNotifications = 0;
user;
employee;
expanded: any[][] = new Array();
interval;
pageRoute = '/dynamic';
tooltipPosition = "above"
constructor(
public authenticationService: AuthenticationService,
private loginService: LoginService,
//private userService: UserAPI,
private dialog: MatDialog,
private router: Router
) { }
ngOnInit() {
console.log("Initializing: header-user-info.component.ts")
console.log(this.authenticationService.getEmployeeId());
console.log(this.authenticationService.getUserName());
this.user=this.authenticationService.getUserName();
}
logout() {
this.loginService.logout();
}
}
This is the html file:
<div class="nav-div" *ngIf="authenticationService.isLoggedIn() | async as loggedIn" fxLayout="row" fxLayoutAlign="start center"
fxLayoutGap="12px">
<div *ngIf="user">
<mat-menu #userMenu="matMenu">
<div class="user-profile-details">User: {{user}}</div>
<!-- <div class="user-profile-details">Role: {{user?.role?.roleName}}</div> -->
<!--<div class="user-profile-details">Company: {{user?.companyNm}}</div> -->
<mat-divider></mat-divider>
<button mat-menu-item (click)="logout()">Logout</button>
</mat-menu>
<button mat-button [matMenuTriggerFor]="userMenu" class="no-hover">
<!-- <mat-icon class="material-icons">account_circle</mat-icon> -->
<i class="fas fa-user-circle fa-lg material-icons"></i>
</button>
</div>
</div>
and this is the Spec file based on a course on Jasmine testing I had taken. (This is what is currently in the Spec file)
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { NavbarUserInfoComponent } from './navbar-user-info.component';
import { AuthenticationService } from 'src/app/services/shared/authentication.service';
import { LoginService } from 'src/app/services/shared/login.service';
import { MatDialog } from '@angular/material/dialog';
import { Router } from '@angular/router';
import { By } from "@angular/platform-browser";
import { MatMenuItem } from '@angular/material/menu';
import { HttpClientTestingModule, HttpTestingController} from "@angular/common/http/testing";
import { of } from 'rxjs';
export class mockAuthentication{
getUserInfo(){
return "1";
};
getUserRole(){
return "admin";
};
getUserName(){
return "Test User";
};
isLoggedIn(){
return true;
};
};
describe('NavbarUserInfoComponent', () => {
let component: NavbarUserInfoComponent;
let fixture: ComponentFixture<NavbarUserInfoComponent>;
let mockLoginService, mockMatDialog, mockRouter; //, mockAuthentication;
let USER;
beforeEach(async(() => {
USER = [
{id:1, name:'Test User', role: 'admin'}
]
//mockAuthentication = jasmine.createSpyObj(['getUserInfo','getUserRole','getUserName','isLoggedIn']);
TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
declarations: [ NavbarUserInfoComponent ],
providers: [
{provide: AuthenticationService, useValue: mockAuthentication},
{provide: LoginService, useValue: mockLoginService},
{provide: MatDialog, useValue: mockMatDialog},
{provide: Router, useValue: mockRouter}
],
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(NavbarUserInfoComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
it('should test a click of the logout button', () => {
spyOn(fixture.componentInstance, 'logout').and.callThrough();
fixture.detectChanges();
const link = fixture.nativeElement.querySelector('#btn-Logout');
link.click();
expect(fixture.componentInstance.logout).toHaveBeenCalled();
})
});
My question is when this runs I am getting this result. (I have update to show the current error messages)
My question is, Why is it saying the 'navbarUserInfoComponent[0]' is undefined?
if I take the [0] off, I am getting a message that 'triggerEventHandler' is undefined.
What am I doing wrong in this case?
Upvotes: 2
Views: 110
Reputation: 17504
You are not catching the HTML element correctly. Try putting id
to get the element easily
<button id="logout-btn" mat-menu-item (click)="logout()">Logout</button>
In spec
file:
it('should test a click of the logout button', () => {
spyOn(component,'logout').and.callThrough();
fixture.detectChanges();
const btn = fixture.nativeElement.querySelector('#logout-btn');
btn.click();
expect(component.logout).toHaveBeenCalled();
)}
Update:
define user
by creating a mock as
class MockAuthenticationService{
getUserName(){
return "hero"
}
// and other methods as well
}
and in TestBed
try:
// ......
providers: [
{provide: AuthenticationService, useClass: MockAuthenticationService},
Upvotes: 1