角度单元测试:TypeError:无法读取未定义的属性“根”
Posted
技术标签:
【中文标题】角度单元测试:TypeError:无法读取未定义的属性“根”【英文标题】:Angular unit Testing : TypeError: Cannot read property 'root' of undefined 【发布时间】:2018-04-18 19:54:24 【问题描述】:我正在我的 Angular 应用程序下进行单元测试。
我的 Angular 版本是 4.0.0。
我的组件如下所示:
component.ts
:
import GdfaClientService from '../../../service/gdfa-client.service';
import SharedclientService from '../../../service/sharedclient.service';
import Client from '../../model/client';
import RouteNavigator from '../../util/route-navigator';
import Component, OnInit from '@angular/core';
import MonitoringService from '../../../service/monitoring.service';
@Component(
selector: 'app-queue-again',
templateUrl: './queue-again.component.html',
styleUrls: ['./queue-again.component.css'],
)
export class QueueAgainComponent implements OnInit
//-- variables --//
showError = false;
queueChoices = [];
selectedQueue;
selectedReason;
requestInProgress = false;
client: Client;
errorMessage: string;
queues: any;
bankNotAllowed: boolean = false;
constructor(private sharedclientService: SharedclientService, private gdfaClientService: GdfaClientService
, private router: RouteNavigator, private monitoringService: MonitoringService)
ngOnInit()
this.client = this.sharedclientService.getShared360Client();
this.getQueues();
this.bankNotAllowed = this.sharedclientService.bankNotAllowed;
goToPrevious()
this.router.goToHomeAccordingToProfile();
queueAgain()
let currentNd = "";
let currentUniverse = "";
let currentCuid = "";
if (!this.selectedReason)
return;
this.requestInProgress = true;
let reg =
registrationId: this.client.registration.gdfaId,
gdfaQueueId: this.selectedQueue.id,
gdfaReasonId: this.selectedReason.id,
firstProfile: (this.client.firstProfile ? true : false)
;
this.gdfaClientService.queueAgain(reg).then(any =>
currentCuid = this.client.clientIdentity.customerId;
if (this.client.fromAdvSearch == undefined || this.client.fromAdvSearch == false)
currentNd = this.client.nd;
if (currentNd != undefined && currentNd != "")
if (currentNd == "0000000000")
currentNd = "";
currentUniverse = "";
if (currentNd.substring(0, 2) == "06" || currentNd.substring(0, 2) == "07")
currentUniverse = "Mobile";
else
currentUniverse = "Fixe";
this.trackReinsertClient(currentCuid, currentNd, currentUniverse);
this.requestInProgress = false;
this.showError = false;
this.sharedclientService.setShared360Client(new Client());
this.goToPrevious();
)
.catch(error =>
this.requestInProgress = false;
this.showError = true;
switch (error.status)
case 403:
this.errorMessage = "Erreur lors de la réinjection du client : utilisateur inconnu";
console.log(this.errorMessage);
break;
case 500:
this.errorMessage = "Réinscription impossible";
console.log(this.errorMessage);
break;
default:
this.errorMessage = "Erreur lors de la réinjection du client";
console.log(this.errorMessage);
);
;
trackReinsertClient(cuid, nd, universe)
let uri = "/api/gdfa/client/registration/reinsert";
let httpMethod = "PUT";
let name = "réinjection d'un client dans la file d'attente";
console.log('trackReinsertClient <' + cuid + '>');
this.monitoringService.trackingAction(name, uri, httpMethod, null, cuid, nd, universe);
selectQueue(queue)
this.selectedQueue = queue;
this.selectedReason = false;
;
isSelectedQueue(queue)
return this.selectedQueue.shortName == queue.shortName;
getQueues()
let queueList = this.client.registration.queueAgainChoices;
// Search for residentiel queue and put it as selectedQueue
let indexSAVSAUMobile = -1;
let indexSAVSAUInternet = -1;
for (let queue of queueList)
if (queue.shortName == 'RES')
this.selectedQueue = queue;
this.queues = queueList;
return queueList;
selectReason(reason)
this.selectedReason = reason;
isSelectedReason(reason)
if (this.selectedReason)
return this.selectedReason.id == reason.id;
return null
getReasons(queue)
let reasonList = this.selectedQueue.reasons;
return reasonList;
component.html
:
<div>
<div [hidden]="!requestInProgress" id="div-spinner">
<img src="/assets/images/indicateur-attente-grand.gif"
class="spinner-loader" />
</div>
<div class="row">
<!-- fermeture de la recherche avancée -->
<div class="col-xs-1 pull-right closeCross">
<img id="ngClick_goToPreviousFromQueueAgain"
src="/assets/images/asset_icon_close_popup_gray.png"
class="pull-right mousePointer" (click)="goToPrevious()" />
</div>
</div>
<div class="row">
<div class="col-xs-10 col-xs-offset-1 error-message"
*ngIf="showError">errorMessage</div>
<div
class="col-xs-10 col-xs-offset-1 col-sm-3 col-sm-offset-0 register-bloc">
<div class="titre_bloc">File d'attente</div>
<div id="files-bloc">
<div id="ngClick_selectQueueAgain" class="file-cell "
*ngFor="let queue of queues | orderBy : 'id'"
[ngClass]=" 'selected-shop-queue': isSelectedQueue(queue)"
(click)='selectQueue(queue)'>
<div class="vertical-center horizontal-middle file_nom">
<div>queue.name</div>
</div>
</div>
</div>
</div>
<div
class="col-xs-10 col-xs-offset-1 col-sm-6 col-sm-offset-0 register-bloc">
<div class="titre_bloc">Motifs</div>
<div id="motifs-bloc">
<div id="ngClick_queueAgain" class="motif-cell"
[ngClass]="'motif-cell-pro': selectedQueue?.reasons?.length == 4, 'motif-cell-selected':isSelectedReason(reason),
'hide-class': (bankNotAllowed && reason.id === 12)" [hidden]="bankNotAllowed && reason.id === 12"
*ngFor="let reason of selectedQueue?.reasons | orderBy : 'motifOrder'"
(click)='selectReason(reason)'>
<div *ngIf="!bankNotAllowed || reason.id !== 12" class="mIcon">
<img
src="/bower_components/nomadis/images-no-cache/reason?.imageName"
[ngClass]="'motif-unique': client?.registration?.queue?.reasons?.length == 1" />
<span>reason.name</span>
</div>
</div>
</div>
<div class="col-sm-offset-4 col-sm-4 btn-validate-reinsert">
<input id="validateReinsertBtn" type="submit" value="Valider"
[ngClass]="'queueAgain-disabled': !selectedReason"
class="btn btn-lg btn-primary btn-block"
(click)='queueAgain()' />
</div>
</div>
</div>
</div>
<router-outlet></router-outlet>
如你所见,我没有使用routeLink
。
在我的测试文件配置中,我已经这样做了:
component.spec.ts
:
import async, ComponentFixture, TestBed, tick, fakeAsync from '@angular/core/testing';
import QueueAgainComponent from './queue-again.component';
import OrderByPipe from 'app/home/pipe/order-by.pipe';
import SharedclientService from 'app/service/sharedclient.service';
import GdfaClientService from 'app/service/gdfa-client.service';
import AuthHttp, AuthConfig, AUTH_PROVIDERS, provideAuth from 'angular2-jwt';
import HttpModule from '@angular/http';
import EnvVarsService from 'app/service/env-vars.service';
import RouteNavigator from 'app/home/util/route-navigator';
import Router from '@angular/router';
import Observable from 'rxjs/Observable';
import * as QueueAgainMocks from 'TU/mocks/queue-again-mocks';
import RouterTestingModule from '@angular/router/testing';
import NO_ERRORS_SCHEMA from '@angular/core';
describe('QueueAgainComponent', () =>
let comp: QueueAgainComponent;
let fixture: ComponentFixture<QueueAgainComponent>;
let sharedclientService: SharedclientService;
let gdfaClientService: GdfaClientService;
let getShared360Client: jasmine.Spy;
let queueAgain: jasmine.Spy;
let client = QueueAgainMocks.CUSTOMER_MOCK;
let selectedQueue = QueueAgainMocks.SELECTED_QUEUE_MOCK;
let selectedReason = QueueAgainMocks.SELECTED_REASON;
let mockRouter =
navigate: jasmine.createSpy('navigate')
;
// TestBed preparation (async)
beforeEach(async(() =>
TestBed.configureTestingModule(
imports: [HttpModule , RouterTestingModule],
declarations: [QueueAgainComponent, OrderByPipe],
providers: [SharedclientService, GdfaClientService, AuthHttp, EnvVarsService, RouteNavigator,
provide: Router, useValue: mockRouter,
provideAuth(
headerName: 'Authorization',
headerPrefix: 'bearer',
tokenName: 'token',
tokenGetter: (() => localStorage.getItem('id_token')),
globalHeaders: ['Content-Type': 'application/json'],
noJwtError: true
)
],
schemas: [ NO_ERRORS_SCHEMA ]
).compileComponents();
));
// Fixture & Spies declarations
beforeEach(() =>
// Creation of the component fixture
fixture = TestBed.createComponent(QueueAgainComponent);
comp = fixture.componentInstance;
fixture.detectChanges(); // this line will call components ngOnInit() method
// Getting Services instances from fixture
sharedclientService = fixture.debugElement.injector.get(SharedclientService);
gdfaClientService = fixture.debugElement.injector.get(GdfaClientService);
// Call of fake methods of `sharedclientService` from the AlertServiceSpy
getShared360Client = spyOn(sharedclientService, 'getShared360Client').and.returnValue(client);
// Call of fake methods of `gdfaClientService` from the AlertServiceSpy
queueAgain = spyOn(gdfaClientService, 'queueAgain').and.callFake((reg) =>
return Observable.of('ok');
);
comp.ngOnInit();
);
// Test case of component compilation
it('should be defined', () =>
expect(comp).toBeDefined();
);
);
虽然我已经导入了NO_ERRORS_SCHEMA
并且我使用了mockRouter
,但路由似乎仍然有问题并出现此错误:
TypeError: Cannot read property 'root' of undefined
at rootRoute (node_modules/@angular/router/bundles/router.umd.js:6110:30)
at _callFactory (packages/core/src/view/ng_module.ts:185:1)
at _createProviderInstance$1 (packages/core/src/view/ng_module.ts:124:1)
at resolveNgModuleDep (node_modules/@angular/core/bundles/core.umd.js:9517:17)
at _createClass (packages/core/src/view/ng_module.ts:158:1)
at _createProviderInstance$1 (packages/core/src/view/ng_module.ts:121:1)
at resolveNgModuleDep (node_modules/@angular/core/bundles/core.umd.js:9517:17)
at NgModuleRef_.Object.<anonymous>.NgModuleRef_.get (node_modules/@angular/core/bundles/core.umd.js:10609:16)
at resolveDep (node_modules/@angular/core/bundles/core.umd.js:11112:45)
at createClass (node_modules/@angular/core/bundles/core.umd.js:10976:32)
at createDirectiveInstance (node_modules/@angular/core/bundles/core.umd.js:10796:37)
at createViewNodes (packages/core/src/view/view.ts:354:1)
at createRootView (node_modules/@angular/core/bundles/core.umd.js:12139:5)
at callWithDebugContext (packages/core/src/view/services.ts:815:1)
at Object.debugCreateRootView [as createRootView] (node_modules/@angular/core/bundles/core.umd.js:12842:12)
at ComponentFactory_.Object.<anonymous>.ComponentFactory_.create (node_modules/@angular/core/bundles/core.umd.js:9904:46)
at initComponent (node_modules/@angular/core/bundles/core-testing.umd.js:924:49)
at ZoneDelegate.Object.<anonymous>.ZoneDelegate.invoke (node_modules/zone.js/dist/zone-node.js:392:26)
at ProxyZoneSpec.Object.<anonymous>.ProxyZoneSpec.onInvoke (node_modules/zone.js/dist/proxy.js:79:39)
at ZoneDelegate.Object.<anonymous>.ZoneDelegate.invoke (node_modules/zone.js/dist/zone-node.js:391:32)
at Object.onInvoke (node_modules/@angular/core/bundles/core.umd.js:3922:33)
at ZoneDelegate.Object.<anonymous>.ZoneDelegate.invoke (node_modules/zone.js/dist/zone-node.js:391:32)
at Zone.Object.<anonymous>.Zone.run (node_modules/zone.js/dist/zone-node.js:142:43)
at NgZone.Object.<anonymous>.NgZone.run (node_modules/@angular/core/bundles/core.umd.js:3853:69)
at TestBed.Object.<anonymous>.TestBed.createComponent (packages/core/testing/src/test_bed.ts:471:1)
at Function.Object.<anonymous>.TestBed.createComponent (node_modules/@angular/core/bundles/core-testing.umd.js:691:29)
at src/app/home/advisor/queue-again/queue-again.component.spec.ts:53:27
从指向 53:27 行的日志的最后一行开始:
fixture = TestBed.createComponent(QueueAgainComponent);
所以它似乎无法创建 fixture。
有什么想法吗?
【问题讨论】:
【参考方案1】:我有同样的问题,只是想通了。 删除该行:
provide: Router, useValue: mockRouter
它会起作用的。
问题是当你导入 RouterTestingModule
时,你应该删除所有路由器模拟提供程序,除了 ActiveRoute
等。
【讨论】:
以上是关于角度单元测试:TypeError:无法读取未定义的属性“根”的主要内容,如果未能解决你的问题,请参考以下文章
反应笑话单元测试用例TypeError:无法读取未定义的属性'then'
渲染中的错误:“TypeError:无法读取未定义的属性'_t'”在使用 Jest 的单元测试中
[karma-server]:TypeError:无法读取未定义的属性“范围”-CI 环境中的 Angular 单元测试