Working StackBlitz.
There were a few typos:
First, I think you meant to declare getAnotherReport as a value, not as a type:
let getAnotherReport = {
text: null,
ref: "7478B45D4D4F1400223BD2F1",
num: 19,
urn: "123",
title: "Test report",
label: "accept & view"
};
then, in SearchComponent.viewFunc you have url = 'main' and in your spec you have:
expect(routerSpy.navigate).toHaveBeenCalledWith(["/main"], {
queryParams: { queryString: queryString }
});
and it should be without /:
expect(routerSpy.navigate).toHaveBeenCalledWith(["main"], {
queryParams: { queryString: queryString }
});
And now, let's see the interesting things.
We'll first explore the first assertion:
const mySpy = jasmine.createSpy("getAnotherReport").and.callThrough();
/* ... */
testee.viewFunc(queryString);
/* .... */
expect(mySpy).toHaveBeenCalled();
the issue here is related to how you decided to spy viewFunc. In this case, you've used spyOn(component, "viewFunc");:
These are the relevant bits that happen under the hood when you call spyOn:
var originalMethod = obj[methodName],
spiedMethod = createSpy(methodName, originalMethod),
where createSpy will be an empty spy, i.e it will simply be used to track how many times the function was called, with which arguments etc. But it will not use the original implementation, which is not what you want, because you also have assertions that concern ReportService, which resides in viewFunc's original implementation.
In order to use the the initial implementation, you can use .and.callThrough():
// a quick look at the fact that it uses the original function
SpyStrategy.prototype.callThrough = function() {
this.plan = this.originalFn;
return this.getSpy();
};
reportService = TestBed.get(ReportService);
// and here we are using it
spyOn(component, "viewFunc").and.callThrough();
put it all together:
// you can get ahold of the current spy like this
const mySpy = mockReportService.getAnotherReport.and.returnValue(
of(getAnotherReport)
);
expect(testee).toBeTruthy();
testee.viewFunc(queryString);
expect(mySpy).toHaveBeenCalled();
And now onto the second assertion:
// inside providers array
{ provide: Router, useValue: routerSpy },
/* ... */
const routerSpy = { navigate: jasmine.createSpy("navigate") };
expect(routerSpy.navigate).toHaveBeenCalledWith(["main"], {
queryParams: { queryString: queryString }
});
In this case, notice you're using a different object than what you've mocked the Router class with.
You'll have to use the same object that you used to mock that class in question, so a way to solve this would be:
let routerSpy = { navigate: jasmine.createSpy("navigate") };
/* ... */
// inside providers array
{ provide: Router, useValue: routerSpy },
/* ... */
const mySpy = mockReportService.getAnotherReport.and.returnValue(
of(getAnotherReport)
);
expect(testee).toBeTruthy();
testee.viewFunc(queryString);
expect(mySpy).toHaveBeenCalled();
expect(routerSpy.navigate).toHaveBeenCalledWith(["main"], {
queryParams: { queryString: queryString }
});
Quick tip
I'm not very familiar with Jasmine either, but it helped me a lot to see what it does under the hood. Without having to understand every tiny detail, you can at least get an intuition to how you could solve your problem. So, when in a StackBlitz app, like the one you linked, you can:
- open the dev tools
- press
CTRL + P and type jasmine.js(there may be more than one file, the right one is the one in which resides known methods like callThrough - you can check this by pressing CTRL + SHIFT + O and typing the method name)
additionally, you can search for search.component.ts and place some breakpoints there for a smoother debugging experience.