Attempting to unit test an angular2 app using jasmine, but when I try to inject service, the spies don't pick up on injected calls.
Test suite:
import { TestBed, inject, tick, fakeAsync, ComponentFixture } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { RouterTestingModule } from '@angular/router/testing';
import { RoomComponent } from './room.component';
import { Room } from './room';
import { RoomService } from './room.service';
import { MockRoomService } from '../mock/mock.room.service';
import { BaseRequestOptions, Http, ConnectionBackend, Response, ResponseOptions } from '@angular/http';
import { MockBackend } from '@angular/http/testing';
...
beforeEach(fakeAsync(() => {
TestBed.configureTestingModule({
  declarations: [
    RoomComponent
  ],
  providers: [
    {
      provide: Http, useFactory: (backend: ConnectionBackend, defaultOptions: BaseRequestOptions) => {
        return new Http(backend, defaultOptions);
      },
      deps: [MockBackend, BaseRequestOptions]
    },
    RoomService,
    {provide: MockBackend, useClass: MockBackend},
    {provide: BaseRequestOptions, useClass: BaseRequestOptions}
  ],
  imports: [
    RouterTestingModule
  ]
})
.overrideComponent(RoomComponent, {
  set: {
    providers: [{provide: RoomService, useClass: MockRoomService}]
  }
})
...
it('should have rooms after getRooms', inject([RoomService], fakeAsync((mockRoomService: MockRoomService) => {
  let spy = spyOn(mockRoomService, 'getRooms').and.callThrough();
  fixture.detectChanges();
  tick();
  expect(spy).toHaveBeenCalled(); //Does not return true
  expect(component.rooms).toBeDefined();
})));
Tested that spies themselves work (using mock service and a direct call) which they do, and that the component calls the mock service rather than the real one, returning the test data:
LOG: 'ngInitified'
PhantomJS 2.1.1 (Windows 7 0.0.0): Executed 6 of 21 (skipped 3) SUCCESS (0 secs / 1.156 secs)
LOG: 'method reached'
PhantomJS 2.1.1 (Windows 7 0.0.0): Executed 6 of 21 (skipped 3) SUCCESS (0 secs / 1.156 secs)
LOG: 'mock service reached'
PhantomJS 2.1.1 (Windows 7 0.0.0): Executed 6 of 21 (skipped 3) SUCCESS (0 secs / 1.156 secs)
LOG: [Object{_id: '12', gitrepo: 'repository', channel: 'slack channel'}, Object{_id: '42', gitrepo: 'newrepo', channel: 'dev'}]
PhantomJS 2.1.1 (Windows 7 0.0.0): Executed 6 of 21 (skipped 3) SUCCESS (0 secs / 1.156 secs)
PhantomJS 2.1.1 (Windows 7 0.0.0) Component: Room should have rooms after getRooms FAILED
    Expected spy getRooms to have been called.
Have tried injecting MockRoomService straight. Have tried putting the spy on a RoomService object instead of a mock object. Neither returns that the spy was called.
Mock Service:
import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import { Room } from '../room/room';
@Injectable()
export class MockRoomService {
    testData: Room[] = [{"_id":"12","gitrepo": "repository", "channel": "slack channel"}, {"_id":"42","gitrepo": "newrepo", "channel": "dev"}];
    constructor(http: Http) { }
    getRooms(): Promise<Room[]> {
        console.log("mock service reached");
        return new Promise((resolve, reject) => {
            resolve(this.testData);
        });
    }
...
Real Service:
import { Room } from './room';
import { Http, Headers, RequestOptions } from '@angular/http';
import 'rxjs/add/operator/toPromise';
import { Injectable } from '@angular/core';
@Injectable()
export class RoomService {
    constructor (private http: Http) {}
    getRooms(): Promise<Room[]> {
        console.log("real service reached");
        return this.http.get('api/rooms/get')
        .toPromise()
        .then(res => res.json() as Room[]);
    }
...
Component:
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { Room } from './room';
import { RoomService } from './room.service';
@Component({
  selector: 'app-room',
  templateUrl: './room.component.html',
  styleUrls: ['./room.component.css'],
  providers: [RoomService]
})
export class RoomComponent implements OnInit {
  title = 'Repos and Channels';
  rooms: Room[] = [];
  constructor(
    private roomService: RoomService,
    private router: Router,
    ) {}
  ngOnInit() {
    console.log("ngInitified");
    this.getRooms();
  }
  getRooms() {
    console.log("method reached!");
    this.roomService.getRooms()
      .then(room => { this.rooms = room;
        console.log(this.rooms); }
    );
  }
...
Help?
You're getting wrong instance of RoomService provider.
it('should have rooms after getRooms', inject([RoomService], fakeAsync((mockRoomService: MockRoomService) => {
  let componentMockRoomService = fixture.debugElement.injector.get(RoomService);
  console.log(mockRoomService instanceof RoomService);         // true
  console.log(componentMockRoomService instanceof RoomService);// false
mockRoomService is instance from root provider whereas you need to test class  corresponding your component
so here's your test
let componentMockRoomService = fixture.debugElement.injector.get(RoomService);
let spy = spyOn(componentMockRoomService, 'getRooms').and.callThrough();
Plunker Example
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With