Check out a free preview of the full API Design in Node.js, v4 course:
The "Testing the Create User Route" Lesson is part of the full, API Design in Node.js, v4 course featured in this preview video. Here's what you'd learn in this lesson:

Scott uses the supertest module to write an integration test for the createNewUser route handler. A mock object is sent along with the request with the username and password. The importance of using a testing database is also discussed in this lesson.

Get Unlimited Access Now

Transcript from the "Testing the Create User Route" Lesson

[00:00:00]
>> Maybe we should write a real test from one of the handlers to see what that looks like with Prisma, and then we can try something else. So let's do that, so I'm gonna go to handlers. Let us actually write a real test here versus what's actually happening.

[00:00:14] So let's bring in that user, so we can bring in * as user from, User, cool. And I wanna test on the user that we can actually create a new user, let's do that. So I'll say it should create a new user, okay? And I'll say async, so I'll say user =, I can't say user.

[00:00:45] NewUser = await, user.create new user. And if you look at this, it expects a request a response and next, okay? So you can like, basically, this function doesn't know that it's in Express. It is saying it needs these three things. We're the one calling the function, we can mark these three things out.

[00:01:10] We can make them be whatever we want. I am just looking at this code and tell you that like, they want the request object and that request object needs to have a body object that has a username and a body object that's a password. Okay, cool, I'll do that.

[00:01:24] And it also needs the response object, response to be an object with a JSON function on it, so I can do that. You can mock these out yourself. You can download packages that will mock them out for you. There's a lot of ways around it. I'm just gonna mock it out myself for now, so we can actually just see the result of it.

[00:01:43] So let's do that. So I need to mock out requests and I need a mock out response. So let's do that. So I'll say, Routes. And what's really cool, is that you can actually use something called a spy. A spy is like a mocked piece of functionality that will tell you when some other piece of code interacted with it.

[00:02:12] We probably won't need to do that right now but we can do it. So a request is just an object has a body property on it that has a username, hello and a password, Hi, okay? And then RES is also an object that has a JSON function on it.

[00:02:38] And if we were gonna make a spy, this would be the spy. This is what will be the spy because we would we would wanna see that this was called and that it was called with like a token. And we want to see that token, right? So we can make this a spy, we can also just like get the token from here and then we can do an expect inside of here.

[00:02:58] We can say expect(token)toBeTruthy(), we can do something like that. And then we can also say expect or assertion count or something like that. We can tell just how many expectations should be called because if this doesn't get called, I mean, JSON was never called, and that would be like a faulty test.

[00:03:25] So you would wanna tell just like I should expect to see at least one expect call, if not more, that's good indeed. So we say createUser, we'll say req, we'll say res, and these next I'm just gonna just do that for next. So we can do that. This isn't going to be a new user because it doesn't return anything, right?

[00:03:46] This is just a handler, it doesn't actually return anything, so it's not gonna be a new user. So really the only way we can verify that something got created. It was we had to do another query the database after this ran to see there was a user with that, or we can just look at the result of the token, one of the two.

[00:04:04] We're just gonna get the token for now and just be naive about it, but let's see what happens. We'll do that and then let's run the tests. And yep, obviously the integration test failed cuz we broke that one, right? I just never fixed it, but the unit tests we just wrote passed.

[00:04:24] So it's fine, it worked because it actually did run this, which was expected. If I log this token, you actually see it, right? Well, now it's gonna break because, and I'll tell you why it's gonna break, actually anybody know why this is gonna break if I write it again It's like, wait, it just work, why would it break?

[00:04:50] All you do is log something. Yeah, it's definitely gonna break, if I run this, it's not gonna pass. It's because I'm creating a user with the same username again, right? In a test, you wanna make sure you delete the database every test run, you wanna clean database, in fact you should be using a different database for testing.

[00:05:18] You probably want a local database, you should be using a host database to host, it's expensive. So you want a local database and you make sure you clean the database, you delete everything after every single run. And the way you can do that is like before all, before each, after all, after each, inside of those functions, you can say, delete everything I just did in his test.

[00:05:44] So when the next test runs, it's good. That's one way to do it. You can also set a configuration file ingest that runs before all your tests run, that just drops the database. But you never wanna have stateful tests, whereas like there's one test that runs and adds something to the database.

[00:06:01] And then you have another test that runs and it relies on the stuff that this thing added. You will have the worst test ever. Don't do that, every test should be stateless and non-reliant on any other test. But yeah, this is gonna fail, let see. No, I guess not, I guess it doesn't care, it passed anyway somehow, that should not have passed because there's already a user in there.

[00:06:31] It just passed again. I wonder if it, did it log a token? No, I didn't even log a token actually. I think this is just a false positive, but yeah, and maybe our test was never passing in the first place. And we just found out that it was just a bad test because this actually never ran and no expectations actually ran maybe that's what's happening.

[00:06:54] But yeah, don't put stuff in the database and not delete it during a test
>> Is there a big difference having one test directory over having tests everywhere? What are the pros and cons?
>> You'll have smaller test files. Yeah, that's probably the biggest pros, smaller test files and, Yeah, smaller test files and then you would probably be able to configure different options for different tests if they were individually group versus putting them all together, adding the options to all the tests, so more flexibility.

[00:07:31] And in a bigger app, just anything that's more abstract away is usually easier. So different teams can work on different things without conflicts. The last thing you want is a merge conflict on a test file. That's the worst worst conflict because it's like you don't wanna touch it.

[00:07:46] Because you know all those tests were passing like for a whole year straight. And now you got a merge conflict in there. And it's like I don't wanna touch this file, somebody comes save me because if you try to fix that merge conflict and you break a test, good luck it's gonna be a bad day.