cartant / rxjs-marbles

An RxJS marble testing library for any test framework
https://cartant.github.io/rxjs-marbles/
MIT License
301 stars 18 forks source link

fakeSchedulers - Testing throttleTime pipes? #75

Closed rbutera closed 3 years ago

rbutera commented 3 years ago

Hello,

I am trying to test a NestJS Saga (not wholly relevant -- just a bit of context here) with the following implementation:

// active-user.saga.ts
  @Saga()
  readonly userWasActive = (
    events$: Observable<any>
  ): Observable<ICommand> => {
    return events$.pipe(
      ofType(UserActiveEvent),
      mergeMap((event: UserActiveEvent) => {
        return of(event.user)
      }),
      filter((user) =>
        this.cooldownService.hasElapsed('activity.cooldown', user.lastLogin)
      ),
      groupBy((user) => user.id),
      mergeMap((group$) =>
        group$.pipe(
          throttleTime(
            10000,
          ),
          mergeMap((user: User) => {
            return of(
              new UpdateUserCommand(user.id, { lastLogin: currentTime() })
            )
          })
        )
      )
    )
  }

As you can see, I am grouping the events by user id and then throttling those individual groups.

The test I have is:

// active-user.saga.spec.ts

    it(
      'prevents multiple command from being output from the same user over 10 seconds',
      fakeSchedulers((advance) => {
        const result: UpdateUserCommand[] = []
        const subject = new Subject()
        effects.userWasActive(subject).subscribe((value: UpdateUserCommand) => {
          console.log('saga was updated with:', value)
          result.push(value)
        })
        subject.next(mockEvent)
        advance(4000)
        subject.next(mockEvent)
        advance(4000)
        subject.next(mockEvent)
        advance(4000)
        subject.next(mockEvent)
        advance(4000)

        expect(result).toHaveLength(2)
      })
    )

Unfortunately this test fails, as result is empty. If I remove throttleTime, then result is no longer empty, and contains 4 items.

Is it possible to test an observable that uses throttleTime using fakeScheduler?

cartant commented 3 years ago

Nope. There's no issue with using throttleTime with fakeSchedulers: https://github.com/cartant/rxjs-marbles/blob/8ea7b795a945a6c92c9df4ed1aa8876d3eb7f526/fixtures/mocha/issues-spec.ts#L43-L63

Your problem is likely that you have something other than a scheduler or a setInterval/setTimeout API call - a Promise maybe? - that's introducing asynchrony.