Advanced GraphQL Simplifying Resolvers
This course has been updated! We now recommend you take the Advanced GraphQL, v2 course.
Transcript from the "Simplifying Resolvers" Lesson
>> Scott Moss: Let's check out Lesson 5, which is gonna be our last lesson for today, but probably the most valuable one, because it's testing. And everybody here writes tests.
>> Scott Moss: [LAUGH] Nobody writes test. They are like [COUGH] test. You're right. Okay, yeah. Nobody writes test, but like you should at least know how to write GraphQL test.
>> Class: [LAUGH]
>> Scott Moss: [LAUGH] You should at least know how cuz it's on your ticket that you got, it says you gotta write test on your ticket, right? So you need to do it. And testing in GraphQL, it can be actually pretty fun. I found testing in GraphQL is way simpler than testing with anything, especially if you use best practices and stuff like that.
[00:00:54] So first thing we wanna talk about is how to write testable resolvers and keeping those testable, so you can test them. We already scratched the surface on it when we talked about context, but let's just dive into it. And I don't think we're gonna have too many examples in our code of what a resolver would look like if you couldn't test it, so we'd probably just make some bad ones right now.
[00:01:18] But let's talk about the good things about a testable resolver. One, I already mentioned, is basically if you just rely on the context object, you will go far. You will go far. So, put everything on context. Don't try to import anything that you have to use in this function because it makes it really hard.
[00:01:36] Two, try your best to extract all the logic that's inside of a resolver out of the resolver, and just use it inside the resolver. The reason you're gonna do that is because, yes when you call your resolvers you can like mark out the stuff for like, what if you had a function that was marking this out?
[00:01:58] Like can you imagine it's gonna mark out this info object? Like you just couldn't. So let's not try to do that. But instead, let's take out most of this stuff, this one's not so bad, and put it in another function. And then just call that function with the only arguments that it needs.
[00:02:13] It doesn't need these GraphQL arguments, it just needs these specific things. And then you could test those functions independently from the resolver, which makes it a lot easier to test. And that's just true with testing in general, but even more so with GraphQL. So for instance, if I were to convert this trivial example over, I might just say, I might just take that out.
[00:02:37] Obviously I put this on another file, but-
>> Scott Moss: I go like this.
>> Scott Moss: And then instead of that, I might just say, models. And then, id-
>> Scott Moss: projectModel. And yeah, that's what all I would do. So I would do that, I would convert this to projectModel.
>> Scott Moss: And change this to id.
[00:03:14] And then now in here, I can just return getProject. With the args.input.id, and then ctx.models.project. And now, all I really gotta do is to test this function, which has just these two arguments. Which is way easier than these two arguments, or these four arguments.
>> Scott Moss: Right? So this is a true example, but you will have resolvers that you will be scrolling on for a long time.
[00:03:42] And when you start doing that, and then when you finally decide to write test because that's where your stripe code is. You wanna write test there, you realize you can't. So you should start doing this to begin with, and now you almost never have to touch these. Yeah, the only thing you've got to test this function is that it calls this function.
[00:04:01] Expect this to be called. That's it, you don't really need to do anything else. Then you go test this one by itself. So it's way simpler. That's how you keep all this stuff simple. As far as testing these files right here it really depends on you. These files the way we're importing they're just strings.
[00:04:26] So you literally could just like, all right here it is, I'm done Command a copy, go into a test file and say, it better look like this. Like you could do that, it's just a string. It's only up to you and there is nothing wrong with that. You can also make a dynamic where you import this as a GraphQL.
[00:04:58] I don't feel the need to actually come in and test these actual files and make sure that they're exactly the way they're supposed to be. And that's because the resolvers have to match with them anyway, and I test the resolvers. But I can see a use case where I'm testing to make sure somebody doesn't come in here and do that.
[00:05:15] All right, so you probably do want to test for that so It's up to you. This is literally just a string if you import it as a strings. So, hard code it in your test and see that this string equals this file and make sure it stays that way.
[00:05:26] But then as soon as you change it, you will definitely be breaking your test. Which, I guess is what's supposed to happen, so it's up to you. Now, the other type of test is actually testing that given a certain query, you actually get back the certain result, all right?
[00:05:42] So wanna test the query, you wanna test the mutation. That's kind of like an integration test on graph 2.0. And that test I do all the time. I think that's way more important. Just testing out the inputs, how all this stuff works. Is this stuff gonna resolve? And that's really testing everything, so that's what I wanna walk through today.
[00:06:00] So testing that, the integration testing stuff and then testing just unit testing like the resolvers. So let's just do an example of that. So if you're going to test an API, there is a project.spec here, you're gonna be doing some test stuff in here, but before that, I'm just gonna write some test on task, let's see.
[00:06:27] So task, we got a whole bunch of resolvers here, we got tons of queries, we got all types of things. So what I wanna do is-
>> Scott Moss: Gonna come in here, I'm gonna make a new file called task.spec.js. And we're using Jest for writing tests. If you've never used Jest before, it's fine.
[00:06:46] It's the same thing as Mocha, which is the same thing as Jasmine. So it's all the same thing, so you're not really missing anything here. All right, and there's just some setup and tear down here for connecting, and dropping, and disconnecting to the database, so you don't have to worry about any of that stuff, it's all taken care for you.
[00:07:07] And then this magic function in here which really shows the power of GraphQL. Basically, I take the schema that we used to generate our server, that exact same schema, that same resolvers, the same type definitions. And then I give in a query and some variables and even some optional context, I'm able to execute that query, write in the test.
[00:07:32] I don't need a server for it, I just execute the query. And that's how GraphQL works. I can run GraphQL anywhere. In fact, there's literally a package called GraphQL anywhere, where you can run GraphQL anywhere without a schema. It's really crazy. But in this case, given a schema in a query, and some optional variables in context, I'm able to execute anything.
[00:07:51] So this means in a test, I can actually just write a query as a client would. Insert it into this function and expect some output, just like a client would. So it's like an integration test. So this is how we can exit, run our GraphQL test without actually having a server.
[00:08:07] We don't have to start the server up and see, we can just execute the GraphQL just like this.