23

I have a spec code to test like this

 it('login test', () => {

      const fixture = TestBed.createComponent(component);
      fixture.detectChanges();
      let authService = fixture.debugElement.injector.get(Auth);
      spyOn(authService, 'login').and.returnValue('');

      const elements = fixture.nativeElement;
      fixture.componentInstance.login();
      expect(authService.login).toHaveBeenCalled();
    });

and the implementation code like this

login() {

    this.auth.login(this.username, this.password).subscribe(() => {

      }
    });
  }

it gives error:

this.auth.login(...).subscribe is not a function

Why does this error happen?

3 Answers 3

39

You need to return something with a subscribe method, as the component calls subscribe directly from login. A string does not. You could just return an object with a subscribe function and it should work

and.returnValue({ subscribe: () => {} });

Or if you want to pass a real observable, you could

and.returnValue(Observable.of('some value'));

You might need to import rxjs/add/observable/of

Sign up to request clarification or add additional context in comments.

2 Comments

For the first option, is there any way of returning a value? Something like this for example : and.returnValue({ subscribe: () => { count: 1000 } });
@abyrne85 That's straight javascript. () => { count: 1000 } sees the curly braces and thinks that's the body of the inline arrow function. But you as the developer know that's for the object you want to return. You need to tell it the same thing. So what you want is () => ({ count: 1000 })--or simply, surround the object in parenthesis. You can also specify it longer by doing something like () => { return { count: 1000 }; } but now that you know the shorter way there's no need for that.
7

On rxjs v6 you should use of instead of Observable.of or Observable.from e.g

const loginService: any = {
    getUser: () => of(['Adam West']),
};

and import

import { of } from 'rxjs';

Comments

6

Change your spy for the 'login' method on your authService to return an observable instead of a value. You'll need to import:

import 'rxjs/add/observable/from';
import {Observable} from 'rxjs/Observable';

Setup your spy:

const loginResult = '';
const spy = spyOn(authService, 'login').and.callFake(() => {
    return Observable.from([loginResult]);
})

Call login:

fixture.componentInstance.login();

Assert:

expect(spy).toHaveBeenCalled();

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.