Testing an Angular service in Jasmine using Subject and localstorage

Viewed 36

I have a login page I need to test, which uses an authentication service. Roughly speaking, when the login button is pressed, at some point this occurs :

  this.userService.$authentification.subscribe((res)=>{
    if(res.success){
      this.router.navigate(['/dashboard']);
    }else{
      console.error(res.error.code)
      this.error=res.error;
    }
  })
  this.userService.authentification(login, pwd);

(this is part of the code I am supposed to test and therefore I should ideally not modify it)

Internally, $authentification is a Subject :

$authentification = new Subject<any>();

which is attached to the service method authentification :

  authentification(login : string, password : string){
    let body = {
      login: login,
      password: password
    }
    this.jwtLocalstorage.remove();
    let post = this.http.post<any>(environment.api + 'user/login/index.php', body, {}).subscribe(response => {
      post.unsubscribe();
      if(response.jwt){
        this.jwtLocalstorage.add(response.jwt, response.data.id);
        this.$authentification.next({
          success:true,
          error: null
        });
      }else{
        this.$authentification.next({
          success:false,
          error: {code:"0X"}
        });
      }
    },response => {
      post.unsubscribe();
      this.$authentification.next({
        success:false,
        error: response.error
      });
    });
  }

The service calls up the authentication API, stores the results in the local storage, and then feeds a confirmation in the Subject object, which will then be used by the login page to decide what to do next.

When testing the login page, what am I supposed to simulate here? Should I mock the service, subject and local storage, or get the service from the component and then mock the subject and local storage? I'm not quite sure how to proceed here.

1 Answers

Unit testing is about testing a unit of code. Everything outside of this unit should be mocked.

So yes, you should mock your service. From there, think about it : since you have mocked the service, why should you mock anything else in it ? A mock has no dependency, so just mock the service and nothing else.

Here is the simplest mock you can make to test your code


const state = new Subject<any>();
serviceMock: any = {
  $authentification: state.asObservable(),
  authentification: jasmine.createSpy()
};

From there, simply inject this mock in your component


component = new MyComponent(serviceMock);

And now, make a meaningful test


it('Should redirect in case of success', (done) => {

  state.pipe(first()).subscribe(() => {
    expect(component.router.navigate)
      .toHaveBeenCalledOnceWith(['/dashboard']);
    done();
  });

  component.yourFunctionToCallToTest();

  state.next({ success: true });
});

Related