具有服务依赖性的ng2组件在单元测试期间错误地解析模板

时间:2016-12-21 13:38:17

标签: angular mocking jasmine angular2-template angular2-services

我使用的是angular-cli 1.0.0-beta.19-3。

我有一个名为UserInfo的组件,当CurrentUser服务通过模板中的* ngIf告知用户登录时,会显示问候语和注销按钮。每当注销时,它只会显示一个登录按钮,将用户定向到登录页面。我已经尝试过设置测试,但我相信模板正在不正确地评估ngIf。我也试过使用fixture.whenStable().then(...),但这似乎并不重要。我运行了karma调试器来检查component._user并且isLoggedIn返回undefined,所以看起来我的存根没有被正确注入。

userinfo.component.spec.ts:

/* tslint:disable:no-unused-variable */
import {
  async,
  ComponentFixture,
  TestBed
} from '@angular/core/testing';

import { UserInfoComponent } from './userinfo.component';
import { CurrentUser } from '../../currentuser/currentuser.service';

describe('UserInfoComponent', () => {
  let component: UserInfoComponent;
  let fixture: ComponentFixture<UserInfoComponent>;
  let userStub: any;
  let mockUser: any;
  let loginSpy: any;
  let nameSpy: any;

  beforeEach(async(() => {
    userStub = {
      name: 'Test User',
      isLoggedIn: function() { return true; },
      getFullName: function() { return this.name; }
    };
    TestBed.configureTestingModule({
      declarations: [UserInfoComponent],
      providers: [{
        provide: CurrentUser, useValue: userStub
      }]
    })
        .compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(UserInfoComponent);
    component = fixture.componentInstance;
    mockUser = TestBed.get(CurrentUser);
    loginSpy = spyOn(mockUser, 'isLoggedIn');
    nameSpy = spyOn(mockUser, 'getFullName');
    fixture.detectChanges();
  });

  it('should render without crashing', () => {
    expect(component).toBeDefined();
  });

  it('should have access to currentUser', () => {
    expect(component._user).toBeDefined();
  });

  it('should contain a user greeting when logged in', () => {
    const greetingEl = fixture.nativeElement.querySelector('.user-greeting');
    expect(greetingEl).toBeTruthy();
    expect(greetingEl.innerHTML).toContain('Test User', 'Name is missing');
    expect(loginSpy.calls.any()).toBe(true);
  });

});

UserInfoComponent:

import { Component, OnInit } from '@angular/core';
import { CurrentUser } from '../../currentuser/currentuser.service';

@Component({
  selector: 'oa-userinfo',
  templateUrl: 'userinfo.component.html',
  styleUrls: ['userinfo.component.scss']
})
export class UserInfoComponent implements OnInit {
  constructor(
      public _user: CurrentUser
  ) { }
  gotoLoginPage() {
    console.log('going to login');
  }
  ngOnInit() { }
}

userinfo.component.html:

<div class="user-info" *ngIf="_user.isLoggedIn()">
  <span class="user-greeting">Welcome, {{_user.getFullName()}}!</span>
  <button id="logout-button"
     (click)="_user.logout()"
     md-raised-button
     color="accent">Logout</button>
</div>
<div class="user-info" *ngIf="!_user.isLoggedIn()">
  <button id="login-button"
     (click)="gotoLoginPage()"
     md-raised-button
     color="accent">Login</button>
</div>

CurrentUser:

import { Injectable } from '@angular/core';

@Injectable()
export class CurrentUser implements ICurrentUser {
  private token: string = '1234567';
  private userName: string = 'Test User';
  constructor() {}
  storeToken(token: string) {
    this.token = token;
  }
  logout() {
    this.token = null;
  }

  isLoggedIn() {
    return this.token;
  }

  getFullName() {
    return this.userName;
  }
}

export interface ICurrentUser {
  storeToken(token: string);
  logout();
  isLoggedIn();
  getFullName();
}

1 个答案:

答案 0 :(得分:0)

问题原来是对spyOn的调用。我不熟悉茉莉花,所以我没有将.and.callThrough()添加到间谍的创作中:

loginSpy = spyOn(mockUser, 'isLoggedIn').and.callThrough();
nameSpy = spyOn(mockUser, 'getFullName').and.callThrough();