Модульное тестирование Angular 2 - невозможно прочитать свойство 'root' из неопределенного

Описание ошибки

Угловая версия: 2.3.1

Мой модульный тест не может создать компонент - я знаю, что эта проблема связана с [routerLink] а также [routerLinkActive] директивы, потому что удаление их из шаблона позволяет тесту создать компонент.

ШАБЛОН

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

МАШИНОПИСЬ

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 Uncaught Ошибка: ошибка в пакете:407:9:6, вызванная: Невозможно прочитать свойство 'root' из undefined в ViewWrappedError.Error (native) в 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. создать (localhost:9876/base/src/test.ts:108142:18) в DebugAppView.View_TopNavbarComponent_Host0.createInternal (/DynamicTestModule/TopNavbarComponent/host.ngfactory.js:16:19) в DebugAppView.HostView: 98.ViewView /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 (локальный хост:9876/base/src/test.ts:6425:53) в ZoneDelegate.invoke (локальный хост: 9876 / base / src / test.ts: 132727: 26) в ProxyZoneSpec.onInvoke (локальный хост: 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

2 ответа

Решение

routerLink директивам нужен настоящий роутер, но вы над ним издеваетесь. Я вижу, как ты делаешь пару вещей:

  • Если вы не планируете переходить по ссылкам во время тестирования, вы можете смоделировать эти директивы, чтобы просто сделать директивы "noop", чтобы компилятор не жаловался. например

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

    Затем просто добавьте это к declarations тестового модуля. При этом вам не нужно настраивать RouterTestingModule совсем. Вы могли бы вероятно избавиться от этого.

  • Также, если вы не планируете нажимать кнопку test, другой вариант (без необходимости создания фиктивных директив - просто игнорировать ошибки отсутствующих директив:

    schemas: [ NO_ERRORS_SCHEMA ]
    

    Вы бы добавили это в конфигурацию тестового модуля (как показано здесь). Это может быть нежелательно в некоторых случаях, так как может также игнорировать ошибки, которые вы на самом деле хотите обнаружить, что может привести к трудностям при отладке тестов.

  • Если вы действительно хотите перейти по ссылкам и проверить маршрутизацию, то вы можете использовать настоящий маршрутизатор. Вы можете увидеть пример того, как вы можете проверить навигацию, используя Location, как видно в этом посте.

У меня решение с немодальной маршрутизацией сработало. Но я узнал, что мне нужно было добавить

<router-outlet></router-outlet>

к компоненту, использующему "routerlink active".

Другие вопросы по тегам