Majesty
Majesty

Reputation: 1919

RxJS: why does subscribing makes no difference

Consider the following service example

export class AuthService {
  private observableCache: { [key: string]: Observable<boolean> } = {};
  private resourceCache: { [key: string]: boolean } = {};

  constructor(private userService: UserService) { }

  isGranted(resource): Observable<boolean> {
    if (this.resourceCache[resource]) {
      return of(this.resourceCache[resource]);
    }

    if (this.observableCache[role]) {
      return this.observableCache[role];
    }

    this.observableCache[resource] = this.userService
        .getCurrentUser()
        .pipe(map((user: User) => user.canAccess(resource)))
        .pipe(share());

    return this.observableCache[resource];
  }
}

In this service I'm checking if user is allowed to review specific resource.

And here is how I'm trying to test it

describe('AuthService', () => {
  let service: AuthService;
  let userService: any;

  beforeEach(() => {
    userService = jasmine.createSpyObj('UserService', ['getCurrentUser']);
    service = new AuthGuardService(userService);
  });

  describe('isGranted', () => {
    const user: User = {id: 123};

    beforeEach(() => {
      userService.getCurrentUser.and.returnValue(
        hot('-^u', { u: user })
      );
    });

    it('should prove response being cached', () => {
      service.isGranted('dashboard').subscribe();
      service.isGranted('dashboard').subscribe();

      expect(userService.getCurrentUser).toHaveBeenCalledTimes(1);
    });
  });
});

The aim of the test is to check that resource cache works. But what I notice, is that if I replace the following snippet

  service.isGranted('dashboard').subscribe();
  service.isGranted('dashboard').subscribe();

With simple

  service.isGranted('dashboard');
  service.isGranted('dashboard');

The test still works, I'm new to RxJS and marble testing, but as far as I know, Observable should not work until subscribed.

The question - why does it works both ways?

Upvotes: 0

Views: 166

Answers (1)

Jacopo Lanzoni
Jacopo Lanzoni

Reputation: 1316

The code the test is working with is asynchronous, try running it using fakeAsync and tick

it('should prove response being cached', fakeAsync(() => {
  service.isGranted('dashboard').subscribe();
  service.isGranted('dashboard').subscribe();
  tick();
  expect(userService.getCurrentUser).toHaveBeenCalledTimes(1);
}));

Look at https://angular.io/guide/testing#component-with-async-service for more information.

Upvotes: 1

Related Questions