如何测试依赖于另一个的 Observable 并在订阅之间断言

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

我正在为 AuthenticationService 编写 jasmine 单元测试。我需要测试注销方法是否清除了用户身份验证。为此,我需要:

  1. 通过 authService.login()
  2. 进行 http 调用
  3. 断言用户已通过身份验证
  4. 通过 authService.logout()
  5. 进行 http 调用
  6. 断言用户不再经过身份验证

    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);
    }));
    

正如您在下面看到的,httpMock 根本不喜欢这样。我觉得在这种情况下我需要以某种方式使用 flatMap,但也无法使其正常工作。有什么想法吗?

// 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();
        }
      );
  });
});