Модульное тестирование 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".