I am hitting a problem unit testing the following Angular 9 component:
export class BirdsDetailComponent implements OnInit {
...
constructor(private route: ActivatedRoute) {
route.params.subscribe(_ => {
this.route.paramMap.subscribe(pmap => this.getData(+pmap.get('id')));
});
}
ngOnInit() {}
getData(id: number): void { ... }
Unlike in other components that I am familiar with, this component initiates the data retrieval from the constructor.
I am hitting a problem (I think) with setting the route parameter. I have tried a range of ways of setting up the activated route mock/stub. Including the one found in this setup in the Angular docs.
describe('BirdsDetailComponent', () => {
let component: BirdsDetailComponent;
let fixture: ComponentFixture<BirdsDetailComponent>;
let activatedRoute: ActivatedRouteStub;
beforeEach(() => {
activatedRoute = new ActivatedRouteStub();
});
// the `id` value is irrelevant because ignored by service stub
beforeEach(() => activatedRoute.setParamMap({ id: 99999 }));
beforeEach(async(() => {
const routerSpy = createRouterSpy();
function createRouterSpy() {
return jasmine.createSpyObj('Router', ['navigate']);
}
TestBed.configureTestingModule({
imports: [RouterTestingModule.withRoutes([])],
declarations: [BirdsDetailComponent],
providers: [
{
provide: ActivatedRoute, useValue: ActivatedRouteStub
}
// {
// provide: ActivatedRoute,
// useValue: {
// params: of({ id: '123' })
// }
// }
]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(BirdsDetailComponent);
component = fixture.componentInstance;
activatedRoute.setParamMap({ id: 1 });
});
it('should call getData', () => {
const conserveStatus = {
conservationStatusId: 1, conservationList: 'string',
conservationListColourCode: 'string', description: 'string', creationDate: 'Date | string',
lastUpdateDate: 'Date | string', birds: []
};
const bird = {
birdId: 1, class: 'string', order: 'string', family: 'string',
genus: 'string', species: 'string', englishName: 'string', populationSize: 'string',
btoStatusInBritain: 'string', thumbnailUrl: 'string', songUrl: 'string',
birderStatus: 'string', birdConservationStatus: conserveStatus,
internationalName: 'string', category: 'string', creationDate: 'Date | string',
lastUpdateDate: 'Date | string'
};
fixture.detectChanges();
// // Act or change
// component.getBird(1);
// // fixture.detectChanges();
// Assert
expect(mockBirdsService.getBird).toHaveBeenCalled();
});
});
I have also tried a simple setup of the activated route parameter, which you can see in the commented out code, like this (and variation of this):
{
provide: ActivatedRoute,
useValue: {
params: of({ id: '123' })
}
}
Whatever I try I also seem to hit the 'Cannot read property 'subscribe' of undefined thrown' error. Could the problem be related to detecting the changes? Can anyone point me in the right direction?