Я использую это, от здесь:
constructor(private heroService: HeroService,
private activatedRoute: ActivatedRoute) {
}
ngOnInit() {
const heroId = this.activatedRoute.snapshot.paramMap.get('id');
this.heroService.getHeroById(heroId).subscribe((hero: Hero) => {
...
});
}
Теперь у меня есть модульный тест, который должен имитировать этот ActivatedRoute. Я уже проверял некоторые ответы здесь, в stackoverflow, но безуспешно.
Обратите внимание, что я использую snapshot.paramMap, поэтому многие решения вообще не работают. Например, это, это и это не работают.
Я думаю, что почти верный ответ может быть таким:
{
provide: ActivatedRoute,
useValue: {paramMap: Observable.of(convertToParamMap({id: 1}))}
}
Но тоже не работает.
Отображаемая ошибка:
Error: Failed to execute 'send' on 'XMLHttpRequest': Failed to load 'ng:///HeroesModule/HeroDetailComponent_Host.ngfactory.js'.
error properties: Object({ INDEX_SIZE_ERR: 1, DOMSTRING_SIZE_ERR: 2, HIERARCHY_REQUEST_ERR: 3, WRONG_DOCUMENT_ERR: 4, INVALID_CHARACTER_ERR: 5, NO_DATA_ALLOWED_ERR: 6, NO_MODIFICATION_ALLOWED_ERR: 7, NOT_FOUND_ERR: 8, NOT_SUPPORTED_ERR: 9, INUSE_ATTRIBUTE_ERR: 10, INVALID_STATE_ERR: 11, SYNTAX_ERR: 12, INVALID_MODIFICATION_ERR: 13, NAMESPACE_ERR: 14, INVALID_ACCESS_ERR: 15, VALIDATION_ERR: 16, TYPE_MISMATCH_ERR: 17, SECURITY_ERR: 18, NETWORK_ERR: 19, ABORT_ERR: 20, URL_MISMATCH_ERR: 21, QUOTA_EXCEEDED_ERR: 22, TIMEOUT_ERR: 23, INVALID_NODE_TYPE_ERR: 24, DATA_CLONE_ERR: 25, code: 19 })
Это потому, что я делаю запрос, который отвечает со статусом 500, потому что paramMap не определен, поэтому в запросе нет идентификатора.
... Любые идеи?
Спасибо и BR





Добавьте снимок к useValue, например:
{
provide: ActivatedRoute,
useValue: {
snapshot: {
paramMap: convertToParamMap({
id: '1'
})
}
}
}
В последних версиях Angular настройка проекта aot включена по умолчанию (для лучшей проверки типов во время компиляции). Если это так с вашим проектом, то вам, вероятно, нужно хотя бы заглушить все свойства ActivatedRoute и ActivatedRouteSnapshot. Что-то вроде этого:
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { Type } from '@angular/core';
import { Location } from '@angular/common';
import { MockPlatformLocation } from '@angular/common/testing';
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
import { ActivatedRoute, ActivatedRouteSnapshot, Params, ParamMap, convertToParamMap } from '@angular/router';
import { of, BehaviorSubject } from 'rxjs';
import { HeroDetailComponent } from './hero-detail.component';
import { Hero } from '../hero';
export class MockActivatedRouteSnapshot implements ActivatedRouteSnapshot {
private innerTestParams?: Params;
constructor(params?: Params) {
if (params) {
this.testParams = params;
} else {
this.testParams = null;
}
}
private get testParams() {
return this.innerTestParams;
}
private set testParams(params: Params) {
this.innerTestParams = params;
}
get paramMap() {
return convertToParamMap(this.testParams);
}
get queryParamMap() {
return this.paramMap;
}
get url() {
return null;
}
get fragment() {
return null;
}
get data() {
return null;
}
get outlet() {
return null;
}
get params() {
return this.innerTestParams;
}
get queryParams() {
return this.innerTestParams;
}
get component() {
return null;
}
get routeConfig() {
return null;
}
get root() {
return null;
}
get parent() {
return null;
}
get firstChild() {
return null;
}
get children() {
return null;
}
get pathFromRoot() {
return null;
}
}
export class MockActivatedRoute implements ActivatedRoute {
private innerTestParams?: Params;
private subject?: BehaviorSubject<Params> = new BehaviorSubject(this.testParams);
private paramMapSubject?: BehaviorSubject<ParamMap> = new BehaviorSubject(convertToParamMap(this.testParams));
constructor(params?: Params) {
if (params) {
this.testParams = params;
} else {
this.testParams = null;
}
}
private get testParams() {
return this.innerTestParams;
}
private set testParams(params: Params) {
this.innerTestParams = params;
this.subject.next(params);
this.paramMapSubject.next(convertToParamMap(params));
}
get snapshot() {
return new MockActivatedRouteSnapshot(this.testParams);
}
get params() {
return this.subject.asObservable();
}
get queryParams() {
return this.params;
}
get paramMap() {
return this.paramMapSubject.asObservable();
}
get queryParamMap() {
return this.paramMap;
}
get url() {
return null;
}
get fragment() {
return null;
}
get data() {
return null;
}
get outlet() {
return null;
}
get component() {
return null;
}
get routeConfig() {
return null;
}
get root() {
return null;
}
get parent() {
return null;
}
get firstChild() {
return null;
}
get children() {
return null;
}
get pathFromRoot() {
return null;
}
}
describe('HeroDetailComponent', () => {
let component: HeroDetailComponent;
let fixture: ComponentFixture<HeroDetailComponent>;
let httpMock: HttpTestingController;
let routeMock: MockActivatedRoute;
let initialMockParams: Params;
let locationMock: MockPlatformLocation;
beforeEach(async(() => {
initialMockParams = {id: 11};
routeMock = new MockActivatedRoute(initialMockParams);
locationMock = new MockPlatformLocation;
TestBed.configureTestingModule({
imports: [
HttpClientTestingModule
],
declarations: [ HeroDetailComponent ],
providers: [
{
provide: ActivatedRoute, useValue: routeMock,
},
{
provide: Location, useValue: locationMock,
}
]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(HeroDetailComponent);
component = fixture.componentInstance;
httpMock = TestBed.inject<HttpTestingController>(HttpTestingController as Type<HttpTestingController>);
fixture.detectChanges();
});
afterEach(() => {
httpMock.verify();
});
it('should be created', () => {
fixture.detectChanges();
expect(component).toBeTruthy();
const dummyHero: Hero = { id: 11, name: 'dummyHero' };
const req = httpMock.expectOne('api/details/11');
req.flush(dummyHero);
});
});