Angular Karma - 组件未定义
Angular Karma - Component undefined
我正在尝试对需要 Resolver、Router 和 ActivatedRoute 作为依赖项的组件进行单元测试。我尝试使用 RouterTestingModule 并模拟我的解析器以在测试模块中提供它们,但它似乎对组件实例的创建有一些副作用。
这是我的组件的代码:
History.component.ts
import { Component, OnDestroy, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { Subscription } from 'rxjs';
import { Transaction } from '../models/transaction.model';
@Component({
selector: 'app-history',
templateUrl: './history.component.html',
styleUrls: ['./history.component.scss']
})
export class HistoryComponent implements OnInit, OnDestroy {
history: Transaction[] = [];
selectedTransaction: Transaction | undefined;
subscription: Subscription = new Subscription();
constructor(
private route: ActivatedRoute,
private router: Router,
) { }
ngOnInit(): void {
this.history = this.route.snapshot.data.history;
const routeSubscription = this.route.params.subscribe((params) => {
if (params.id) {
this.setSelectedTransaction(+params.id);
}
});
this.subscription.add(routeSubscription);
}
setSelectedTransaction(transactionId: number): void {
const historyTransaction = this.history.find((transaction) => transaction.id === transactionId);
this.selectedTransaction = historyTransaction;
}
displayTransaction(transaction: Transaction): void {
this.router.navigate(['transactions', transaction.id]);
}
ngOnDestroy(): void {
this.subscription.unsubscribe();
}
}
这是当前的单元测试:
History.spec.ts
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ActivatedRoute, Resolve, Routes } from '@angular/router';
import { RouterTestingModule } from '@angular/router/testing';
import { Observable, of } from 'rxjs';
import { Transaction } from '../models/transaction.model';
import { HistoryComponent } from './history.component';
import { HistoryResolver } from './history.resolver';
const mockRawTransactions = [
{
"id":"1",
"created_at":"2016-01-01T08:30:39-0300",
"counterparty_name":"Uber",
"debit":"false",
"credit":"true",
"amount":"44.20",
"currency":"EUR",
"operation_type":"refund",
"attachements":[
{
"url":"https:\/\/fakeimg.pl\/350x200\/?text=Hello"
}
],
}
];
const mockTransactions = mockRawTransactions.map((transaction) => new Transaction(transaction));
class HistoryMockResolver implements Resolve<Transaction[]> {
resolve(): Observable<Transaction[]> {
return of(mockTransactions);
}
}
describe('HistoryComponent', () => {
const historyRoutes: Routes = [
{ path: 'transactions', component: HistoryComponent },
{ path: 'transactions/:id', component: HistoryComponent },
];
let component: HistoryComponent;
let fixture: ComponentFixture<HistoryComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ HistoryComponent ],
imports: [
RouterTestingModule.withRoutes(historyRoutes),
],
providers: [
{
provide: ActivatedRoute,
useValue: {
snapshot: {
params: { id: 1 },
},
},
},
{ provide: HistoryResolver, useClass: HistoryMockResolver },
]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(HistoryComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
console.log('Component', component);
expect(component).toBeTruthy();
});
it('should display transactions', () => {
component.history = mockTransactions;
expect(component.history).toBeDefined();
expect(component.history).toHaveSize(mockRawTransactions.length);
});
it('should display a single transaction', () => {
component.history = mockTransactions;
component.displayTransaction(component.history[0]);
expect(component.selectedTransaction).toBeDefined();
expect(component.selectedTransaction).toEqual(component.history[0]);
});
});
组件已定义并在 console.log 中显示良好,而 运行 在 Karma 中的测试,但 Karma 会为每个测试用例引发错误并将组件评估为未定义。
这是第一个错误:
TypeError: Cannot read property 'history' of undefined
at HistoryComponent.ngOnInit (http://localhost:9876/_karma_webpack_/webpack:/src/app/history/history.component.ts:22:45)
at callHook (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:2486:1)
at callHooks (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:2457:1)
at executeInitAndCheckHooks (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:2408:1)
at refreshView (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:9207:1)
at renderComponentOrTemplate (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:9306:1)
at tickRootContext (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:10532:1)
at detectChangesInRootView (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:10557:1)
at RootViewRef.detectChanges (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:22569:1)
at ComponentFixture._tick (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/testing.js:141:1)
我应该在测试模块中修复什么?
这是因为 this.route.snapshot.data.history
数据未定义,因为您没有在模拟激活快照中传递它。
您可以在 History.spec.ts
中更新您的提供商以获得已激活的路线快照
{
provide: ActivatedRoute,
useValue: {
snapshot: {
params: { id: 1 },
data: {history: 'something-history-obj'}
},
},
},
或者您始终可以在 History.component.ts
中使用 this.route.snapshot.data?.history
如果它确实可以为 null
我正在尝试对需要 Resolver、Router 和 ActivatedRoute 作为依赖项的组件进行单元测试。我尝试使用 RouterTestingModule 并模拟我的解析器以在测试模块中提供它们,但它似乎对组件实例的创建有一些副作用。
这是我的组件的代码:
History.component.ts
import { Component, OnDestroy, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { Subscription } from 'rxjs';
import { Transaction } from '../models/transaction.model';
@Component({
selector: 'app-history',
templateUrl: './history.component.html',
styleUrls: ['./history.component.scss']
})
export class HistoryComponent implements OnInit, OnDestroy {
history: Transaction[] = [];
selectedTransaction: Transaction | undefined;
subscription: Subscription = new Subscription();
constructor(
private route: ActivatedRoute,
private router: Router,
) { }
ngOnInit(): void {
this.history = this.route.snapshot.data.history;
const routeSubscription = this.route.params.subscribe((params) => {
if (params.id) {
this.setSelectedTransaction(+params.id);
}
});
this.subscription.add(routeSubscription);
}
setSelectedTransaction(transactionId: number): void {
const historyTransaction = this.history.find((transaction) => transaction.id === transactionId);
this.selectedTransaction = historyTransaction;
}
displayTransaction(transaction: Transaction): void {
this.router.navigate(['transactions', transaction.id]);
}
ngOnDestroy(): void {
this.subscription.unsubscribe();
}
}
这是当前的单元测试:
History.spec.ts
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ActivatedRoute, Resolve, Routes } from '@angular/router';
import { RouterTestingModule } from '@angular/router/testing';
import { Observable, of } from 'rxjs';
import { Transaction } from '../models/transaction.model';
import { HistoryComponent } from './history.component';
import { HistoryResolver } from './history.resolver';
const mockRawTransactions = [
{
"id":"1",
"created_at":"2016-01-01T08:30:39-0300",
"counterparty_name":"Uber",
"debit":"false",
"credit":"true",
"amount":"44.20",
"currency":"EUR",
"operation_type":"refund",
"attachements":[
{
"url":"https:\/\/fakeimg.pl\/350x200\/?text=Hello"
}
],
}
];
const mockTransactions = mockRawTransactions.map((transaction) => new Transaction(transaction));
class HistoryMockResolver implements Resolve<Transaction[]> {
resolve(): Observable<Transaction[]> {
return of(mockTransactions);
}
}
describe('HistoryComponent', () => {
const historyRoutes: Routes = [
{ path: 'transactions', component: HistoryComponent },
{ path: 'transactions/:id', component: HistoryComponent },
];
let component: HistoryComponent;
let fixture: ComponentFixture<HistoryComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ HistoryComponent ],
imports: [
RouterTestingModule.withRoutes(historyRoutes),
],
providers: [
{
provide: ActivatedRoute,
useValue: {
snapshot: {
params: { id: 1 },
},
},
},
{ provide: HistoryResolver, useClass: HistoryMockResolver },
]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(HistoryComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
console.log('Component', component);
expect(component).toBeTruthy();
});
it('should display transactions', () => {
component.history = mockTransactions;
expect(component.history).toBeDefined();
expect(component.history).toHaveSize(mockRawTransactions.length);
});
it('should display a single transaction', () => {
component.history = mockTransactions;
component.displayTransaction(component.history[0]);
expect(component.selectedTransaction).toBeDefined();
expect(component.selectedTransaction).toEqual(component.history[0]);
});
});
组件已定义并在 console.log 中显示良好,而 运行 在 Karma 中的测试,但 Karma 会为每个测试用例引发错误并将组件评估为未定义。
这是第一个错误:
TypeError: Cannot read property 'history' of undefined
at HistoryComponent.ngOnInit (http://localhost:9876/_karma_webpack_/webpack:/src/app/history/history.component.ts:22:45)
at callHook (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:2486:1)
at callHooks (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:2457:1)
at executeInitAndCheckHooks (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:2408:1)
at refreshView (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:9207:1)
at renderComponentOrTemplate (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:9306:1)
at tickRootContext (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:10532:1)
at detectChangesInRootView (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:10557:1)
at RootViewRef.detectChanges (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:22569:1)
at ComponentFixture._tick (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/testing.js:141:1)
我应该在测试模块中修复什么?
这是因为 this.route.snapshot.data.history
数据未定义,因为您没有在模拟激活快照中传递它。
您可以在 History.spec.ts
{
provide: ActivatedRoute,
useValue: {
snapshot: {
params: { id: 1 },
data: {history: 'something-history-obj'}
},
},
},
或者您始终可以在 History.component.ts
中使用 this.route.snapshot.data?.history
如果它确实可以为 null