Setting Up a Mock Server with MSW Node
00:00 Let's get started by getting the mock server itself up and running. So we'll go to our mock index right here, and this is where we've got our file that's going to be setting up our mock service worker. We're going to bring in setup server from MSW node, and we'll take care of resend here in a little bit.
00:18 We just want to get this server up and going to get us started. So we're going to call setup server, and we're going to pass in these miscellaneous handlers. This is for Remix's hot module replacement and hot data revalidation functionality.
00:34 It actually makes a HTTP fetch request or a post request to the Remix dev origin slash ping. So because every single fetch request is coming from our process, it's going to be intercepted by MSW, we have to handle that,
00:52 and just basically what we're doing is just letting it pass on through, just like let that thing happen as it happens. You will definitely have some things like this as you're building out your apps. So it's a useful thing to know about. Okay, we'll add the resend stuff to this later. What we get from this is a server,
01:10 and then we can use server.listen right here with an unhandled request of warn. So if there is a request that's made in the process of our application running, it's going to log to the console and say, hey, you didn't actually think about this request,
01:29 maybe you should intercept it. Then we have server.close when our process closes, so we can clean up after ourselves nicely. So with that all set up, we can get our process hooked up to this MSW server.
01:49 To do that, we need to do a couple of things. So we'll go to our index.js, and in here, we're going to key off of whether the process env mocks is set to true. If it is, then we're going to dynamically import
02:08 the mocks from our test mocks index file. So we can just import it and forget it. We don't need to worry about handling what comes back. I will add an await here just to wait until
02:25 the mock server is all up and running before we actually proceed. So with that now, I actually should be able to start this up with mocks mode enabled. I could run npm run dev and with mocks equals true and all that work. But as just like a default,
02:43 I think it makes a lot of sense to just set mocks to true as part of the dev server script. So that's what we're going to do right here. We'll say mocks is true when we start our dev server, and that way we don't have to worry about it. So with all this setup now, we should be able to restart our server.
03:02 Let's take a look at our logs going on right here. Once our server is restarted, which I'll do right now, then we should see that log. Yep, there it is right there, mock server installed. So we're in a good place there.
03:18 Next thing we want to do is actually intercept this request that we're making. So let's go to that signup route again, and we'll turn on this little test that we had there. We'll go to login and then create an account, and that will take us to the signup.
03:38 Actually, we got to import that function again. Here we go. So now we go create an account, and we end up here. We can take a look. We get our status error, API keys invalid because we're not handling that yet. We also get the MSW warning because we aren't handling that API.
03:57 So let's handle that API, and then we won't have this problem anymore. I'm going to get off of this page so that we're not making those requests every time I change a file, it's going to refresh itself. I don't want to make those requests until I'm ready to test it out. So right in here in our mocks directory, we've got this resend module that is going to be
04:15 responsible for mocking out the resend API. We're going to build this out as all of the APIs that we're hitting with resend, which for us is just the one. So the first thing we're going to import is HTTP response from MSW,
04:32 and we also want the HTTP utility, and we're going to need the HTTP handler type from MSW. So we'll grab all of that, and then we're going to export const handlers, which is an array of the HTTP handler.
04:51 We'll have just all of our handlers right here. Yes, you're exactly correct. Copilot, we want to mock out a post to this API, except Copilot doesn't know about the new request response API from MSW in the latest version. So we're going to have to help it out a little bit.
05:10 So we'll take the request as one of our options there, and then we can get the request body from request JSON. There it is. Nice. We're going to just Copilot. You're helpful, but not always perfectly helpful. You got to watch your AI assistance. So here we're grabbing the body,
05:30 and then we'll handle the extra credit here in a little bit, and then we want to log out the e-mail body. The reason that we log out the e-mail body is to make it so that even though we're not actually sending the e-mail, we need to see the contents of the e-mail because it's going to have a special code in
05:48 it that we're going to use to actually log in and everything. So you want to be able to look in your terminal output to see that code, but we don't want to actually send the e-mail. So we'll log out the e-mail contents. I'm going to make it more obvious what it is, mocked e-mail contents. I like to use this little emoji which looks like
06:08 the old MSW logo a little bit. So here's our mocked e-mail contents. Then we have this helper utility from HTTP response called JSON. So I'm going to plug that off JSON from the HTTP response and we're going to return JSON.
06:26 Now, this looks a lot like a remix, doesn't it? That's the power of standards. It's pretty amazing. So if you go to the recent docs, you'll see what the API is for this particular API, what it sends back. That is an important part of mocking is making
06:43 sure that you're resembling the API as closely as possible. So a couple of things that it sends back is an ID. We're going to use Faker actually to generate an ID. So we're going to say string UUID.
06:56 Then it sends back the e-mail or the address that this e-mail is from. That's going to come from the body. Then the two will come from body two. Then it also sends a created at, which is an ISO string.
07:15 TypeScript is not super jazzed about this. We'll fix that here in a little bit. But with that, we should be able to restart our server. Actually, we're almost done. We need to come over here and bring those handlers in. We'll spread the recent handlers along with the handlers that are handled.
07:35 Now, that will trigger a restart of our server, and we've got the mock server installed. So now, if I go to create an account, then we get exactly what we wanted. We no longer are going to get the error or these warnings about the recent e-mails, and the API key isn't valid. We're no longer making that request.
07:54 Now, our request is being routed to our handler, which is going to log out the e-mail contents, and we get a status of success. So we're in a good place now. This is awesome, actually. We can even see the HTML version and all that stuff, which is pretty cool. So good stuff.
08:12 Let's clean up a little bit here because I don't like the red underlying squigglies either. So we're going to import Z from Zod, and then we're going to make a e-mail schema, which is a Z object, a Zod object.
08:29 And basically, we want to have a type for what the request JSON should be. So it should, actually, if we go over to our send e-mail function we wrote, it should have from and all these other options. So all these things. So let's just grab these,
08:49 and we'll let Copilot help us out just a little bit. And we'll add a from, which is a string. There we go. Okay, Copilot, can you do this for me? And actually, when we end up sending it, the HTML is not going to be optional. So we're going to say from to subject HTML and text.
09:09 And with that e-mail schema now, we can use that to parse the request body. So we'll say e-mail schema, parse the request.json function, and now everything is happy. And it will still work. So I can refresh, and we get those contents all logged, which is sweet.
09:30 And yeah, with that, we're all set. We are mocking properly. So let's review everything, because there are a number of moving parts here. First of all, we created our module that's responsible for setting up MSW. So we grab pass through an HTTP from MSW,
09:49 set up server, and our recent handlers. We have these miscellaneous handlers. These are for handling the HTTP requests that our server is going to be sending to let Remix know when it's ready to go. So, and that's for HMR and HDR support. And then we have our setup server function
10:10 that we call with all of our handlers. We log that the server is installed and ready to go, and we listen and log out any unhandled requests with a warning. So it doesn't like fail or anything. It just logs a warning for us. And then when the process exits,
10:29 then our server will be closed. Then to get this file running as part of our process in our index file, the first file that's run as part of our server, we have this check here to say if the mock environment variable is set to true,
10:46 then we'll dynamically import that mock file. And then we set our mocks to true in the dev server script. So this is the, when we run our dev server, this is the first file that's going to be evaluated and it shells out to TSX to start our server.
11:05 And then we went over here to sign up to do this little test right here, make sure that this thing is going to work. And we added our resend mock. So here we can handle a post request to this URL. And with that, we started getting the warning before we added this.
11:24 So we, now we handle it, we get the response body, we log that out, and we return something that is similar to what is returned. This email parse is actually more than just TypeScript, like making TypeScript happy.
11:41 This is also ensuring that we're using the API as expected. Anytime you mock something, you're poking a hole in reality. You need to fill it in as best as you possibly can by making assertions. And so this is an assertion that we're making to say that yes, indeed,
11:57 they are hitting the API appropriately. So that is getting our mock server up and running so that we can send emails without actually sending emails during development.