KidA2001
KidA2001

Reputation: 195

Clarification on this Jasmine Error: this.http.get is not a function clarification

I keep running into this error when I try unit testing any of my functions that use a service in my component class. Here is a part of my function.

loadUser() {
this.httpService.getData(AppConfig.URL_UserById + "?UserID=" + this.userId)
  .catch((error: Response | any) => {
    this.showAlertWindow(this.exceptionMessage);
    console.error(error.message || error);
    return Observable.throw(error.message || error);
  })

This part retrieves the data from a url and throws an error if there is a problem. getData is a service that makes a get request .I am just trying to test if the method showAlertWindow is being called. Now I am pretty sure my test code is correct but I have to be missing something to be receiving this error. I am guessing that jasmine does not know what to do with the line this.httpService.getData(...) Thank you.

Test:

  fit('should have getUsers() call showAlertWindow', () => {

 let window = spyOn(userComponent, 'showAlertWindow');

 userComponent.loadUser(); //Fails here

 expect(window).toHaveBeenCalled();

})

Full Error:

    Error: Cannot call Promise.then from within a sync test.
Error: Cannot call Promise.then from within a sync test.
    at SyncTestZoneSpec.webpackJsonp../node_modules/zone.js/dist/zone-testing.js.SyncTestZoneSpec.onScheduleTask (http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone-testing.js:365:1)
    at ZoneDelegate.webpackJsonp../node_modules/zone.js/dist/zone.js.ZoneDelegate.scheduleTask (http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone.js:401:1)
    at Zone.webpackJsonp../node_modules/zone.js/dist/zone.js.Zone.scheduleTask (http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone.js:232:1)
    at Zone.webpackJsonp../node_modules/zone.js/dist/zone.js.Zone.scheduleMicroTask (http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone.js:252:1)
    at scheduleResolveOrReject (http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone.js:862:1)
    at ZoneAwarePromise.then (http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone.js:962:1)
    at ApplicationInitStatus.webpackJsonp../node_modules/@angular/core/esm5/core.js.ApplicationInitStatus.runInitializers (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/esm5/core.js:3580:1)
    at TestBed.webpackJsonp../node_modules/@angular/core/esm5/testing.js.TestBed._initIfNeeded (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/esm5/testing.js:1011:1)
    at TestBed.webpackJsonp../node_modules/@angular/core/esm5/testing.js.TestBed.get (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/esm5/testing.js:1050:1)
    at Function.webpackJsonp../node_modules/@angular/core/esm5/testing.js.TestBed.get (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/esm5/testing.js:834:1)

If somebody can give me some insight on the meaning behind this error, that would be great. Thanks.

Test config:

import { HttpService } from '../../services/http.service';
import { TestBed, async, inject, fakeAsync, ComponentFixture } from "@angular/core/testing";
import { UserComponent } from './user.component';
import { Observable } from 'rxjs';


    fdescribe('User Component', () => {
    let httpService: HttpService;
    let userComponent: UserComponent

beforeEach(async() => {
    TestBed.configureTestingModule({
      declarations: [
        UserComponent, 
      ],
 providers: [
  HttpService,
 ],
 }).compileComponents();
  });
   beforeEach(() => {
 userComponent = fixture.componentInstance;
 httpService = TestBed.get(HttpService);

 fit('should have getUsers() call showAlertWindow', () => {

     let window = spyOn(userComponent, 'showAlertWindow');

     userComponent.loadUser();

     expect(window).toHaveBeenCalled();


   })

Edit: There are two possible solutions. I solved the error by spying on my service and returning an observable. spyOn(httpService, 'getData).and.returnValue(Observable.of('test')); Or JanRecker's solution, which is more practical.

Upvotes: 3

Views: 5167

Answers (1)

JanRecker
JanRecker

Reputation: 1847

Did you mock your HttpService ?

If you instantiated your service in the UnitTests, than it will try to process this method. I assume, that in your HttpService you use the Angular HTTPClient Service (i think so because of the error "this.http.get")

Now, you instantiated your Service, but not its dependancies. And, in the UnitTests, you have to instantiate everything by hand. Therefore in your tests, there is no Angular "http" service up and running.

I have the habit to mock EVERYTHING away, that´s not my component/service under test. So in your case i would do something like

 TestBed.configureTestingModule({
    declarations: [YourComponentUnderTest],
    providers: [
        {provide: YourHttpService, useClass: MockYourHttpService} 
    ]
});
let httpService = TestBed.get(YourHttpService);

MockYourHttpService would be a skeleton that looks like the original service, but without fancy implementations. Now you can mock that service as you like

spyOn(httpService, 'getData').and.returnValue(yourMockedData)

Alternatively you could import the HttpClientTestingModule, and mock the "this.http.get" call, but then your component Unit Test will implicitly test parts of your httpService.

warm regards

Upvotes: 6

Related Questions