Marco Natale
Marco Natale

Reputation: 71

Why isn't my test using the service stub method?

I have this spec:

import {TestBed, ComponentFixture} from '@angular/core/testing';
import { LoginComponent } from './login.component';
import {UserService} from "../services/user.service";
import {HttpModule} from "@angular/http";
import {FormsModule} from "@angular/forms";
import {RouterTestingModule} from "@angular/router/testing";

describe('LoginComponent', () => {

  let component: LoginComponent;
  let service: UserService;
  let fixture: ComponentFixture<LoginComponent>;



  class UserServiceStub {
    userLogin(email: string, password: string) {
      return [email, password];
    }
  }


  beforeEach(() => {

    TestBed.configureTestingModule({
      declarations: [LoginComponent],
      imports: [HttpModule, FormsModule, RouterTestingModule],
      providers: [
        {provide: UserService, useClass: UserServiceStub}
      ]
    });

    service = TestBed.get(UserService);
    fixture = TestBed.createComponent(LoginComponent);
    component = fixture.componentInstance;

  });





  it('should create', () => {
    expect(component).toBeTruthy();
  });

  it('should call the service when the sign in button is clicked', () => {
    component.onLoginButtonClick();
    expect(service.userLogin("pippo", "pluto")).toBe(["pippo", "pluto"]);

  });
});

I can't figure out what is the displayed issue:

TypeError: this.userService.userLogin(...).catch is not a function
    at LoginComponent.onLoginButtonClick (http://0.0.0.0:9882/base/src/test.ts:71519:68)
    at Object.<anonymous> (http://0.0.0.0:9882/base/src/test.ts:71485:19)
    at ZoneDelegate.invoke (http://0.0.0.0:9882/base/src/test.ts:108270:26)
    at ProxyZoneSpec.onInvoke (http://0.0.0.0:9882/base/src/test.ts:103404:39)
    at ZoneDelegate.invoke (http://0.0.0.0:9882/base/src/test.ts:108269:32)
    at Zone.run (http://0.0.0.0:9882/base/src/test.ts:108066:43)
    at Object.<anonymous> (http://0.0.0.0:9882/base/src/test.ts:103119:34)
    at attemptSync (http://0.0.0.0:9882/base/node_modules/jasmine-core/lib/jasmine-core/jasmine.js:1950:24)
    at ZoneQueueRunner.QueueRunner.run (http://0.0.0.0:9882/base/node_modules/jasmine-core/lib/jasmine-core/jasmine.js:1938:9)
    at ZoneQueueRunner.QueueRunner.execute (http://0.0.0.0:9882/base/node_modules/jasmine-core/lib/jasmine-core/jasmine.js:1923:10)
    at ZoneQueueRunner.jasmine.QueueRunner.ZoneQueueRunner.execute (http://0.0.0.0:9882/base/src/test.ts:103149:42)
    at Spec.queueRunnerFactory (http://0.0.0.0:9882/base/node_modules/jasmine-core/lib/jasmine-core/jasmine.js:714:35)
    at Spec.execute (http://0.0.0.0:9882/base/node_modules/jasmine-core/lib/jasmine-core/jasmine.js:371:10)
    at Object.fn (http://0.0.0.0:9882/base/node_modules/jasmine-core/lib/jasmine-core/jasmine.js:2579:37)
    at attemptAsync (http://0.0.0.0:9882/base/node_modules/jasmine-core/lib/jasmine-core/jasmine.js:1980:24)

It looks like the test goes on the real service and not on the UserServiceStub.

Upvotes: 4

Views: 1481

Answers (1)

SethGunnells
SethGunnells

Reputation: 1269

The issue you are observing is that your userLogin method from your real service is returning a Promise while the userLogin method from your stub class is returning an array. Since an array does not have a catch method, it is causing an error. What you are trying to accomplish is this:

import {TestBed, ComponentFixture} from '@angular/core/testing';
import { LoginComponent } from './login.component';
import {UserService} from "../services/user.service";
import {HttpModule} from "@angular/http";
import {FormsModule} from "@angular/forms";
import {RouterTestingModule} from "@angular/router/testing";

describe('LoginComponent', () => {

  let component: LoginComponent;
  let service: UserService;
  let fixture: ComponentFixture<LoginComponent>;
  let userService: UserServiceStub; // NEW



  class UserServiceStub {
    userLogin(email: string, password: string) {
      return Promise.resolve([email, password]); // UPDATED
      // OR: return Observable.of([email, password]);
    }
  }


  beforeEach(() => {
    userService = new UserServiceStub();

    TestBed.configureTestingModule({
      declarations: [LoginComponent],
      imports: [HttpModule, FormsModule, RouterTestingModule],
      providers: [
        {provide: UserService, useValue: userService} // UPDATED
      ]
    });

    service = TestBed.get(UserService);
    fixture = TestBed.createComponent(LoginComponent);
    component = fixture.componentInstance;

  });



  it('should create', () => {
    expect(component).toBeTruthy();
  });

  it('should call the service when the sign in button is clicked', () => {
    spyOn(userService, 'userLogin').and.callThrough(); // NEW
    component.onLoginButtonClick();
    expect(service.userLogin).toHaveBeenCalled(); // UPDATED
  });
});

You can read more about Jasmine Spies here. The gist is that they allow you to check if a method has been called. You can also check things like what it was called with, what it returned, and so on. There are many ways to use them and they are very powerful. I hope this helped!

Upvotes: 2

Related Questions