One of the primary advantages of using Redux is that reducers are incredibly easy to test. By nature, they have a clearly defined contract of inputs and outputs. Because they are stateless, they require very little instrumentation to test in isolation.
In this lesson, we are going to learn how to test our reducers by kicking things off by tackling our categories reducer first. We'll step into our category spec, and we're going to import the categories reducer, as well as the get categories action constant.
Then we'll start with our initial describe block. Within that, we are going to create one more describe block that defines we are testing the categories reducer. Then from here, let's define a constant of initial state.
We're going to put two category items in here. We'll go with development, and we'll do one more with a name of design. Now that we have this initial state in place, let's go ahead and write our first test. The first thing we want to assert is that our reducer should return an empty array for state by default.
We are going to capture the result of calling categories with an undefined state, and a completely nonsensical action type that it will not recognize, payload of just an empty an object. What we can expect here is that we're just going to get an empty array.
We expect the result to equal an empty array. Let's step into the terminal. We will run NPM test. We are off to a good start. Let's write another test. Let's assert that we should return initial state with an unknown action.
We're going to capture the result of calling categories with the initial state, and we're going to do an action type of something that it will not recognize, and a payload of just an empty object. Now we can expect the result to equal, or rather to be, the initial state.
Back into the terminal, let's run our test again. We are two for two. Now what we want to test is that we get the correct payload when we send in an action type that it recognizes, in this case, get categories.
We'll capture the output one more time of calling categories. Result equals categories. We'll send in initial state of undefined, type of get categories, and a payload of initial state. Now, because we're passing in an action type that it will recognize with a payload, we expect the result to equal the payload that we sent in. In this case, it is initial state.
Let's run our test again. We're three for three. Let's just cap this off with some semicolons, and let's move on to our bookmarks reducer. It's a little bit more involved, so the tests are going to get slightly more interesting.
The first thing we need to do is import our bookmarks reducer, as well as the action constants that we need to test our reducer. In this case, get bookmarks, create bookmark, update bookmark, and delete bookmark.
Now that we have these imported, let's start with our initial describe block, where we're letting the world know that we're testing bookmarks. Then from here, let's create an initial state constant of two bookmarks.
We'll go with an ID of zero. We'll give it a title of Angular JS. We'll create one more bookmark item. We'll give this a title of egghead.io. Let's go ahead and write our first test, just to make sure that we've spun up everything correctly.
It should return an empty array for state by default. We'll capture the output of calling our bookmarks reducer by giving it an input of an undefined initial state, and a type of random, which it will not recognize, and a payload of an empty object.
We're just testing that, indeed, we get the appropriate initial state, which in this case, is just an empty array. Let's run our test. It passed. There's a few more tests we could do around initializing the reducer, but let's move on, and write a test to verify that we can create a bookmark, and that our reducer handles that properly.
It should return state with added bookmark on create bookmark action. What we're going to do here is we're first going to define our new bookmark. This will just be an object with an ID of two. We'll give it a title of a list apart.
Then we can also define the next state collection, which is just going to be the concatenation of our initial state with the new bookmark. From here, let's capture the result of calling bookmarks. We'll go bookmarks, and we'll give it an initial state.
Then we'll give it an action item of type create bookmark, and a payload of new bookmark. Based on this input, we can assert that our output is going to be next state. Expect result to equal next state. Let's test it out. That test also passed.
Let's go ahead and test the ability to update an existing bookmark within our collection. It should return state with updated object on update bookmark action. What we're going to do is define an updated bookmark.
We'll give it a new updated title, Angular JS updated. Then let's capture the result. Bookmarks, pass in initial state. We'll do an action type of update bookmark, and we'll pass in the updated bookmark as the payload.
Then from here, we can assert that the first item in our result, the title of that object was the same as the title of our updated bookmark. Let's test this out. That passed as well. Let's write one more test to test our ability to delete a bookmark from the bookmarks collection.
It should return state without deleted object on delete bookmark action. What we're going to do here is we're going to define the bookmark that we want to delete. We'll go with an ID of zero, title Angular JS. We didn't really need to put a title, but it just makes it a little easier to read.
We can capture the result, so bookmarks with the initial state. Then we're going to give it an action type of delete bookmark, and a payload of deleted bookmark. Now just need to assert that deleted bookmark is not in the result, so not to contain deleted bookmark. Let's go ahead and run this. That test passed as well.
Let's do a quick review. We imported our reducer and our action constants so that we could call our reducer. We created an initial state, and from there, we just simply captured the result of calling the reducer, and then we wrote some simple assertions to make sure that what we got in the result is what we expected.
This is how you test reducers in an Angular application.