Lesson Sunday

Now that we've installed VSCode's Jest extension, let's introduce a bug in our shape-tracker application. Then we'll use our new extension in tandem with VSCode to debug the issue.

Someone has inadvertently added a bug to our code and our tests are a mess. To follow along, update the source code to look like this:

src/triangle.js
export default function Triangle(side1, side2, side3) {
  this.side1 = side1;
  this.side2 = side2;
  this.side3 = side2;
}

Triangle.prototype.checkType = function() {
  if ((this.side1 > (this.side2 + this.side3)) || (this.side2 > (this.side1 + this.side3)) || (this.side3 > (this.side1 + this.side2))) {
    return "not a triangle";
  } else if ((this.side1 !== this.side2) && ((this.side1 !== this.side3)) && ((this.side2 !== this.side3))) {
    return "scalene triangle";
  }  else if ((this.side1 === this.side2) && (this.side1 === this.side3)) {
    return "equilateral triangle";
  } else {
    return "isosceles triangle";
  }
};

It's a simple bug - and you may already see it - but the process for debugging in VSCode will be the same regardless.

First, take a look at Jest in the blue bar at the bottom of the screen.

Jest test suite is now failing.

There's a new icon - an exclamation point in a triangle along with the information 1 test suite failed.

We can click Jest in the blue bar to bring up our tests and get a little more information. Four of our five tests in our test suite are failing.

4 of 5 tests are failing now.

Now let's take a look at triangle.test.js in VSCode. Here's one of our broken tests.

A broken test in VSCode.

There are several new things here, all courtesy of the Jest extension.

  • Each broken test has the word Debug above it. We can click this to activate the debugging process.
  • Broken tests now have a red X instead of a check mark.
  • Each failed expectation has a red line underneath it. Since our tests will generally have a single expectation, this usually won't provide much information. However, since this test has three expectations, it's helpful to see that just the third expectation is failing.

Before we actually start debugging, let's take a look at the tools in the left-hand pane of Run and Debug. If the pane is collapsed or showing something other than the Run and Debug pane, remember that you can open this pane by clicking the following icon:

The run and debug icon.

Now let's look at the options in this pane. In the image, the windows in the pane are folded (except for the last one).

The lefthand pane of run and debug.

Let's quickly go over each of these.

  • Variables will show us the values of all the variables currently in scope when we are paused in debugging. This is super useful - so keep an eye on this pane and keep it open.
  • Watch allows us to specify specific variables that we'd like to watch as they change. This is similar to the Watch option in Chrome DevTools. It's also very useful and we'll use it more in just a moment.
  • Call Stack shows the call stack - all the code that has been called to execute the code where we're paused. The information here can be overwhelming, especially since it will often go deep in the call stack beyond our code (to external libraries and so on). However, we can click and expand other items in the call stack to get more information. We won't be covering this functionality further in this lesson, but we encourage you to keep the window open and take a look.
  • Breakpoints allows us to add breakpoints on caught and uncaught exceptions - just as we can do in Chrome DevTools! We can also add a breakpoint on a function by name by clicking the + icon to the right of Breakpoints and then specifying a function name:

Add a breakpoint to a function by the function's name.

Important note: If you don't see caught and uncaught exceptions listed under breakpoints, you can select vscode-jest-tests in the dropdown by RUN at the top left of the screen. Then click the green play icon.

Click the green play icon by vscode-jest-tests.

Finally, the Breakpoints pane is very helpful because it will keep track of all the breakpoints in our code. We'll cover this more in just a moment.

Now we're ready to start debugging. If we click Debug above one of our broken tests, the Node Debug Console will automatically open in the bottom pane. The tests will run again, which isn't particularly useful. That's because the code is executing without pausing. We need to add a breakpoint to make this useful.

We can add breakpoints to a line by clicking on the line number. When we add a breakpoint, a red dot will show up to the left of the line number - just like in Chrome DevTools. Go ahead and try adding a breakpoint to a line. Now check out the the Breakpoints pane.

Breakpoints have been added to the Breakpoints pane.

Two breakpoints have been added to the source code (in different files) and they've both been added to Breakpoints. We see the file and directory the breakpoint is in as well as the line number. If the breakpoint is active, there will be a red dot. If it's not, there will be a gray dot. We can click the checkbox by a breakpoint to deactivate (or reactivate) it. We can also click the overlapping circles icon in the upper right corner to activate or deactivate all breakpoints. Finally, we can click the overlapping squares with an X in the upper right corner to remove all breakpoints.

This is super helpful for giving us granular control over our breakpoints when we are debugging, especially when we have breakpoints in multiple files. We can quickly try one breakpoint and then another and then both simultaneously without having to toggle between files and updating the breakpoints manually.

Let's also watch some variables. At this point, with the third expectation in our constructor test being broken, it's safe to surmise that the error might be in the constructor itself.

In the GIF below, we navigate to triangle.js and determine which variables and properties we want to watch.

We look at the constructor code and then pick out some values to watch.

First, we'll want to check the value of the parameter side3. Note that this parameter is grayed-out. When a variable or parameter is grayed out in VSCode, that means it's not being used in our code. Well, that's a strong hint that this.side3 doesn't correctly correspond to the side3 parameter!

Assuming we can't see this bug yet, though, we're going to watch the value of side3 and and this.side3 - and verify that they don't match.

In the GIF below, we add breakpoints to line 5 of triangle.js and line 9 of triangle.test.js. Then we go through the debugging process.

Code now pauses execution when we click Debug.

To follow along, you should have breakpoints in the same places. We click Debug above the constructor test. Our code pauses at the breakpoint in line 5 of triangle.js. Note that this breakpoint is hit before the one in our test. This makes complete sense because our test instantiates a triangle and uses the constructor before it reaches the expectation. It's often useful to have breakpoints in both tests and source code, but if you are running them simultaneously, make sure to keep track of the order the breakpoints run in to avoid confusion. Or simply use the nifty Breakpoints pane to deactivate breakpoints if needed.

As the GIF above shows, when the code is paused, both the Variables and Watch pane are populated with values. The Variables pane shows all the variables that are in scope while the Watch pane shows the values we specifically want to watch - in this case side3 and this.side3.

The error was already pretty obvious, but now it's especially so:

this.side3 = side2;

The value of side3 doesn't match this.side3. Instead, side2 and this.side3 match. The variable on the right side needs to be updated to side3.

We don't need to do further debugging for this particular error, but the GIF above shows one other important detail. We can also open the Debug Console in the lower pane to try out code in the current scope.

To do so, click the three dots in the lower pane and select Debug Console as the image below shows.

Click on the three dots in the lower pane and select _Debug Console_.

This is very similar to the console in Chrome DevTools and it's a great way to experiment with and run code in the paused scope.

Now that we solved the issue, how do we get out of the paused scope? When we are debugging, there's a toolbar at the top of the screen that looks very similar to the one when we are paused in Chrome.

The control bar has six icons.

  • The Play icon on the left resumes execution of the code.
  • The next icon is Step Over, which allows us to step through code just as we do in Chrome Dev Tools.
  • The third and fourth icons allow us to Step In and Step Out of functions, which is helpful if we want to jump to the next function instead of just to the next line.
  • The Restart icon restarts the debugging process so we can start from scratch.
  • Finally, the Stop icon stops the debugging process altogether.

As we can see, VSCode's Jest extension is a powerful tool that allows us to quickly and continuously run and debug our tests. We don't even need to run our tests in the terminal. This is faster and more efficient - and making our workflow easier and more efficient is a great way to reduce our stress levels and make us better developers.


Example GitHub Repo for Shape Tracker

Make sure to use the second commit titled "full testing of Triangle with Jest" as your point of reference.

Lesson 32 of 43
Last updated October 18, 2021