Current section: Testing Remix 4 exercises

Rendering Components with Mock Data

Loading solution


00:00 Right from the get-go, we're getting an error. Uncaught error, used loader data must be used within a data router. So if we go into here and take a look at the component that we're rendering, right there, that's the used loader data that needs to be rendered within a data router. So to be able to do that,

00:17 we need to bring in CreateRemixStab, which is going to be able to create a fake version of the Remix app for us. So we create the stab right here. We're going to say our app, so CreateRemixStab returns a component that we're just going to call app.

00:34 This is CreateRemixStab and we define routes. These routes are actually going to resemble React router route configuration. So if you've ever worked on React router before, this should actually be pretty familiar to you. So we're going to say our path is the same path as what it actually is. So it's going to be slash users slash colon username.

00:53 So we've got that param. Then our component will be the username route. The thing that we want to render itself. Then we'll have a loader and that is going to, we want this to be the same type of thing, like we're going to return mock data and stuff,

01:11 but we want it to be the same loader as the loader of our component or the route that we're rendering. So we're going to use the same return type. So I'm going to say return type, type of loader, and this should be the awaited version of that.

01:30 So that is what is going to return. So let's return JSON. This utility is going to come from Remix. So let's import JSON from Remix run node. There we go. Then JSON is going to return

01:49 a user and user join display, and that can be whatever we want. Now, I am clearly added an extra thing there. Then we've got our loader that needs to be from here. We're just going to bring in the type though, because that's all we need. It's not the real loader, just the type. Okay, great.

02:08 Yeah, so we've got our user right here. We have our join display here. Probably better to just say user.created at to locale date stream. There we go. That makes it more realistic. Then once we've got all of that,

02:27 we can render the app instead of our username route. So we'll say app, and we've got it around this wrapper because we still need the authenticity token that's being rendered by our route. Then we can save that and see what our tests say now. Okay, we've got another error this time,

02:45 and the error is no routes match location slash. So we set our path to be slash user slash username. We could remove this, but we actually need that param. That's our application actually relies on that. And so what we're going to say instead is our app is going to have some initial entries. And so the initial entry,

03:04 that's an array of entries in like the history stack. We only need like one. We could have multiple, but we only need one. And that is, we're just going to land on this page. So users, and then we want the path, the username to be our user's username.

03:20 So we'll make this a template string and say user.username. And that will be our initial entry. We could also say initial index, initial, oh, whoops, right here, initial index and say initial index is zero, but that's the default. So we're all set there. Okay, and with that, our test passes.

03:40 We can take a look at screen.log playground URL if you want to, and then pull that up right here, our markup, oh dear, is very minimal. So there's a problem with that. Oh, I know what's going on. The problem is that it actually is going to take a second

04:01 for this to actually render our UI. And so that's why we're using these find by queries down here because we need to wait for those to show up. And that's what Olivia the owl was trying to explain and I just ignored it. So there you go. So if I do it after the heading,

04:17 then we get the full UI and let me move that over here. So this is what our UI looks like. Yeah, it's missing some styles and stuff, but that's the general idea. And we can use that to select the heading and the image and the link and all of that stuff. And then of course you can always say screen.debug right there.

04:38 And there it's all laid out and nicely highlighted and everything, which is pretty cool. Okay, great. So let's just do a quick review. We brought in the CreateRemixStub, also brought in the type of the loader and JSON for this test.

04:55 We created a RemixStub that gave us back an app. We defined the routes that we want for this test, specified our component and our path and our loader. And then instead of rendering our components, we're rendering the app. And we're still using React Testing Library to render that. The RemixStub is just creating the app

05:14 that has all the context necessary for our components to be rendered. Then we also specify where we want to be rendered because we can have multiple routes. And so we need to say which route we want to have active and what params they will have and everything. You could also do search params as a part of this as well, if you wanted to.

05:32 And yeah, then we wait for these things to appear. It doesn't take long, but it does take a moment. So we use screen.findby for these queries. And in general, at this level of testing with integration testing, which is what we're doing here, we want to typically use the find variant

05:52 of these queries anyway, because if you're using the get variant of the query, so if we say get by role and all of those, then those are not async. So they will look for those things in the DOM right now. And unfortunately, you can't really rely on that ever. Somebody could add some asynchrony to things

06:11 and that could very well be a perfectly fine thing. And so when you're at this level of testing, I actually recommend you typically want to use the async version of all of the queries. The exception to this being like, if you want to verify that something doesn't exist, then you're gonna use query by,

06:29 and you just want to, the tricky thing with an async thing is how do you know that it never shows up? But yeah, so you're typically gonna be using find by, sometimes you'll use query by. And then if you're at a lower level test, then using get by variant to the queries is just fine.

06:47 And interestingly, when you're in Playwright and you're doing all of the locators and things there that are testing library inspired, those are also going to be async as well. So once you get to this level of testing on the testing trophy, we're in the integration piece right now. Once you get to this level, you're pretty much better off doing the async queries.

07:06 Okay, I think that is enough for this step. So let's keep on going to the next.