Instructor: We've got specs in place
around our comment box
and we are correctly calling our action creator
whenever a user types in a comment and then submits it.
So we've got a reasonable idea
that we're calling our saveComment action creator right here
with the comment that the user entered.
That means the last thing that we need to do
is create a reducer for handling this list of comments
and generating our comments piece of state.
We're also going to test this reducer as we develop it.
So let's scaffold out the reducer
and then we'll write all the specs for it
and then we'll implement the reducer.
So inside of our reducer's folder,
inside of the source directory,
I'm gonna create a new file called comments.js.
So this thing right here is gonna be our reducer.
Now we know that our reducer is almost always
have the same signature.
We're always going to export default a function
that receives piece of state,
and we're going to default it to an array
since it's gonna be a list of comments.
And then we're also going to receive actions in here.
So we'll say that, hey, second argument is our action.
So this is really all we need in here for right now
to get us writing some reasonable specs.
So I'll go ahead and save this file.
And then inside of my test directory,
I'm gonna make a new folder called reducers.
And inside of reducers we'll make,
oops, yes, there we go, comments_test.js.
And so here's where we're gonna put
all of our tests around our reducer.
Now for our reducer, we've only got one action type
floating around our entire application.
So here's what we're gonna test
and this is something that's repeatable
for just about every single reducer we create.
Whenever we test a reducer
we're gonna desk test the default case,
which is we pass in an action that we know
that the reducer is not supposed to work with a respond to.
The purpose of this is to really just test
the initial state of the reducer.
We're gonna make sure that hey,
that array that we just defaulted it to
is never gonna get changed accidentally to something else.
The second thing that we're gonna test,
and again this is true of all reducers,
is we're going to test each possible action
that the reducer cares about.
Now, in this application that we're building,
there's only one action type floating around.
So that means only one test here.
But if we had a application with say
20 different action types,
if our reducer only cared about this one action,
or a very single action type,
we would still only have one test.
So let's do some scaffolding for our test here
for our reducer.
We're going to import, export, excuse me, expect
from up one directory test helper.
Again, we're not going to need to bring in
the render component helper
because we're not rendering any components here.
And then the only other thing we need to import in here
is the reducer itself.
So we'll import commentReducer from
and this is another one of those big walks up the tree.
So we'll go up to test,
up to root, into source, into reducers.
So up, up source reducers comments.
Now, I might have spoken too early when I said
there was only one other thing we had to import here.
I think that we'll also import our action types
and make sure that we're working
with the correct SAVE_COMMENT.
We do wanna make sure
that we are responding correctly to the SAVE_COMMENT.
So we will also import SAVE_COMMENT
from up up source actions types.
Okay, so now we can go ahead
and write our two specs around both cases for this reducer,
the default case and the save comment case.
So we'll describe comments reducer,
again, the top level describes purposes
to give a top level description
of exactly what we're gonna be testing inside of this file.
And then we'll say, it handles action with unknown type.
So in other words, if we give this thing an action
with some just super random type
that isn't really supposed to be responded to
in our application, this thing should at least respond
with an array, with an empty array by default.
The other case we'll wanna handle
is it handles action of type SAVE_COMMENT.
Another more concise way that I like to use
in my personal projects where I've got a reasonable idea
that anyone reading this code
or reading my code in the future will know what's going on.
I'll usually just abbreviate all these different types
into something like, I'll just say SAVE_COMMENT by itself.
So anyone who's looking through here,
if a specific case is failing
or if they want to add a specific action type,
they just put an it.
You can just put an it down
with just the type that we're talking about here
as opposed to saying handles action of type, so and so.
Just a little time saver.
All right, let's go ahead and write the test
for the unknown type first.
So before we write the test, let me ask you,
I'm asking you whoever's listening to this.
If we call our reducer with some just super random action,
maybe even action without a type at all,
what do we expect to happen?
What do we expect to get back?
Take a second.
You can even pause the video,
look at the code we have right now
and just say, hey, if I pass in,
let's say no action whatsoever,
what do I really expect my reducer to return by default?
And if you can answer that question yourself,
I encourage you to, again, pause the video
and try writing this expectation here.
Testing is all about practice, all about practice.
So if you wanna give it a shot, go for it.
Otherwise, we'll start in just a second.
All right, So let's give it a shot.
We'll do expect commentReducer, and we're just gonna say
you know what, we're not gonna pass in any initial state
and we're not gonna pass in any action whatsoever.
I want to test that if this thing gets called
with mysterious arguments, we wanna make sure
that it at least returns an empty array.
So I'm gonna expect commentReducer.
And you know what actually this would be a great time
to go look at some of the further documentation.
So let me pull up another HTML document here.
We've been looking at some of the matchers for chai-jquery,
but in this case, I wanna look at some of the matchers
for just chai js by itself.
So the Chai library,
and we'll talk about the purpose of mocha versus chai.
The purpose of chai is just to provide some very low level,
very common, very default assertions.
And so we can expect
that whatever is returned from our reducer,
we know that we want it to be an array by default.
So I'm gonna say that I expect
if I call our comment reducer with no arguments,
I expect the value to be returned
is gonna be an instance of an array.
So let's give that a shot.
We'll say, expect commentReducer to be instance of array.
So keep in mind here that I'm not expecting
the reducer itself to be an array.
I'm expecting whatever the reducer returns to be an array.
We are invoking it here.
So I know the language here
can be just a little bit misleading.
There's one other approach
that I think we could get away with here.
We could probably also try commentReducer
to equal empty array like so.
And so you'll notice that I'm using eql here
as opposed to the full word E Q U A L.
So this equal right here will do a deep comparison
and it'll say, Okay, if this is an array,
I'm gonna make sure that all the values in this array
are equal to the values in this array right here.
Whereas the E Q U A L, equal, the full word equal
checks to see if the array or whatever is right here
is the absolute identical object on either side.
So equal is, the full length equal is sometimes that we use
a little bit more sparingly.
It's more often used with
when we're comparing strings or numbers.
Anyways, let's go ahead and just give this a shot.
Let's see how far we get.
So I'm gonna save this.
Now, I did just create a new spec file,
which means I need to restart my tests, so I'll do so.
Huh, interesting.
So we got expected undefined to be an instance of array.
But you know what?
Come to think of it,
this is actually very reasonable right now
because right now we are defaulting the array.
We're defaulting state to an array,
but we're not returning state by default.
So let's improve this to return state.
And now sure enough, everything is passing, very good.
So just as a little exploration there,
we were able to use either the result of commentReducer
should be an instance of array
or it should literally be an empty array.
It's really up to you which direction you wanna go.
I would probably stick with this second expectation
down here just because it is specifically asserting
that the array is gonna be empty.
Whereas up here we're asserting that it's just of type array
and it's not necessarily saying that it should be empty.
So I think in my case, I'm gonna stick with this reducer
or excuse me, this assertion right here.
I'm gonna save and we're still passing, very good.
So we now need to handle the case
of it handles action of type SAVE_COMMENT.
So whenever we're handling a reducer test
where we're going to craft an action,
where we'll craft the action ahead of time
and then we'll pass it into the reducer
with some default state,
and then we'll expect that whatever gets returned
from the reducer is the state that we expect.
So we'll first craft our action.
We're gonna have an action of type SAVE_COMMENT
and we'll have a payload of new comment.
So now if I put this into commentReducer,
and remember the first argument to my reducer
is the initial state.
So I'll put in an initial state of empty array.
And then the second is the action.
So if I call my commentReducer with an empty array
and an action of type SAVE_COMMENT
with a payload of new comment,
basically my expectation here is that I should see
this new comment be added into this array.
Because ultimately that's all this app
is really trying to do.
It's trying to create a list of comments,
which are gonna live inside of an array.
Now the knowledge of that is the fact
that I wanted to add it to an array.
Kind of, I only personally know that
because I know how to build this application.
If that wasn't immediately obvious to you, it's no problem.
This is part of the difficulty of testing.
It's kind of, it really requires you
to have a very deep understanding of the software
that you wanna build and the code that you wanna write.
And that's really a positive and a negative.
So I expect to see an array back with this
that has one string in it of new comment.
So in this case, we'll say to eql new comment.
So let's save this.
And okay, so we've got our error now
because we aren't handling this case inside of our reducer.
Let's go ahead and continue inside the next section
where we will finish wiring up the reducer
and then we'll do a little bit of review
of the specs that we just wrote as well.