Introduction to Node.js Debugging & Testing Solution
This course has been updated! We now recommend you take the Introduction to Node.js, v2 course.
Transcript from the "Debugging & Testing Solution" Lesson
>> Scott Moss: That one was just very, I have no idea what I'm doing. Yeah, that's the purpose of debugging. The whole point is, I have no idea what I'm doing but I need to find a way to figure out how to make some progress, especially when it's somebody else's code.
[00:00:16] Debugging your code is one thing. Debugging somebody else's code when you have no context on this library that they're using and any of these stuff? It's another thing. So the only way to make it through is to use your fundamentals of logging and inspecting and just walk through line by line.
[00:00:33] And try to figure out what's expected and what's being returned. So that's how you have to have solved this. Obviously, I know where all the issues are because I made them, whether they were intentional or not, I made them. So I know where they are. But there's a couple of things you can do here.
[00:00:50] So let's just start. I'm just gonna get into it cuz there's other stuff I wanna talk about. So basically, what you want to do is you will start the server first. So we start the server, and then we should be able to do a get request to user/1 and get a user.
[00:01:10] So if I do that, it doesn't really work. It kind of just hangs. So like I said, the issue are very obscured. You don't even get a log. Nothing even logs here, like nothing happens. So you have no idea what is going on, it's just hanging. This thing is still spinning, this thing is not logging anything.
[00:01:27] So there's no way to get past this unless you're just really good at knowing and you can just look and see what's happening. So the first thing I would do is I know I'm hitting this route user/id, that's the get request that I'm doing. So I'll go ahead and kinda figure out what's happening.
[00:01:44] So first thing you might do is maybe you'll add a debugger in here. If you wanna jump right into the debuggers, just go ahead and add a debugger here and we can start this thing with inspect, we'll start that. We'll go ahead over to Chrome, and we'll look at the chrome://inspect tab.
[00:02:08] We'll click on Inspect here. And we'll fire off an API call, and then boom, it pops open here. Now we're in inspect. So now we're inside of here. Now, we can kind of figure out what's going on. So line 13, Const id equals rec.id. Rec.id is undefined, that might be a problem.
[00:02:26] So just literally the first line inside of this controller, I was able to find out that this code is expecting id to have some value, but in fact it's undefined. It's literally the first line. I'll just put a debugger here. And I was able to find out. So that's probably a bug.
[00:02:43] So you got to fix that. How would you know to fix that? Well, you don't really know that unless you kinda looked at some Express documentation or did some exploring. You would have to have figured it out. If you really wanted to get this to work, you could have just hard coded an id.
[00:02:57] I was gonna put one here and get this to work and keep going. And that way, you don't really need to concern yourself about how Express works. That way, you're just completely forget about Express. I don't really care about it. I'm just gonna put 1 here, and then make sure that this works, and this is satisfying it.
[00:03:11] So it's like trial and error. But you also could have came here, and you could have looked, and you could have looked for something that might have made sense. But to fix this, there's actually a params property called id, so req.params.id. And that's where the id is. So it looks like there was a bug here.
[00:03:26] It's looking for a req.id, but it should have been a req.params.id. And again, this is free. I just typed in the debugger, did inspect, and I'm just looking at this thing. With one glance of an Express documentation, I could have found that out as well. How do you get a parameter?
[00:03:41] Cuz it's undefined it should be there. I could have found that out.
>> Scott Moss: So there's our id so that's one fix. Yeah cool, so let's make that fix and we'll see what happens.
>> Scott Moss: So req.params.id, params is the name that's here. id is the name that's here, they match.
[00:04:01] If I changed this to something else, it would be called something else here as well. That's where the id came from, id, id, okay, cool. So we got that. Let's restart the server and continue going. So we'll do that again. Go back to Chrome. I'll just close this, open back up the inspector, refresh, make sure it's good.
[00:04:24] Got the debugger still running. We'll issue another request boom debugger stops. Okay, cool req.params.id, look, it's 1 now. That's great, we got a value, it's string 1. So let's continue to go. So the next thing we'll do is this one is like let's put a breakpoint here. Cuz this is a function and then we will just hit play and see what happens.
[00:04:45] So we'll hit play, hit our breakpoints here. So we're gonna wait on users.find user. So we wanna see what happens, so we'll put another breakpoint here and we'll hit Resume and what happens if we go look at the output? Looks like node just hit the bed says UnhandledPromiseRejectionWarning.
[00:05:08] No user with id "user, arrow function user.id. What does that even mean? So if you were to look at this, If you were to look at the AP offer find user, if I were to go click, and it's even showing you right here, find user takes an id.
[00:05:25] It looks like I'm passing at a function, all right. I'm passing at a callback function to find user, when in reality find user takes in an id, so we can verify that if we go look at the source code Users findUser. Yeah, it just takes an id, that's it.
[00:05:42] I'm passing it in a function, and that error just over here, no user with the id. And it's just wrapping the argument in a string. The argument was a function, and that's why you see the function and print it out as an argument. Cuz it's expecting an id but it got a string, so that's another error.
[00:05:56] So I need to change that to just be id, boom.
>> Scott Moss: So that's those two fixed. So we'll restart, we'll run it again.
>> Scott Moss: And we'll close that, do a refresh on the Inspector to make sure it's good. Cool, open the Inspector. And we'll get rid of these breaks, the debugger is still there.
[00:06:23] Actually, we'll put a break here just to make sure it will issue a request, it stops on the debugger, we'll hit play. And looks like something happened, let's see. So now it's saying error, no user with id of 1 in a string, so that's kinda weird. Because if we go look at our code, we know that we do get an array of users with the indexes of between 0 and 20, and the id is definitely 0 to 20.
[00:06:52] So we know there's a user there with an id of 1, and we can verify that, right? If we put a debugger here,
>> Scott Moss: All right, and then we restart this, and we go back and do all of our stuff all over again.
>> Scott Moss: Refresh that, inspect this.
[00:07:17] Hold on, there we go. Hit play, boom. So we put a debugger here, and we look at users, there is a user id of one right there. It's right there. So how is it not finding this? Is my algorithm wrong? Well, I'm in user.find, compare user.id to the given id.
[00:07:34] That seems pretty fair. I don't understand why that wouldn't match. Anybody figured this one out?
>> Speaker 2: You're type checking too.
>> Speaker 3: It's a string versus a number.
>> Scott Moss: Yeah, this one's so obscure. Yeah, I'm glad you guys found that. Yeah, it's a string versus a number. So because you pass up an id, Express transcode everything as a string.
[00:07:53] But I'm comparing it to a number. So they're both 1. So remember, 1 is a number on the user. But from the route parameter, it's a 1 string. So the equality fails. So you have to convert it to a number and there's just no way you would have got an error for that.
[00:08:06] You just would have seen it, and even the log is kind of obscure. It's like, yeah, I am passing a 1 but it's a string you had to notice that detail. So it's pretty minute, so you would have to fix that to make sure that that is actually comparing correctly.
[00:08:21] So that's why I made a function called fixId takes in an id ad just does a parseInt on id. And then now I got to say const I just got to make _id equals fixId of the id. But know I just compare against _id. And I'll just change that to _id as well
>> Scott Moss: All right, there we go, thank you. Cool, so that should fix that. So now let's try to this, get rid of that debugger at the beginning, kind of annoying and we'll restart this
>> Scott Moss: And then we'll go do the whole thing again, refresh that.
>> Speaker 4: Do we have to restart the debugger each time, the window?
>> Scott Moss: I don't think you do. But from my experience, sometimes there will be a different, so every time you start the inspector, it gives you a unique hash for the web socket. And sometimes it's different. So it's better just to restart, otherwise you'll be in a stealth state.
[00:09:24] One time I got stuck, thought I was debugging some code, but the code was out of date. And for a long time I was like, I cannot figure out this. I don't understand what's going on. I was looking at code from two commits ago. So I just started refreshing it by habit.
[00:09:37] So it's a habit that I do. So open inspector.
>> Scott Moss: Issue a request. And look, it's gonna work this time. So boom, we debugged that one and we went through line by line and use the debugger, inspected everything and we were able to figure it out. And that's exactly what I would have did if that was your code that you gave me.
[00:09:56] It was my code I would have started logging everything. But I know something is wrong here, I smell it, but it was your code. I was like, I was gonna open the debugger, and just, I'll work from there, and figure it out. So yeah, it's a tough process, and a lot of those bugs I wrote were hidden pretty sneakily.
[00:10:12] [LAUGH] But if you use a debugger, you would have found them. So yeah, that's that. And then for a test, there were probably already some tests in there, right? They were already good to go. The way you would write test for this, and I just wanna be brief because I wanna get to the next point.
[00:10:30] But basically, if we go back and look at all the things that we fixed, you just wanna write test for those things, and they're pretty simple tests. So for instance, users, if you look at users, I made this fixId function. So I would make sure I export that down below, fixId.
[00:10:44] And I would write a test for it, so we'll try to click on right click. So I'd say, oops, my charger fell off, that's all right, I'm good to go. So I will write a test for fixId, and I'll pull in fixId here
>> Scott Moss: Oops, the ES6 [LAUGH],
>> Scott Moss: From users and I'll say fixId and I'll just write a test. So I'll just say expect(fixId) to, oops, that's a function so (fixId("200") in a string to be 200 as a number, and I write a test for that. Pretty simple test, that function only does one job, it turns a string to a number, pretty simple.
[00:11:32] So I'll just run that test, and if you looked at the read me, you can actually just type in npm test to run the test now, and I'll tell you why in a minute. So npm test will just run your test. And this other stuff still fails because we didn't fix any of that but exercises testing test areas, that passed and that's literally only this one that's all in the past.
[00:11:56] So we're good to go. Any questions on debugging and testing in node?
>> Scott Moss: After me showing you walking through debugging, was everyone able to understand the pattern how to go about debugging application? Or is this still like I feel just as lost doing this when I first started now?
[00:12:20] Or does anyone still feel like that, yeah?
>> Speaker 5: I just had a question. Can you go over again, I missed how you, when you went into Chrome and when you started the inspector, how you opened the file in there.
>> Scott Moss: Got it, yeah, so basically, so once you start the inspector, right?
[00:12:38] So you'll start the inspector with the --inspect flag. You got that part, right? Okay, cool, then you go into Chrome. And then in Chrome URL, you want to type in this chrome://inspect. You just do that, you type that in and it will load this up and you'll see anything that's inspecting in this case.
[00:13:02] Here's what I'm expecting exercises testing js. That's gonna be there. All of it is click inspect link, that's it. So once you click inspect link, you may or may not see files here. You may or may not see files, right, you probably don't see anything. Right, so what I normally do for that is I like to kick it off myself by going into my source code and adding a debugger statement somewhere.
[00:13:22] So once you add a debugger statement it's just gonna pop up right here. And then from there Chrome would like okay, I know your source files are all good. If you don't want to do that, you have to feed it yourself. You have to click on add folder to workspaces and feed it the files but that's just so much work.
[00:13:36] You're better off just like adding a debugger to kick it off and then go from there, yeah.