【问题标题】:TypeError: navbarUserInfoComponent[0] is undefined in Jasmine testTypeError: navbarUserInfoComponent[0] 在 Jasmine 测试中未定义
【发布时间】:2020-11-20 10:15:32
【问题描述】:

我目前正在编写一个 jasmine 测试用例来测试注销菜单组件是否正常工作。

这是我的 TS 文件。

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();
  }

}

这是html文件:

<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>

这是基于我参加的 Jasmine 测试课程的 Spec 文件。 (这是目前在 Spec 文件中的内容)

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();

  })
});

我的问题是当它运行时我得到这个结果。 (我有更新以显示当前的错误消息)

我的问题是,为什么说 'navbarUserInfoComponent[0]' 未定义?

如果我关闭 [0],我会收到一条消息,提示“triggerEventHandler”未定义。

在这种情况下我做错了什么?

【问题讨论】:

    标签: javascript angular typescript jasmine karma-jasmine


    【解决方案1】:

    您没有正确捕捉 HTML 元素。尝试输入id 轻松获取元素

    <button id="logout-btn" mat-menu-item (click)="logout()">Logout</button>
    

    spec 文件中:

      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();
       )}
    

    更新:

    通过创建一个模拟来定义user

    class MockAuthenticationService{
       getUserName(){
         return "hero"
      }
      // and other methods as well
    }
    

    TestBed 试试:

     // ......
     providers: [
            {provide: AuthenticationService, useClass: MockAuthenticationService},
    

    【讨论】:

    • 好的,HTML页面是别人写的。我做了这些更改:在 html&lt;button id="btn-Logout" mat-menu-item (click)="logout()"&gt;Logout&lt;/button&gt; 规范中:`it('should test a click of the logout button', () => { spyOn(fixture.componentInstance, 'logout').and.callThrough(); fixture.detectChanges(); const link = fixture.debugElement.nativeElement.querySelector('#btn-Logout'); link.click(); expect(component.logout).toHaveBeenCalled(); })' 我得到@987654330 @ 结果
    • 我没有在我更新的规范文件周围加上正确的引号。 it('should test a click of the logout button', () =&gt; { spyOn(fixture.componentInstance, 'logout').and.callThrough(); fixture.detectChanges(); const link = fixture.debugElement.nativeElement.querySelector('#btn-Logout'); link.click(); expect(component.logout).toHaveBeenCalled(); }) 这应该正确显示它
    • @EricLommatsch:你能试试fixture.nativeElement.querySelector('#logout-btn'); 请告诉我。我已经更新了答案
    • 进行此更改时我仍然得到相同的结果。
    • @EricLommatsch :您能否确保已定义 user,因为有一个 *ngIf 条件来呈现此按钮。检查新的更新答案
    猜你喜欢
    • 2015-06-29
    • 1970-01-01
    • 2023-03-29
    • 2016-03-07
    • 1970-01-01
    • 2017-08-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多