How to test an Observable that depends on another and assert between subscriptions

I am writing jasmine unit tests for an AuthenticationService. I need to test that the logout method clears the user authentication. In doing so, I require to:

  1. make an http call through authService.login()
  2. assert that the user is authenticated
  3. make an http call through authService.logout()
  4. assert that the user is no longer authenticated

    describe('logout', () => {
    it('should clear user authentication', fakeAsync(() => {
      authenticationService.login(loginContext)
        .subscribe(() => {
          expect(authenticationService.isAuthenticated()).toBe(true);
    
          authenticationService.logout()
            .subscribe(() => {
              expect(authenticationService.isAuthenticated()).toBe(false);
              expect(authenticationService.credentials).toBeNull();
              expect(sessionStorage.getItem(credentialsKey)).toBeNull();
              expect(localStorage.getItem(credentialsKey)).toBeNull();
            });
      });
    
      const logoutRequest = httpMock.expectOne(`${environment.apiSettings.serviceUrl}${logoutApi}`);
      expect(logoutRequest.request.method).toEqual('POST');
      logoutRequest.flush(true);
    }));
    

As you can see below, httpMock doesn't like this at all. I have the feeling that I need to somehow use flatMap in this circumstance, but haven't been able to get that working either. Any ideas?

enter image description here enter image description here

1 answer

  • answered 2018-03-14 01:34 th3n3wguy

    // Your code:
    /* describe('logout', () => {
    it('should clear user authentication', fakeAsync(() => {
      authenticationService.login(loginContext)
        .subscribe(() => {
          expect(authenticationService.isAuthenticated()).toBe(true);
    
          authenticationService.logout()
            .subscribe(() => {
              expect(authenticationService.isAuthenticated()).toBe(false);
              expect(authenticationService.credentials).toBeNull();
              expect(sessionStorage.getItem(credentialsKey)).toBeNull();
              expect(localStorage.getItem(credentialsKey)).toBeNull();
            });
      });
    
      const logoutRequest = httpMock.expectOne(`${environment.apiSettings.serviceUrl}${logoutApi}`);
      expect(logoutRequest.request.method).toEqual('POST');
      logoutRequest.flush(true);
    })); */
    
    // Updated code:
    import { tap, mergeMap } from 'rxjs/operators';
    
    describe('logout', () => {
      it('should clear the user authentication', (doneCallback) => {
        authenticationService.login(loginContext)
          .pipe(
            tap(() => expect(authenticationService.isAuthenticated()).toEqual(true)),
            mergeMap(() => authenticationService.logout())
          )
          .subscribe(
            () => {
              expect(authenticationService.isAuthenticated()).toEqual(false);
              expect(authenticationService.credentials).toBeNull();
              expect(sessionStorage.getItem(credentialsKey)).toBeNull();
              expect(localStorage.getItem(credentialsKey)).toBeNull();
              
              // Execute the callback to let Jasmine know that the test is finished.
              doneCallback();
            },
            (err) => {
              // Tell Jasmine that we don't ever expect that this error value will ever be defined for this test, because that means that an error was thrown somewhere in the flow and it didn't work for us.
              expect(err).toBeUndefined();
              
              // Execute the callback to let Jasmine know that the test is finished.
              doneCallback();
            }
          );
      });
    });