EDIT: 2 added complete example of how to Unit test Angular 2/4 service with HTTP call stub data replacing original example. Excellent example of unit testing a service IMO somewhat different than official and third party guide.
EDIT: re-read official guide and after @AnteJablanAdamović in the above comments pointed out it's supposed to be
it('should tell ROUTER to navigate when hero clicked',
inject([Router], (router: Router) => { // ...
}));
https://angular.io/guide/testing#the-inject-function
I'm not sure if you can wrap it in an fakeasync(why not?) or async as a call back but this is the correct answer to my original question(how did nobody figure this out with a 50+ bounty and 10+ upvotes?!).
However strategy below is a cleaner/faster way to do this imo instead of pasting inject into every "it" statement by including it in BeforeEach;
It's a shame Karma or angular doesn't throw any error or warning flags.
Here's the original answer I provided but also works as an alternative way:
I used testBet.get to inject service in beforeEarch: Much better than what most guides suggest IMO.
Try this guide if your having issues testing services: covers simple or complex services with dependencies:
http://www.kirjai.com/testing-angular-services-with-dependencies/
describe('SearchService', () => {
// IMPORTANT - declase variables we'll set in before each so every "it statement // can reach them
let searchService: SearchService;
let backend: MockBackend;
let setupConnections;
class MockActivatedRoute extends ActivatedRoute {
constructor() {
super();
this.params = Observable.of({ 'searchterm': '*', 'sorttype': 'relevant', 'pagenumber': 1, 'facet': '' });
}
}
const MockRouter = {
navigate: (x) => ({
then: () => ({})
})
};
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpModule],
providers: [
// below required for HTTP substitution testing
MockBackend,
BaseRequestOptions,
{
provide: Http,
useFactory: (backend: MockBackend, options: BaseRequestOptions) => new Http(backend, options),
deps: [MockBackend, BaseRequestOptions]
},
AnalyticsService,
{ provide: ActivatedRoute, useClass: MockActivatedRoute },
{
provide: Router,
useValue: MockRouter
},
SearchService
]
});
// set our values in before each and use Testbed to inject services
searchService = TestBed.get(SearchService);
backend = TestBed.get(MockBackend);
you can set path with if statements like in guide link above for setupConnections but unless your doing something unusual with a call, you don't need to have path match so this is fine
setupConnections = (backend: MockBackend, options: any) => {
backend.connections.subscribe((connection: MockConnection) => {
const responseOptions = new ResponseOptions(options);
const response = new Response(responseOptions);
connection.mockRespond(response);
});
};
});
Note the async not fakeAsync!!!! Usually I use fakeAsync fine in component unit testing but I got some errors doing this when unit testing these services this way, YMMV
it('should get suggestions for search drop down and match of mock results for test', async(() => {
console.log('running get Suggestions');
// here we set out HTTP data response stub: put return data in body
setupConnections(backend, {
body: {
suggestions:
["6-minute walk test",
},
status: 200
});
// resolve HTTP call with subscribe and do test in call back.
searchService.getSuggestions('test').subscribe((x) => {
console.log(x);
expect(x).toEqual(['6-minute walk test']);
});
});