Saga Marble Tests with RxJS and NestJS

Pierre Chabardes
Tales of Libeo
Published in
2 min readJun 3, 2021

Hello there !

At Libeo, we chose NestJs for our backend. At first, we only used the standard pattern (controller/service/repository/entity) in our codebase, but as it grew, we felt the need to introduce a new pattern with the help of NestJs CQRS module.

In this post, I won’t talk about how we use this CQRS pattern (I might in a future post), but I wanted to show, with (almost) real life examples, how RxJS allow us to add some cool tests to our Sagas.

Some Context

We have our own simple 2FA process (we call it validationCode), and there are 2 steps for a user to get her validation code:

  • One command generates a code for a user and chooses the appropriate channel to send it (for now, only text message or email): GenerateValidationCodeCommand (I know, how very original…)
  • One command that calls the correct 3rd party provider to send the validation code. Also with its own obscure name: SendValidationCodeCommand

And a Saga to tie it all together:

Once a code is generated, we send it to the user. Easy !

This is where the fun begins

Of course, it could not be that simple: we also want to make sure that we don’t spam our users (also, we are paying for those text messages !). Hopefully RxJS has the perfect operator for that: throttleTime

Now how do we test this ? (because testing is important right ?)
With Marble testing of course !

Marble testing allow us to create complex test scenarios. It is fairly easy to write (and read):

  • Each v represents a code being generated, each s is a command to send it, and each dash is an empty timeframe.
  • We feed our saga with a marble diagram of events: -vv-v- 5s -vv-|
    (A burst of 3 events v, then a 5 seconds pause, then 2 more events)
  • We check that the output is what we expected: -s---- 5s -s--|
    (Only the first event v of each burst will result in a command s)

Of course, there is some setup code before that but nothing too fancy.

I don’t think the system works

You may have noticed that our throttling is really dumb for now: If 2 users were to generate a validation code around the same time, the second one would be throttled. With a 5 seconds window, that wouldn’t even be a rare occurence. So we use some RxJS magic to group our events by userId and throttle each group separately !

Now we can add a test case for this scenario :

Now imagine having to write this kind of test scenario without marble testing… But with marble testing, you just write your input as a string of events and check that the output match the expected string of commands !

I think this way of testing is really nice and I hope you learned something from this post !

--

--