Check out a free preview of the full Complete Introduction to React (feat. Redux and React Router) course:
The "Testing Redux" Lesson is part of the full, Complete Introduction to React (feat. Redux and React Router) course featured in this preview video. Here's what you'd learn in this lesson:

Since Redux requires all methods and reducers be functional by nature, unit testing is very easy. Brian writes a few tests for the Store.jsx file. He verifies the initial state is set properly and the state is updated when the setSearchTerm action is called.

Get Unlimited Access Now

Transcript from the "Testing Redux" Lesson

[00:00:00]
>> [MUSIC]

[00:00:03]
>> Brian Holt: Our tests are broken, unfortunately, cuz we've just done a ton of stuff. I really wanna get to universal rendering and web packed chunking. So are we okay if I skip fixing there, I'll show you how to test redux really quick cuz it's super fast, but are we okay if I skip fixing a react tests?

[00:00:20] And then we'll come back to it eventually if there's time at the end, okay.
>> Brian Holt: So go to your app.speck real quick.
>> Brian Holt: This is one of the joys of,
>> Brian Holt: So this is down at the bottom. This is one of the joys of redux is, it's so easy to test because it's functional and anything that's purely functional in nature is just input in, output out, nothing in the middle.

[00:00:50] There's no set up and no tear down, it's just wonderful.
>> Brian Holt: Okay, so we're gonna test Store,
>> Brian Holt: And make a new method here. it('should bootstrap'), so we're just gonna make sure that our it everything gets created very quickly and easily.
>> Brian Holt: And all we're gonna say is delay bring in Store up here.

[00:01:21] I need to bring Store up here as well, so,
>> Brian Holt: const { store, reducer }.
>> Brian Holt: We have to go fix that as well, okay. So rootReducer, rather.
>> Brian Holt: = store, so we're gonna say require('./Store'), okay. Remember, we actually didn't export rootReducer because we don't need it at anywhere else, but we actually do wanna be able to test it.

[00:02:00] So save this, head over to store.jsx, and down here at the bottom, where it says connector and store, just also say, rootReducer as well, right? The actual crux of what we're interested in testing in redux is just the reducers, right, from state A to state B. That's the most important part and the part that's prone to breaking.

[00:02:25] So do that, go back to app spec. And here, let's go actually test that. So we're gonna say const state = rootReducer(undefined). And we’re gonna send in an action type of : ’@@redux/INIT’. So this is the action when redux bootstraps, just FYI, that's the name of the action that it sends.

[00:03:00] And I think they made it look like this cuz you would never name your action this, right? So that's why they did that.
>> Speaker 2: Should Store be lower case on line 32, cuz isn't it referencing-
>> Brian Holt: I mean, it's up to you. This is actually like the note to yourself.

[00:03:19]
>> Speaker 2: Right, okay.
>> Brian Holt: So I called it uppercase cuz it's actually referring to Store.jsx, that's what we're testing here.
>> Brian Holt: Okay, so now we should have a state returned from our reducer, right, because remember, reducer takes in an old state and creates a new state and hands it back to you.

[00:03:39] What I'm interested in seeing is I'm interested to see if expect(state) to deep equal, and we just expected the deep to equal that initial state that we set up, in our case, it's gonna be searchTerm: that, right? Remember, that's what our initial state looked like. So it goes from having nothing to creating this, basically, this initial state.

[00:04:05] That's what our test is asserting presently.
>> Brian Holt: So save that.
>> Speaker 3: Your require, I think, at the top, needs a ../js.
>> Brian Holt: You're right, ../js, thank you.
>> Speaker 3: Mm-hm.
>> Brian Holt: Just this one here.
>> Brian Holt: Okay, so let's come in here to, we'll just cancel my http server for a second and run npm test.

[00:04:42] Just keep in mind, the old tests are definitely broken. We're just caring about Store right now.
>> Brian Holt: So if we look here, our Store is passing, right, the other three are failing.
>> Brian Holt: Any questions about the bootstrap test?
>> Brian Holt: It's really simple, right? That's a two liner and that's what I really, really like about testing redux, and this is like, whereas I say don't test react that much just test the hell out of your redux, right?

[00:05:21] That's the place that like all your app transformations, all your business logic, and all your state transformation. One, it's super easy to test, and two, it's the part of the app that you really need to test that doesn't change from UI to UI. It just changes with whatever new business logic you're introducing, which is far less frequent than UI changes.

[00:05:42] ie, you could have not paid attention previously, and you should definitely be paying attention now.
>> Class: [LAUGH]
>> Brian Holt: So actually, what I'm gonna do here is I'm just gonna say X describe cuz I am sick of hearing that output. [LAUGH]
>> Brian Holt: Okay, so we're gonna do one more test.

[00:06:04] We're gonna make sure that if we pass in a set search term event, that it's gonna correctly set our state. So I'm gonna say, it('should handle setSearchTerm actions'.
>> Brian Holt: Okay, and I'm gonna do something similar, const state = reducer. I'm gonna pass in an initial state of searchTerm, call in some random string, where you can buy whatever you want there.

[00:06:46]
>> Brian Holt: And then another action,
>> Brian Holt: Which is gonna be type: 'setSearchTerm, value: 'correct string', like whatever string you want, just make sure that you're consistent, or else, it's not really testing anything. Okay, so now I have a state back from here, so I'm gonna do an expect(state) to deep equal({,

[00:07:28]
>> Brian Holt: searchTerm: 'correctString'}).
>> Brian Holt: That makes sense, correct space s. As long as this one and this one are the same, so just to recap, this is the initial state they were passing in, right? So we want this search term to be blown away, right? That's the idea here.

[00:08:00] We're sending in a setSearchTerm action, which is going to get dispatched to our reducer, our rootReducer, which is going to then dispatch to our setSearchTerm reducer, right? And then it's going to return this-
>> Speaker 5: Should that be rootReducer then?
>> Brian Holt: Yeah, this needs to be rootReducer. Yep, definitely.

[00:08:23]
>> Brian Holt: Yeah, whatever the name of that function method is. So we're just checking this to make sure that this gets updated correctly.
>> Brian Holt: All right, so let's try and run that. So we're gonna run here, clear, npm test again.
>> Brian Holt: So, notice we're no longer running these tests, but we are running both of these, and they do pass.

[00:08:56] And if you wanted to, you could actually do an npm run cover, if you wanted to see the coverage on store, I don't know, might be interesting, might not be. [LAUGH]
>> Brian Holt: Let's make this smaller.
>> Brian Holt: So, it's saying that you have kind of crappy coverage, which is kind of true.

[00:09:23] But notice Store, we're hitting most of the lines here, right? So, an okay amount.
>> Brian Holt: Okay, any questions about testing redux?
>> Brian Holt: Makes sense?
>> Brian Holt: Looks like Scott T asked, why is this setSearchTerm right here? Well, if you remember in our Store, that's the name of the variable, right, and the variable is set to this.

[00:10:02] So that's why it's setSearchTerm and why it's actually gonna be this, right? Now if I had them be the same thing, then it would be that, right? But that's actually what we're looking for here. [COUGH] It's up to you how you wanna do that.
>> Speaker 6: I have a question.

[00:10:20]
>> Brian Holt: Sure.
>> Speaker 6: Is rootReducer reusable at all? I mean, in its current state, it's not, but could you set something up reusable?
>> Brian Holt: So, the answer is not particularly cuz it's kind of your dispatch function. Definitely the reduceSearchTerm, that could be reused somewhere else. So one of the caveats is you only have one redux store on any given page.

[00:10:43] It's actually a hard requirement of redux is that, that's the only store on the page. So this one's reusable, but typically, your rootReducer is not gonna be reusable. And I'll say it, which I had mentioned previously, you actually really don't usually make your own rootReducers, there's a redux function called compose reducers.

[00:11:01] I think that's what it's called, might even just be compose. I don't recall. Anyway, there's a function that basically you pass in a bunch of reducers to, and then it just does your dispatch for you. It's just a little bit lazier way to get your rootReducer created for you.

[00:11:21] I kinda like being explicit, but up to you.
>> Speaker 6: So if you have more than one dispatch, you wouldn't create a new rootReducer, you would get a new case, right?
>> Brian Holt: Exactly.
>> Speaker 6: Okay.
>> Brian Holt: Yep, precisely.
>> Brian Holt: Yep, cuz you're gonna have a case for every action you have.

[00:11:44]
>> Speaker 7: Can you talk about testing a redux connected component?
>> Brian Holt: Yeah, it's a lot more complicated, which is actually what I would show you in the other section, how to test the integration between the two. But remember when I was saying that we have shallow, we have mount, and we have static, we have to resort to using static because it gets complicated enough.

[00:12:08]
>> Brian Holt: Yeah, because redux has to be able to bootstrap a full instance of react and be able to talk to all the individual components. But honestly, I don't think there's any really special cases here. Basically, what you do is you create the store, right, that you provide to the provider and then you actually run actions against the store, right?

[00:12:28] That's the basic gist of what goes on. Cuz this store, did I bring that in? Sorry, I'm in an app here.
>> Brian Holt: I don't actually need store in here, right, anyway. So the store method has something called dispatch as well. So you can actually call a dispatch directly in the store, and that's actually how you're gonna dispatch all these action, is just directly call dispatch on the store.

[00:12:58] So maybe towards the end, I'll fix one of the tests, so you can see it, but I definitely wanna get to universal rendering first and as well as web packed chunking cuz I think that's the most compelling part. And I already showed you how to do this, basically, once, and the next step is not terribly difficult to arrive to.

[00:13:15] So if we don't get to it, we'll be okay, so says I. [LAUGH]