Intermediate React, v2 API Mocks
This course has been updated! We now recommend you take the Intermediate React, v5 course.
Transcript from the "API Mocks" Lesson
>> Brian Holt: Now we wanna write some tests for search params. But we have a bit of a problem here, iIt's that search params makes Ajax calls. And you don't wanna sit around in your test waiting for Ajax calls to complete, nor do you wanna hammer your API every time you run the tests, right?
[00:00:17] So what do we do about that? Well one thing, I actually have already written a mock for this, so we could use the mocks, right? But we're not gonna do that. We're actually going to write a manual mock ourselves just to show you how that works.
>> Brian Holt: So inside of not the source directory,
>> Brian Holt: Inside of the top level directory here, I'm gonna make another folder. So another folder here and we're gonna call this __mocks__, with an s, okay? Inside of __mocks__, we're gonna create another folder called frontendmasters,
>> Brian Holt: Which it is going to represent that it's at frontendmasters/pet. So inside of frontendmasters we gonna make another file called pet.
[00:01:10] So it is significant what it is called, right? If I wanted to mock Axios for an example, I would make a folder inside of __mocks__ called Axios, right? Not a folder but a file.
>> Brian Holt: So this is important that this is called pet.
>> Brian Holt: So this is gonna be run inside of node.
[00:01:32] So I can use import [ readFileSync ] from 'fs' which is a node core library. I'm going to import path from 'path', and I'm going to import [ act ] from 'react-testing-library'. So path again comes from the node itself as well. And then act comes from the React test renderer.
[00:02:03] It's how it actually keeps track of when it's supposed to rerender. So you actually have to use this act thing, we'll see that in just a second. And then here we're just gonna make some mock data. So const breeds equals, I decided to make them named after my favorite family of dog breeds which is the Bichon group, Bichon Frise.
>> Brian Holt: And we'll make five of these.
>> Brian Holt: So Bichon Frise, another one is a Bolognese,
>> Brian Holt: And this is a, let's do a Coton de Tulear. If you've not seen these breed of dogs, they're adorable, I just can't even.
>> Brian Holt: Of course, my favorite one, because it's what my dog is, she's a Havanese.
[00:02:54] And we'll put Multese in here as well.
>> Brian Holt: Okay, so that's some good mock data for us. And then we're gonna get some mock data from an API. So we're gonna call cons daggos = JSON.parse (readFileSync).
>> Brian Holt: Import that, readFileSync from path.join dirname and then res.json.
>> Brian Holt: And then put that toString.
>> Brian Holt: So this is a little bit of node magic. If you don't really understand it that much, that's okay. This is just making sure that you get the file from the right directory, right? So this is going to make sure that inside of the same directory, we're gonna have something called res.json and it's going to be reading from res.json.
[00:03:58] So what I want you to do, I've made this res.json file for you. So coming to complete-intro-to-react-v5, let's hop over to the testing branch. So hop on that, create there. And then inside of this, inside of mocks, there's this res.json file. Let's click on that.
>> Brian Holt: I think I have a, yep.
[00:04:25] I also have a link to this as well. So if you go into the complete-intro-to-react-v5, go down to testing, the last one underneath this one here, we have this part where it says go and copy and paste this fixture. So it's this, right? So just copy all.
>> Brian Holt: Make a new file here in the same directory and save it called, inside of frontendmasters called res.json.
>> Brian Holt: And as you can see, it's 1,100 lines of API response stuff, right?
>> Brian Holt: So now, doggos here will represent this file. That's all that this line does, is it just goes and grabs that file and parses it into an object, okay?
>> Brian Holt: Now what we need to do is we're gonna say a couple of things here.
[00:05:21] We're gonna say export ANIMALS = ['dog', 'cat', 'bird']. You can put more of them in here but for now we'll just make this a short list of animals. Export const rather, export const. Export const _breeds = breeds. I do underscore here just to signify this is only meant to be for testing.
[00:05:52] It's not meant for general consumption. And export const _dogs = doggos.animals. So inside of our testing fixtures, we'll test for these to make sure that they match up, right?
>> Brian Holt: And then here, we're just gonna make a really quick mock library. So const mock = an object, and we're gonna test breeds.
[00:06:22] And we're gonna make this a jest.fn.
>> Brian Holt: This is called a spy function which you're gonna check later to make sure this function has been called. And so we're gonna give it an implementation detail where it's just gonna say, whenever someone calls jest.fn, or calls rather mock.breeds, call this function and then return,
>> Brian Holt: An object with a then callback, right? It's promised like, right? And this is gonna be a callback,
>> Brian Holt: That then calls act. That is another function that returns callback with doggos. So I recognize that this is a little convoluted here, but let's just kinda step through it, okay?
[00:07:20] So we're creating a mock library of pet, right? So we've been calling our pet API client all over the place and we're creating an object that looks like it, right? Looks and acts like it. It has a breeds function, right? So we're making breeds a spy function that we can say, later, make sure this was called, make sure it was called with these things, so on and so forth.
[00:07:43] It's going to run this function which is then going to return a promise-like object, right? So when I say promise-like, it's an object that has a then function on it, right? So this looks and acts like a promise right here. This has provided itself with the function, right?
[00:08:03] And we have to call this act thing to let react know like, I updated something, go do something with that, right?
>> Brian Holt: So a little convoluted but this is how you. This is again probably why I don't like testing UI code is cuz you kinda have to get into the details with it.
[00:08:21] We're gonna do the same thing with animals.
>> Brian Holt: It's gonna be another jest.fn, or jest.fn.
>> Brian Holt: And it's going to return an object with the then function which is going to take in a callback which is then going to return an act which is then going to call the callback with doggos.
[00:08:46] Yeah, this one doesn't call doggos, this one calls breeds.
>> Brian Holt: So sorry, line 24 there, make sure that that's breeds and this one's doggos.
>> Brian Holt: Okay, so now you have two functions. This one returns breeds eventually, which is this one that we mocked up here, this one, right?
[00:09:10] And then we have one that returns doggos. And, one more thing, line 24. We need this to be an object which is breeds: breeds, like that, or you can just call it breeds, like this, because the API's response has to look identical or else the code's gonna fail.
>> Brian Holt: Okay, that's it, I promise. [LAUGH] So now at the bottom here we can say export default mock, but what's cool is anytime inside of our jest if it says, I have a mock for this, anytime that someone imports frontendmasters/pet inside of jest, I'm gonna use this instead of the real library, right?
[00:09:57] So now I have control over this, which is good.
>> Brian Holt: Now you might be wondering, jest is not defined. This is gonna be a global variable provided to us by jest. And we can make eslint to be okay with that if they go into our eslint.json file and say, hey, env, we also have jest.
[00:10:18] And just say true, and then now everything's happy.