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

问题描述:

我正在使用angular-cli 1.0.0-beta.19-3。具有服务依赖性的ng2组件在单元测试期间错误地解析模板

我有一个名为UserInfo的组件,当CurrentUser服务告诉用户登录时,通过模板中的* ngIf显示一个问候语和一个注销按钮。每当注销时,它都会显示一个登录按钮来引导用户登录页面。我试过设置一个测试,但我相信该模板正在评估ngIf不当。我也尝试过使用fixture.whenStable().then(...),但这似乎无关紧要。我运行了karma调试器来检查component._user,而isLoggedIn返回的是未定义的,所以看起来好像我的存根未被正确注入。

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

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

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