Search code examples
angular6angular-test

how to unit test subscription to a BehaviourSubject in angular


I have a UserManagementService which exposes an Observable of a BehaviourSubject.

this.userSignInState$ = this.signInStateSubject.asObservable();

I subscribe to userSignInState in a nav component.

constructor(public userManagementService: UserManagementService, private fb:FormBuilder, private helper:HelperService) {
    this.userSignInStateSubscription = this.userManagementService.userSignInState$.subscribe(
          (result:Result)=> {
            console.log("In nav - result from user signin state ",result);
            let subscribed:UserSigninState = result.additionalInfo;
            console.log("new user signin state received:", subscribed);
            this.userLoggedIn = subscribed.isSignedIn;
            if(subscribed.isSignedIn && subscribed['additional-info'] !== ''){
              this.profile = JSON.parse(subscribed['additional-info']) as UserProfileAPI
            }
            if(!subscribed.isSignedIn && subscribed['additional-info'] !== ''){
            //  let error:ServerResponseAPI = JSON.parse(subscribed['additional-info']) as ServerResponseAPI
              //let errorMessage:string = this.helper.userFriendlyErrorMessage(error);
              this.navEvent.emit(new NavContext(subscribed['additional-info']));
            }
          },
        (error:ServerResponseAPI)=>{
            console.log("got error from the Observable: ",error);

           let errorMessage:string = this.helper.userFriendlyErrorMessage(error);
           this.navEvent.emit(new NavContext(errorMessage));
    //       this.userloggedIn =false;
      },
      ()=>{ //observable complete
        console.log("observable completed")
        //this.userloggedIn =false;
      });
  }

I want to unit test nav. The spec should test that the component subscribes to userSignInState$ and handles Result correctly. How do I do this? As this is a unit test, I don't want to use the real UserManagementService

I wrote the following spec

fit('should subscribe to user sign in state observable',()=>{
    let userManagementService = TestBed.get(UserManagementService);
    let navComponent:NavComponentComponent = component;
    console.log('component is ',navComponent);
    navComponent.userLoggedIn = false;
    let dummyUserProfile = new UserProfileAPI(new User('fn','ln','test@test.com'));
    userManagementService.signInStateSubject.next(new Result('success',(new UserSigninState(true,JSON.stringify(dummyUserProfile ))).toString));
    expect(navComponent.userLoggedIn).toBe(true)
  });

but I got error Expected undefined to be true.

I don't understand why userLoggedIn is undefined. I have declared it in the nav class

export class NavComponentComponent implements OnInit  {

  userLoggedIn:boolean;
...
}

I set it in ngOnInit.

ngOnInit(){

    this.userLoggedIn = false;
  ...
}

I also moved the subscription logic to ngOnInit but that doesn't work either and gives the same result.


Solution

  • The issue was with the way I was creating Result. I should have not used .toString with userSignInState. From another question I posted in SO, "reference to .toString without () is just a reference to that function, so if you log that you get the code for that function." Also, "toString() will not work as userSignInState doesn't have a meanigful string representation and is defaulting to [object Object]". I removed toString and the code worked as additional-info is of type any