Angular 2单元测试-无法读取未定义的属性"root" [英] Angular 2 Unit Testing - Cannot read property 'root' of undefined

查看:81
本文介绍了Angular 2单元测试-无法读取未定义的属性"root"的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

错误说明

角度版本:2.3.1

Angular version: 2.3.1

我的单元测试无法创建组件-我知道此问题与[routerLink][routerLinkActive]指令有关,因为从模板中删除它们允许测试创建组件.

My unit test fails to create the component - I know this issue is related to the [routerLink] and [routerLinkActive] directives because removing them from the template allows the test to create the component.

模板

<nav class="navbar navbar-default navbar-fixed-top" role="navigation">
<div class="container-fluid">
<div class="navbar-header">
  <button class="navbar-toggle" data-toggle="collapse" data-target="#iotahoe-top-navigation">
    <span class="sr-only">Toggle navigation</span>
    <span class="icon-bar"></span>
    <span class="icon-bar"></span>
    <span class="icon-bar"></span>
  </button>
  <a class="navbar-brand" [routerLink]="['/']">IoTahoe</a>
</div>
<div class="collapse navbar-collapse" id="iotahoe-top-navigation">
  <ul *ngIf="isAuthenticated()" class="nav navbar-nav navbar-right">
    <li [routerLinkActive]="['active']"><a [routerLink]="['/dashboard']">Dashboard</a></li>
    <li [routerLinkActive]="['active']"><a [routerLink]="['/browse']">Browse</a></li>
    <li [routerLinkActive]="['active']"><a [routerLink]="['/admin']">Admin</a></li>
    <li [routerLinkActive]="['active']"><a (click)="onLogout()" style="cursor: pointer;">Logout</a></li>
  </ul>
</div>

TYPESCRIPT

import { Component, OnInit } from '@angular/core';
import { AuthenticationService } from   '../../authentication/authentication.service';
import { Router } from '@angular/router';

@Component({
moduleId: module.id.toString(),
selector: 'app-top-navbar',
templateUrl: './top-navbar.component.html',
styleUrls: ['./top-navbar.component.css']
})
export class TopNavbarComponent implements OnInit {

constructor(private authenticationService: AuthenticationService, private router: Router) { }

ngOnInit() {
}

isAuthenticated() {
    return this.authenticationService.isLoggedIn;
}

onLogout() {
    this.authenticationService.logout().subscribe(() => {
        return this.router.navigate(['/login']);
    });
}

}

测试规格

/* tslint:disable:no-unused-variable */
import {async, ComponentFixture, TestBed, inject} from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import {DebugElement, CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA, Component} from '@angular/core';
import { RouterTestingModule } from '@angular/router/testing';
import { Location, CommonModule } from '@angular/common';
import { TopNavbarComponent } from './top-navbar.component';
import { AuthenticationService } from '../../authentication/authentication.service';
import { Router } from '@angular/router';
import {ReactiveFormsModule} from "@angular/forms";

@Component({
template: ''
})
class DummyComponent {
}


describe('TopNavbarComponent', () => {
let component: TopNavbarComponent;
let fixture: ComponentFixture<TopNavbarComponent>;
let authenticationService: AuthenticationService;

beforeEach(async(() => {
    const authenticationServiceStub = {
        isLoggedIn: false
    };

    const routerStub = {
        navigate: jasmine.createSpy('navigate'),
        navigateByUrl: jasmine.createSpy('navigateByUrl')
    };

    TestBed.configureTestingModule({
        declarations: [ TopNavbarComponent, DummyComponent ],
        imports:[CommonModule, ReactiveFormsModule,     RouterTestingModule.withRoutes(
            [
                { path: '/', component:DummyComponent },
                { path: '/login', component:DummyComponent },
                { path: '/dashboard', component:DummyComponent },
                { path: '/browse', component:DummyComponent },
                { path: '/admin', component:DummyComponent }
            ])],
        providers: [
            { provide: AuthenticationService, useValue: authenticationServiceStub },
            { provide: Router, useValue: routerStub }
            ]
    }).compileComponents();
}));

beforeEach(() => {
    fixture = TestBed.createComponent(TopNavbarComponent);
    component = fixture.componentInstance;
    authenticationService = TestBed.get(AuthenticationService);
    fixture.detectChanges();
});

it('should create', () => {
    expect(component).toBeTruthy();
});
});

错误

zone.js:155未捕获的错误:软件包:407:9:6中的错误是由于:无法引起的 读取未定义的属性"root" 在ViewWrappedError.Error(本机) 在ViewWrappedError.ZoneAwareError(localhost:9876/base/src/test.ts:133296:33) 在ViewWrappedError.BaseError上[作为构造函数](localhost:9876/base/src/test.ts:35630:16) 在ViewWrappedError.WrappedError [作为构造函数](localhost:9876/base/src/test.ts:35695:16) 在新的ViewWrappedError(localhost:9876/base/src/test.ts:68018:16) 在DebugAppView._rethrowWithContext(localhost:9876/base/src/test.ts:108242:23) 在DebugAppView.create(localhost:9876/base/src/test.ts:108142:18) 在DebugAppView.View_TopNavbarComponent_Host0.createInternal(/DynamicTestModule/TopNavbarComponent/host.ngfactory.js:16:19) 在DebugAppView.AppView.createHostView(localhost:9876/base/src/test.ts:107700:21) 在DebugAppView.createHostView(localhost:9876/base/src/test.ts:108156:52) 在ComponentFactory.create(localhost:9876/base/src/test.ts:49830:25) 在initComponent(localhost:9876/base/src/test.ts:6425:53) 在ZoneDelegate.invoke(localhost:9876/base/src/test.ts:132727:26) 在ProxyZoneSpec.onInvoke(localhost:9876/base/src/test.ts:95802:39) 在ZoneDelegate.invoke(localhost:9876/base/src/test.ts:132726:32)Zone.runTask @ zone.js:155ZoneTask.invoke @ zone.js:345data.args.(匿名函数) @ zone.js:1376

zone.js:155 Uncaught Error: Error in package:407:9:6 caused by: Cannot read property 'root' of undefined at ViewWrappedError.Error (native) at ViewWrappedError.ZoneAwareError (localhost:9876/base/src/test.ts:133296:33) at ViewWrappedError.BaseError [as constructor] (localhost:9876/base/src/test.ts:35630:16) at ViewWrappedError.WrappedError [as constructor] (localhost:9876/base/src/test.ts:35695:16) at new ViewWrappedError (localhost:9876/base/src/test.ts:68018:16) at DebugAppView._rethrowWithContext (localhost:9876/base/src/test.ts:108242:23) at DebugAppView.create (localhost:9876/base/src/test.ts:108142:18) at DebugAppView.View_TopNavbarComponent_Host0.createInternal (/DynamicTestModule/TopNavbarComponent/host.ngfactory.js:16:19) at DebugAppView.AppView.createHostView (localhost:9876/base/src/test.ts:107700:21) at DebugAppView.createHostView (localhost:9876/base/src/test.ts:108156:52) at ComponentFactory.create (localhost:9876/base/src/test.ts:49830:25) at initComponent (localhost:9876/base/src/test.ts:6425:53) at ZoneDelegate.invoke (localhost:9876/base/src/test.ts:132727:26) at ProxyZoneSpec.onInvoke (localhost:9876/base/src/test.ts:95802:39) at ZoneDelegate.invoke (localhost:9876/base/src/test.ts:132726:32)Zone.runTask @ zone.js:155ZoneTask.invoke @ zone.js:345data.args.(anonymous function) @ zone.js:1376

推荐答案

routerLink指令需要一个真实的路由器,但是您在嘲笑它.我可以看到您在做的几件事:

The routerLink directives need a real router, but you are mocking it. A couple things I can see you doing:

  • 如果您不打算在测试期间单击链接,则可以模拟那些指令以仅创建"noop"指令,以使编译器不会抱怨.例如

  • If you don't plan to click the links during testing, then you can mock those directive to just make "noop" directives so the compiler doesn't complain. e.g.

@Directive({
    selector: '[routerLink], [routerLinkActive]'
})
class DummyRouterLinkDirective {}

然后将其添加到测试模块的declarations中.有了它,您实际上根本不需要配置RouterTestingModule.您可能会摆脱它.

Then just add that to the declarations of the test module. With this you don't really need to configure the RouterTestingModule at all. You could probably get rid of that.

此外,如果您不打算单击测试",那么另一个选择(无需创建虚拟指令就是忽略忽略的指令的错误:

Also if you don't plan to click test, another option (without needing to create dummy directives is to just ignore the errors of missing directives:

schemas: [ NO_ERRORS_SCHEMA ]

您将其添加到测试模块配置中(如此处所示).在某些情况下,这可能不是所希望的,因为它也可能会忽略您实际要检测到的错误,这可能导致难以调试测试.

You would add this to the test module configuration (as seen here). This might not be desirable in some cases, as it could also ignore errors that you actually want detected, which could lead to hard to debug tests.

如果您实际上想单击链接并测试路由,则可以使用真实的路由器.您可以看到一个示例,该示例如何使用Location测试导航,如这篇文章中所示./p>

If you would actually like to click the links and test routing, then you can use the real router. You can see an example of how you can test the navigation, using the Location, as seen in this post.

这篇关于Angular 2单元测试-无法读取未定义的属性"root"的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆