I am trying to write a simple test for ActivatedRoute
. Here's what my test looks like.
it("should check if subscribes are called in init", () => {
const subRouteSpy = spyOn(activatedRouteStub.paramMap, "subscribe");
component.ngOnInit();
expect(subRouteSpy).toHaveBeenCalled();
});
My TestBed config
:
const activatedRouteStub = {
paramMap: {
subscribe() {
return of();
}
}
};
TestBed.configureTestingModule({
declarations: [HomeFilterDrawerComponent],
providers: [
{ provide: ActivatedRoute, useValue: activatedRouteStub }
],
imports: [
FormsModule,
StoreModule.forRoot(appReducers),
HttpClientTestingModule,
RouterTestingModule
]
}).compileComponents();
The test keeps failing giving me Expected spy subscribe to have been called.
Not sure what exactly I am doing wrong here.
The code inside ngOnInit
of the component.
this.route.paramMap.subscribe(params => {
if (params["params"].slug !== undefined) {
}
});
Angular is cloning your activatedRouteStub
object when you provide it via useValue
. So you're spying on the original stub object, but your component sees a cloned object without the spy attached.
This is mentioned in the guide
Always get the service from an injector Do not reference the userServiceStub object that's provided to the testing module in the body of your test. It does not work! The userService instance injected into the component is a completely different object, a clone of the provided userServiceStub.
To fix this, you need to get a reference to the cloned object using TestBed.get
let activatedRoute;
const activatedRouteStub = {
paramMap: {
subscribe() {
return of();
}
}
};
TestBed.configureTestingModule({
declarations: [HomeFilterDrawerComponent],
providers: [
{ provide: ActivatedRoute, useValue: activatedRouteStub }
],
imports: [
FormsModule,
StoreModule.forRoot(appReducers),
HttpClientTestingModule,
RouterTestingModule
]
}).compileComponents();
beforeEach(() => {
fixture = TestBed.createComponent(NewsComponent);
component = fixture.componentInstance;
// Get a reference to the injected value
activatedRoute = TestBed.get(ActivatedRoute);
});
it("should check if subscribes are called in init", () => {
// Spy on the injected value
const subRouteSpy = spyOn(activatedRoute.paramMap, "subscribe");
component.ngOnInit();
expect(subRouteSpy).toHaveBeenCalled();
});
Alternatively, you can keep your code the same, but change useValue
to useFactory
. This will allow you to bypass the cloning behavior:
providers: [{ provide: ActivatedRoute, useFactory: () => activatedRouteStub }]