Unit Test Your ngrx/effects in Angular

Netanel Basal
Netanel Basal
Published in
3 min readApr 25, 2017

--

This post assumes that you at least have some working knowledge of Angular, Jasmine, and @ngrx/effects.

If you have no prior knowledge on the subject, you can read my previous articles and then come back.

Let’s start with a simple example that we can test. We’ll create a basic redux flow that will fetch blog posts from the server.

Build the Posts Reducer —

Build the Posts Action Creators —

Now let’s create the service that will be responsible for fetching the posts from the server.

Build the Posts Service —

Build the Posts Effects —

We need to listen to GET_POSTS action, then call our service and based on the response status to do the following thing:

  • If the response is successful, dispatch GET_POSTS_SUCCESS action with the result.
  • If the request fails, dispatch GET_POSTS_FAIL action with the error.

These are the two cases we need to test

Let’s create the test and explain each part.

TestBed creates an Angular testing module — an @NgModule class—that you configure with the configureTestingModule method to produce the module environment for the class you want to test.

The configureTestingModule method takes an @NgModule-like metadata object. The metadata object can have most of the properties of a normal Angular module.

We need to import the EffectsTestingModule from @ngrx/effects. We also need two providers:

  1. The original PostsEffects .
  2. A mock of our PostsService.get() method.

One of the reasons we want to mock the service get() method is because we do not want to make an HTTP request. In addition to that, In this case, we do not care about the method implementation; we care about the result.

Let’s stop for a second to explain this piece.

jasmine.createSpyObj is used to create a mock that will spy on one or more methods. It returns an object that has a property for each string that is a spy.

What we are saying here is, Hey Angular when you need the PostsService, please provide this mock.

Next, we can get a reference to the providers with the help of the TestBed.get(provider) method.

EffectsRunner is provided by the EffectsTestingModule .

Now we can write our first case.

postsService.get() is a jasmine spy, therefore we can control the return value. In this case, we are returning mock data.

Next, we are calling the queue() method that her job is to queue up actions.

The last thing we need to do is to subscribe to the postEffects.get$ observable and check if the result is the same as our mock data.

Now, let’s test the second part.

The same process as before, smooth and clean.

Let’s finish with a more advanced case, add debounceTime to our effect.

debounceTime discard emitted values that take less than the specified time between output.

We need to control time

Luckily, Angular provides a function that does just that — fakeAsync.

We can “control” time with the tick() function. Calling tick() simulates the passage of time until all pending asynchronous activities finish.

When 400 milliseconds have not yet passed, the result should be null. Otherwise, the result should be what returns from the getPostsFail('error') function.

The final code.

Follow me on Medium or Twitter to read more about Angular, Vue and JS!

--

--

A FrontEnd Tech Lead, blogger, and open source maintainer. The founder of ngneat, husband and father.