Current section: HTTP Mocking 5 exercises

Testing OAuth2 Flow and Mocking GitHub API Responses

Loading solution


00:00 So let's go to our auth provider callback test. And there are a couple of things that we need to make sure that we're doing. So first of all, when we go through this auth process, we're going to be talking to the GitHub API. Now for development, we already put together a GitHub mock. So if we go to GitHub under our mocks, we've got a mock here already

00:19 for dealing with that API during development. We developed this already, but we need to make sure that we have the mocks running in our tests. So if we go to our index TS, this is where we do our server.listen and all that good stuff. So you need to make sure that those mocks are running in our tests.

00:39 And so that's what this import is going to do is it will start up the mocks as a part of this test process so fetch requests that are made as part of our tests will be mocked out in the same way that they're mocked in development. This is actually one of the really, really cool things about using MSW the way we are is because we can mock things the exact same way

00:58 during development as we do in our tests. So just saving that, now we're setting up our mocks as a part of this process for the auth provider callback test. And so now we can start making requests and those GitHub requests will go through our mocks, which would be sweet. Okay, so we're going to need a couple other things.

01:17 We'll just grab those from our handy helper, Marty the money bag. And then we're going to create a couple of variables. So these two will be const and set to these values. So the route path is where we're going. This is a generic provider. You can add other providers.

01:37 We're going to go with the GitHub one and our params for that will be GitHub. We're going to use that when we call the loader. And then we're also going to need a base URL for constructing the URL. And that can be epicstack.dev or you could do the whatever example.com, however you want to do that.

01:57 So now we need to create our new URL. So here's our URL that is the path, which for us is the route path. And then here's the base URL right there. And we can get rid of that right there. Awesome. Okay, so that gets us our URL,

02:16 but we need some search params in this URL. If you recall, we have a code and some state. So let's create that. Our code is going to be fakr.string UUID and our state will also be fakr.string UUID. Let's grab fakr and get that imported.

02:35 And then we need to set the search params on the URL. So URL search params set the code and the state. So those end up on the URL for that request. And then to simulate the environment that is present when we land on this page, we need to set a cookie.

02:55 So if you recall from the web auth workshop that we went through, and we actually have this as part of our mock in our GitHub under providers right here, where we're simulating this connection session. We need to do this same sort of thing because this connection session is how RemixAuth

03:17 manages the state for this OAuth2 flow. So we need to do the same sort of thing in our test to simulate that state being established already so that when we go through and call the authenticator.authenticate, that is already in place so that it can handle that.

03:35 So we're gonna need our connection session and that's await connection session storage.getSession. And then we'll set the OAuth2 colon state to state. Now this is kind of an implementation detail of RemixUtils. It ties our test to that implementation. Hopefully that never really changes in the library,

03:54 but I can't think of any other better way to simulate this important aspect of the auth flow. So this is what we're doing. And I've done this before and it works well. Okay, so we're gonna get the set cookie header. So the set cookie header comes from awaiting connection session storage,

04:13 commit session with our connection session. There we go. And we need to turn that set cookie header to a actual cookie header because we're gonna create a request and simulate the cookie that will be set as part of this authentication process.

04:30 So we need to convert that to a cookie header. So convert set cookie to cookie with that set cookie header. Now that's a little utility that Kelly Coworker put together for us. Should look familiar. We did this with our Playwright stuff before. So we're just parsing the set cookie string

04:51 and then grabbing the set cookie header and that works out nicely. Okay, great. So then we can get our request from a new request of our URL to string. And then our headers will include the cookie headers. You can also specify a method of get

05:10 to be really specific there. And that will take care of creating the request. So the next piece here is we need to call our loader and then validate the response that we get back from that. So the response will call the loader with the request and the params.

05:29 This is actually gonna be in an object. The params is a property of that object. And the context is also a property of that object. So context is not something we're actually using in the Epic stack at all, but definitely something that you might use

05:48 and you absolutely have to provide it. Otherwise TypeScript will not like you very much. So we're passing that context object as well. Okay, great. And to be clear, that context object is called the load context in a remix lingo. This is different from like a React context thing. So once we get that response,

06:07 like at this point we're calling the loader and all of the API like GitHub API calls are gonna happen as part of this loader. And once that's all finished, then we should get a response back. And that response should send us back to onboarding. Let's go ahead and console log the response. So we can see a couple of the things

06:27 that are a part of that response. So with that, we cannot read property get session, uh-oh, of undefined. Let's see, we've got our connection session storage that's coming from the wrong place. Connection dot server TS. There we go. That should take care of that.

06:45 You gotta pay attention to your type errors, people. Okay, so we've got our response and there's our headers right there. Location is sending us to onboarding GitHub and it's got a set cookie and stuff there too. So awesome. Now all we have to do is assert our redirect.

07:05 So let's say expect response dot headers dot get location to be our onboarding URL. That expect, of course, is gonna come from vTest. So let's bring that in from vTest and we can clean all this stuff up and we've got our happy assertion in here.

07:23 So this, yeah, we need to use the base URL. There we go. And like I said, any URL there will work. So let's review really quick and then I'll leave the extra credit to you to implement that. Ah, heck, we'll do it together. We'll do it right now.

07:40 So this is gonna just be a simple assert redirect function that takes a response, response and a redirect to, it's a string, and then we're just doing a bunch of assertions here. So we'll expect the response status to be greater than or equal to 300.

07:59 So that's just a redirect response, but it has to also be less than 400. So between 300 and 400. And then we'll have our expectation on the location to be the redirect to. And then we can say assert redirect on the response should go to onboarding GitHub.

08:20 There we go. So that takes care of that piece. Now we can review. So what we did here was we create the URL that we're going to be hitting as part of our whole flow. Like this, when our loader is called, we're going to expect that the request.URL matches where that loader is. So that's important.

08:41 We also expect some search params. This is remix auth is going to expect both search params as well as some cookie state. And so that's what all of this is establishing right here is that stuff that the remix auth requires for this OAuth2 flow.

09:00 And so we're creating a code and setting some state. We're setting that in the cookie so that when we go through our authenticator.authenticate, remix auth will look for that code and that state and it'll find the same state inside of the cookie and be like, okay, good. So they've gone through the auth flow.

09:18 Let's let them through so they can go through onboarding. And then, and it's going to hit our mocks, which we have in here. It's going to be talking to our access token API and we're creating a GitHub user for that and sending back a token.

09:38 And so that's how all of that process works is the authenticator is talking to the GitHub API. All of these API calls are working just fine. And so it is able to proceed and let us through like we're an actual user that authenticated with GitHub. So then we call our loader and we assert

09:55 that the response sent us to the right place. And that is your first test for getting this server started up for this mocking that's going on during our testing.