Eric Lommatsch
Eric Lommatsch

Reputation: 147

TypeError: navbarUserInfoComponent[0] is undefined in Jasmine test

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)

enter image description here

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

Answers (1)

Shashank Vivek
Shashank Vivek

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

Related Questions