We'll be using Jest to run some unit tests in this lesson. Because our app currently relies on external props being passed in and having an array called to dos, the build-in test that comes with create React app will fail. So I'm just going to update this file and add skip to that test so that, when we run our test, we don't get unnecessary errors.
I'm going to start by adding a directory under source. I'm going to call this reducers. Then in that reducers folder, I'm going to add a new file. I'm just going to call that todo.js.
Then I'm going to add another file called todo.spec.js. I'm just going to paste some code into the spec file.
You'll see we're importing reducer from that to do file which is currently empty, so we're going to have to define that. Then I have a simple describe that wraps one test that just verifies that our reducers returns a state object.
I'm going to save this file. If I switch to the terminal and I run this using the RM test, we expect this to fail. We're getting a type error because to do is not defined. So let's open up todo.js and define our reducer.
I'm just going to export a default function. This function's going to take two arguments. It's going to take state and it's going to take an action.
The reducer's job is to take in the existing state and an action, and then return a new state based on the action. So what we'll do for now is we'll just create this as a block. I'm just going to return the state as is because we haven't defined what we want our action to do yet.
I'm going to save this. My spec is going to rerun. This time it's going to fail because I'm returning an undefined value.
To fix that, I'm going to define a constant which I'm going to call a net state. This is going to be my initial state object.
That's going to have a to do as array. We'll just leave that empty for now. Then I'm just going to assign that as the default value for state, so if I receive undefined here, it'll return that initial state and my test will pass.
Now that we have the beginnings of a reducer, let's add some functionality to it. I'm going to jump back over to our spec file. In my describe block under the initial test, I'm going to paste in a second test. I'll get rid of the file so it's a little easier to see this.
This test is just verifying that our reducer can add a to do, so we have a starting state with a to dos array that has three items in it.
Then we have an expected state with a to dos array. This time there's four items in it, so we expect that the action we pass into our reducer is going to add this fourth to do object.
Then we have a result which right now is just an empty object. Then we have an expectation. I'm going to collapse the expected and start state.
Then we just need to define what we want our result to be. Our result is going to be the object that we get back from calling the reducer with our start state, and then an action that's going to add a new to do. Our action is going to be defined in a constant that we'll throw up here.
Each action for a Redux reducer is going to have a certain shape. We're going to have an object that has a type property. The type is how we're going to decide what action to take inside the reducer.
We're just going to call this to do_add. Then our action's going to get a payload. That payload, in this case, is going to hold a to do object.
I'm just going to paste in an object that matches the expected fourth to do in our expected result so we have an ID, a name, and it is complete. Payload is just a property on an object, so it can carry whatever data needs to go with that action in order to get the expected state back out.
Now that I have this, I'm going to save it. We're going to see that our spec is failing, so let's update our reducer so that we can get our test to pass.
Back in todo.js I'm going to add a switch statement. We're going to use the switch statement to take a different action based on the action type that's been passed in, so I'm going to switch on action.type.
In the case where it is to do_add, we're going to take the payload and add it to the existing array. Then our default action is going to be to return the state as is.
Up here, I'm going to start with the return statement. I want to take the existing state, which is an object. I'm going to spread all of its properties.
Then I just want to apply the change that needs to be made, so what I'll do is I'll take to dos and I'll make those equal the existing state.to dos. Then I want to concat my action.payload because I know for a to do add action, my payload is going to be a to do object.
I'm going to save this. Then our test will pass.