this.activatedRoute.queryParamMap.pipe 中的单元测试茉莉花错误
Unit test jasmine error in this.activatedRoute.queryParamMap.pipe
我有一个 Anuglar(版本 8)应用程序,它使用 ngrx/store 和 RxJs for angular 这个组件:
export class CarComponent implements OnInit, OnDestroy {
// subscriptions
private unsubscribe$ = new Subject<void>();
constructor(
private activatedRoute: ActivatedRoute,
private readonly store: Store<any>,
private routingService: RoutingService,
private readonly carService: CarService) {}
ngOnInit(): void {
this.activatedRoute.queryParamMap.pipe(
takeUntil(this.unsubscribe$)).subscribe((paramMap: ParamMap) => {
this.store
.pipe(
select(selectDog, { dog: paramMap.get('carCode')})
)
.subscribe((car: Car) => {
this.setCar(Car);
}).unsubscribe();
});
}}
}
我用 Karma 和 Jasmine 创建了一个单元测试:
import { ChangeDetectionStrategy } from '@angular/core';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ReactiveFormsModule } from '@angular/forms';
import { ActivatedRoute, Router } from '@angular/router';
import { RouterTestingModule } from '@angular/router/testing';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { NgSelectModule } from '@ng-select/ng-select';
import { EffectsModule } from '@ngrx/effects';
import { Store, StoreModule } from '@ngrx/store';
import { Observable } from 'rxjs';
const scope = (): Scope => {
return {
carCode: '5288-5547-5247-4',
brandCar: '480',
};
};
describe('CarComponent ', () => {
let activatedRoute: ActivatedRoute;
let component: CarComponent;
let fixture: ComponentFixture<CarComponent>;
let store: Store<any>;
let routingService: RoutingService;
let router: Router;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
ReactiveFormsModule,
RouterTestingModule,
RouterTestingModule.withRoutes([]),
SharedModule,
StoreModule.forRoot({}),
StoreModule.forFeature(stayRestrictionsFeatureKey, stayRestrictionReducer),
StoreModule.forFeature(scopeFeatureKey, scopeReducer),
StoreModule.forFeature(inventoryFeatureKey, inventoryReducer),
StoreModule.forFeature(codeCarFeatureKey, codeCarReducer),
StoreModule.forFeature('scope', scopeReducer),
EffectsModule.forRoot([]),
NgbModule,
NgSelectModule,
NgOptionHighlightModule
],
providers: [{
provide: ActivatedRoute,
useValue: {
snapshot: {
queryParams: {
carCode: 'ss'
}
}
}
},
{
provide: Router,
useValue: {
routerState: {
snapshot : {
url : 'month/day/123'
}
}
}
}]
})
}));
beforeEach(() => {
activatedRoute = TestBed.get(ActivatedRoute.prototype.queryParamMap.pipe());
router = TestBed.get(Router);
routingService = TestBed.get(RoutingService);
store = TestBed.get(Store);
spyOn(store, 'dispatch').and.callThrough();
store.dispatch(new LoadScopeSuccess(scope()));
fixture = TestBed.createComponent(CarComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('init', () => {
spyOn(activatedRoute.queryParamMap, 'pipe').and.returnValue(new Observable());
component.ngOnInit();
const start = DateUtil.firstOfMonth();
const end = endDate(start, 3);
fixture.whenStable().then(_ => {
expect(component.searchCriteriaForm.get('carCode').value).toEqual('5288-5547-5247-4');
expect(component.searchCriteriaForm.get('brandCode').value).toEqual('480');
});
});
});
但是当我启动测试时出现这个错误:
1) init
CarComponent
TypeError: Cannot read property 'pipe' of undefined
at Object.get queryParamMap [as queryParamMap] (http://localhost:9876/_karma_webpack_/C:/Root/root-projects/[...]/client/node_modules/@angular/router/fesm2015/router.js:2747:1)
at UserContext.<anonymous> (http://localhost:9876/_karma_webpack_/src/app/monthly-view/monthly-view.component.spec.ts:90:59)
at ZoneDelegate.invoke (http://localhost:9876/_karma_webpack_/C:/Root/root-projects/[...]/client/node_modules/zone.js/dist/zone-evergreen.js:359:1)
at ProxyZoneSpec.push.../../node_modules/zone.js/dist/zone-testing.js.ProxyZoneSpec.onInvoke (http://localhost:9876/_karma_webpack_/C:/Root/root-projects/[...]/client/node_modules/zone.js/dist/zone-testing.js:308:
1)
at ZoneDelegate.invoke (http://localhost:9876/_karma_webpack_/C:/Root/root-projects/[...]/client/node_modules/zone.js/dist/zone-evergreen.js:358:1)
at Zone.run (http://localhost:9876/_karma_webpack_/C:/Root/root-projects/[...]/client/node_modules/zone.js/dist/zone-evergreen.js:124:1)
[...]
我试过模拟激活路由,但我还没有找到解决方案。您有解决方案来绕过这个问题吗?非常感谢。
您必须模拟 activatedRoute.queryParamMap
,不幸的是,由于它不是一种方法,因此您不能使用 pipe
。我会这样做:
import { ChangeDetectionStrategy } from '@angular/core';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ReactiveFormsModule } from '@angular/forms';
import { ActivatedRoute, Router } from '@angular/router';
import { RouterTestingModule } from '@angular/router/testing';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { NgSelectModule } from '@ng-select/ng-select';
import { EffectsModule } from '@ngrx/effects';
import { Store, StoreModule } from '@ngrx/store';
import { Observable } from 'rxjs';
const scope = (): Scope => {
return {
carCode: '5288-5547-5247-4',
brandCar: '480',
};
};
describe('CarComponent ', () => {
let activatedRoute: ActivatedRoute;
let component: CarComponent;
let fixture: ComponentFixture<CarComponent>;
let store: Store<any>;
let routingService: RoutingService;
let router: Router;
// !! add this line
const mockQueryParamMap = new BehaviorSubject<any>({
get(value: string) => {
if (value === 'carCode') {
return '123'; // your mock for `carCode`
} else {
return '456';
}
}
});
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
ReactiveFormsModule,
RouterTestingModule,
RouterTestingModule.withRoutes([]),
SharedModule,
StoreModule.forRoot({}),
StoreModule.forFeature(stayRestrictionsFeatureKey, stayRestrictionReducer),
StoreModule.forFeature(scopeFeatureKey, scopeReducer),
StoreModule.forFeature(inventoryFeatureKey, inventoryReducer),
StoreModule.forFeature(codeCarFeatureKey, codeCarReducer),
StoreModule.forFeature('scope', scopeReducer),
EffectsModule.forRoot([]),
NgbModule,
NgSelectModule,
NgOptionHighlightModule
],
providers: [{
provide: ActivatedRoute,
useValue: {
snapshot: {
queryParams: {
carCode: 'ss'
}
}
}
},
{
provide: Router,
useValue: {
routerState: {
snapshot : {
url : 'month/day/123'
}
},
// !! add this line
queryParamMap: mockQueryParamMap,
},
}]
})
}));
it('init', () => {
// this is why we use BehaviorSubject so we have full control
// on what to push into the subscription
mockQueryParamMap.next({
get(value: string) => {
if (value === 'carCode') {
return '5288-5547-5247-4'; // your mock for `carCode`
} else {
return '456';
}
}
});
component.ngOnInit();
const start = DateUtil.firstOfMonth();
const end = endDate(start, 3);
fixture.whenStable().then(_ => {
expect(component.searchCriteriaForm.get('carCode').value).toEqual('5288-5547-5247-4');
expect(component.searchCriteriaForm.get('brandCode').value).toEqual('480');
});
});
我有一个 Anuglar(版本 8)应用程序,它使用 ngrx/store 和 RxJs for angular 这个组件:
export class CarComponent implements OnInit, OnDestroy {
// subscriptions
private unsubscribe$ = new Subject<void>();
constructor(
private activatedRoute: ActivatedRoute,
private readonly store: Store<any>,
private routingService: RoutingService,
private readonly carService: CarService) {}
ngOnInit(): void {
this.activatedRoute.queryParamMap.pipe(
takeUntil(this.unsubscribe$)).subscribe((paramMap: ParamMap) => {
this.store
.pipe(
select(selectDog, { dog: paramMap.get('carCode')})
)
.subscribe((car: Car) => {
this.setCar(Car);
}).unsubscribe();
});
}}
}
我用 Karma 和 Jasmine 创建了一个单元测试:
import { ChangeDetectionStrategy } from '@angular/core';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ReactiveFormsModule } from '@angular/forms';
import { ActivatedRoute, Router } from '@angular/router';
import { RouterTestingModule } from '@angular/router/testing';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { NgSelectModule } from '@ng-select/ng-select';
import { EffectsModule } from '@ngrx/effects';
import { Store, StoreModule } from '@ngrx/store';
import { Observable } from 'rxjs';
const scope = (): Scope => {
return {
carCode: '5288-5547-5247-4',
brandCar: '480',
};
};
describe('CarComponent ', () => {
let activatedRoute: ActivatedRoute;
let component: CarComponent;
let fixture: ComponentFixture<CarComponent>;
let store: Store<any>;
let routingService: RoutingService;
let router: Router;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
ReactiveFormsModule,
RouterTestingModule,
RouterTestingModule.withRoutes([]),
SharedModule,
StoreModule.forRoot({}),
StoreModule.forFeature(stayRestrictionsFeatureKey, stayRestrictionReducer),
StoreModule.forFeature(scopeFeatureKey, scopeReducer),
StoreModule.forFeature(inventoryFeatureKey, inventoryReducer),
StoreModule.forFeature(codeCarFeatureKey, codeCarReducer),
StoreModule.forFeature('scope', scopeReducer),
EffectsModule.forRoot([]),
NgbModule,
NgSelectModule,
NgOptionHighlightModule
],
providers: [{
provide: ActivatedRoute,
useValue: {
snapshot: {
queryParams: {
carCode: 'ss'
}
}
}
},
{
provide: Router,
useValue: {
routerState: {
snapshot : {
url : 'month/day/123'
}
}
}
}]
})
}));
beforeEach(() => {
activatedRoute = TestBed.get(ActivatedRoute.prototype.queryParamMap.pipe());
router = TestBed.get(Router);
routingService = TestBed.get(RoutingService);
store = TestBed.get(Store);
spyOn(store, 'dispatch').and.callThrough();
store.dispatch(new LoadScopeSuccess(scope()));
fixture = TestBed.createComponent(CarComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('init', () => {
spyOn(activatedRoute.queryParamMap, 'pipe').and.returnValue(new Observable());
component.ngOnInit();
const start = DateUtil.firstOfMonth();
const end = endDate(start, 3);
fixture.whenStable().then(_ => {
expect(component.searchCriteriaForm.get('carCode').value).toEqual('5288-5547-5247-4');
expect(component.searchCriteriaForm.get('brandCode').value).toEqual('480');
});
});
});
但是当我启动测试时出现这个错误:
1) init
CarComponent
TypeError: Cannot read property 'pipe' of undefined
at Object.get queryParamMap [as queryParamMap] (http://localhost:9876/_karma_webpack_/C:/Root/root-projects/[...]/client/node_modules/@angular/router/fesm2015/router.js:2747:1)
at UserContext.<anonymous> (http://localhost:9876/_karma_webpack_/src/app/monthly-view/monthly-view.component.spec.ts:90:59)
at ZoneDelegate.invoke (http://localhost:9876/_karma_webpack_/C:/Root/root-projects/[...]/client/node_modules/zone.js/dist/zone-evergreen.js:359:1)
at ProxyZoneSpec.push.../../node_modules/zone.js/dist/zone-testing.js.ProxyZoneSpec.onInvoke (http://localhost:9876/_karma_webpack_/C:/Root/root-projects/[...]/client/node_modules/zone.js/dist/zone-testing.js:308:
1)
at ZoneDelegate.invoke (http://localhost:9876/_karma_webpack_/C:/Root/root-projects/[...]/client/node_modules/zone.js/dist/zone-evergreen.js:358:1)
at Zone.run (http://localhost:9876/_karma_webpack_/C:/Root/root-projects/[...]/client/node_modules/zone.js/dist/zone-evergreen.js:124:1)
[...]
我试过模拟激活路由,但我还没有找到解决方案。您有解决方案来绕过这个问题吗?非常感谢。
您必须模拟 activatedRoute.queryParamMap
,不幸的是,由于它不是一种方法,因此您不能使用 pipe
。我会这样做:
import { ChangeDetectionStrategy } from '@angular/core';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ReactiveFormsModule } from '@angular/forms';
import { ActivatedRoute, Router } from '@angular/router';
import { RouterTestingModule } from '@angular/router/testing';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { NgSelectModule } from '@ng-select/ng-select';
import { EffectsModule } from '@ngrx/effects';
import { Store, StoreModule } from '@ngrx/store';
import { Observable } from 'rxjs';
const scope = (): Scope => {
return {
carCode: '5288-5547-5247-4',
brandCar: '480',
};
};
describe('CarComponent ', () => {
let activatedRoute: ActivatedRoute;
let component: CarComponent;
let fixture: ComponentFixture<CarComponent>;
let store: Store<any>;
let routingService: RoutingService;
let router: Router;
// !! add this line
const mockQueryParamMap = new BehaviorSubject<any>({
get(value: string) => {
if (value === 'carCode') {
return '123'; // your mock for `carCode`
} else {
return '456';
}
}
});
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
ReactiveFormsModule,
RouterTestingModule,
RouterTestingModule.withRoutes([]),
SharedModule,
StoreModule.forRoot({}),
StoreModule.forFeature(stayRestrictionsFeatureKey, stayRestrictionReducer),
StoreModule.forFeature(scopeFeatureKey, scopeReducer),
StoreModule.forFeature(inventoryFeatureKey, inventoryReducer),
StoreModule.forFeature(codeCarFeatureKey, codeCarReducer),
StoreModule.forFeature('scope', scopeReducer),
EffectsModule.forRoot([]),
NgbModule,
NgSelectModule,
NgOptionHighlightModule
],
providers: [{
provide: ActivatedRoute,
useValue: {
snapshot: {
queryParams: {
carCode: 'ss'
}
}
}
},
{
provide: Router,
useValue: {
routerState: {
snapshot : {
url : 'month/day/123'
}
},
// !! add this line
queryParamMap: mockQueryParamMap,
},
}]
})
}));
it('init', () => {
// this is why we use BehaviorSubject so we have full control
// on what to push into the subscription
mockQueryParamMap.next({
get(value: string) => {
if (value === 'carCode') {
return '5288-5547-5247-4'; // your mock for `carCode`
} else {
return '456';
}
}
});
component.ngOnInit();
const start = DateUtil.firstOfMonth();
const end = endDate(start, 3);
fixture.whenStable().then(_ => {
expect(component.searchCriteriaForm.get('carCode').value).toEqual('5288-5547-5247-4');
expect(component.searchCriteriaForm.get('brandCode').value).toEqual('480');
});
});