Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can't spy on injected services' method in angular 4

I am trying to spy and intercept a method of service I use in the component I am trying to unit test:

This is the component I am trying to test:

export class SearchModuleCheckCardListComponent implements OnInit {
    httpError: boolean = false;


  constructor(private searchModuleService: SearchModuleService) {
    console.log("Constructor");
  }

  ngOnInit() {
    this.fetchSearchModule();
  }



  /**
   * Get all search modules from the back end service
   */
  fetchSearchModule() {
    console.log("FetchSearchModule");
    this.searchModuleService.fetchSearchModules().subscribe(searchModules => 
    {
      //Most code abstracted out for simplicity
      this.httpError = false;
    }, err => {
      this.httpError = true;
    })
  }

Basically what I am trying to test is that the property httpError is set , this is what my spec file looks like : (again stripped out irrelevant code)

describe('SearchModuleCheckCardListComponent', () => {
  let component: SearchModuleCheckCardListComponent;
  let fixture: ComponentFixture<SearchModuleCheckCardListComponent>;
  let searchModuleService: SearchModuleServiceStub;



  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [
                      SearchModuleCheckCardListComponent,
                    ],
      providers:    [
                      { provide: SearchModuleService, useClass: SearchModuleServiceStub },
                    ]
    })
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(SearchModuleCheckCardListComponent);
    component = fixture.componentInstance;
    searchModuleService = fixture.debugElement.injector.get(SearchModuleService);
    fixture.detectChanges();
  });

it('should set httpError on error', () => {
    spyOn(searchModuleService, 'fetchSearchModules').and.returnValue(Observable.throw('error'));

    //'Trying to test:'expect(component.httpError).toBeTruthy();

    //This fails  inspite of fetchSearchModules being called in the stub
    expect(searchModuleService.fetchSearchModules).toHaveBeenCalled();
  })
}); 

This is what searchModuleServiceStub looks like:

export class SearchModuleServiceStub {


  constructor() {}


  fetchSearchModules(): Observable<SearchModule[]> {
    console.log('fetchSearchModules Called');
    return Observable.of(SEARCH_MODULES);
  }
}

Now the console does log out 'fetchSearchModules Called' when I run the test, but the spy still doesn't seem to intercept the function call

like image 319
Snedden27 Avatar asked Oct 19 '25 06:10

Snedden27


1 Answers

This is because the ngOnInit() life-cycle hook is fired before you create your spy. Therefore the function has been called without the spy knowing about it.

You have two options:

1) Re-fire ngOninit() in your test after your spy creation.
2) Create your spy before you call TestBed.createComponent() in your beforeEach()

like image 71
James Avatar answered Oct 21 '25 19:10

James