DailyJS

DailyJS

The JavaScript blog.


Tagtechniques
Featured

testing techniques node modules

Debugging with Mocha

Posted on .

I do a lot of work with Mocha, because I like to write well-tested Node projects. Sometimes there are things I just can't figure out non-interactively, and that's when I reach for the debugger. It's a lot better than repeatedly running tests with more and more console.log statements.

Rather than using any extra Mocha extensions, I find Node's standard debugger works great. With Mocha you access it by running your tests in debug mode:

mocha debug  

The debug option works just like node debug file.js. Node's debugger comes from V8, which has a built-in JSON-based protocol that supports communication with a live process using TCP. That means you're not limited to Node's command-line tools: the fancy GUI debugger in Chrome can be used instead.

Debugging a Failing Test

To debug a failing test, look at the stack trace to figure out a good place to add a breakpoint. I usually put them in test cases, just before a failing assertion, but you can put them anywhere in the program.

Breakpoints are added by inserting debugger on a single line by itself. Once you've strategically placed some breakpoints, run the tests with mocha debug.

Whenever you run mocha debug or node debug, you'll be dropped into the debugger on the first line of the program. Type c to allow the tests to continue until the first debugger statement is encountered -- there may be a delay after you issue the continue command, so be patient. After that the program will run until a breakpoint is hit, at which point you'll be dropped into a prompt.

Debugger Commands

The commands are like gdb or lldb for the most part -- if you've used another debugger before you should be able to figure out what's going on. If not, there are three main commands that will get you started:

  • s: Step into code
  • n: Run the next line without stepping into it if it's a function/method call
  • repl: Enter a REPL, which we mainly use for printing values and objects

As I have some experience with other debuggers, I found it took me a while to get used to typing repl: in most debuggers there's a specific command for printing and formatting values or locations in memory. This REPL mode is exited by typing CTRL-C once. While you're in the REPL, you can type the name of a value or object to see it: this is usually how I fix most of the problems in my tests.

Other Thoughts

I haven't found a way to automatically drop into a debugger when an assertion fails. I'd really like to do this -- it would be a bit like how IDEs work, but I'm not sure if it's possible.

Featured

codereview techniques

Using Vars to Shortcut Namespaces

Posted on .

When I was researching the last turing.js
framework
article I came
across a simple technique for namespace shortcuts in TJ Holowaychuk's
jspec. I haven't noticed it used very often, so I thought DailyJS hackers may find it interesting.

;(function() {
  MyClass = {
    map: function(object, callback) {
      var items = [];
      each(object, function(i) { items.push(callback.apply(this, arguments)); });
      return items;
    },

    each: function(object, callback) {
      for (var i = 0; i < object.length; i++) {
        callback(i);
      }
    }
  }

  var methods = 'each map'.split(/ /);
  while (methods.length) { eval('var ' + methods[0] + ' = MyClass.' + methods.shift()); }
})();

// Map can refer to each without dereferencing
result = MyClass.map([1, 2, 3], function(i) {
  return i + 1;
});

print(result);
// 1,2,3

Ignore the implementations of each and map and
look at the loop after MyClass.

What happens here is a list of methods are mapped to vars so they can be
referenced without their containing object name.

  1. MyClass is declared globally
  2. Methods within the containing anonymous function can refer to
    hand-picked "utility" methods without referring to MyClass
  3. These methods are declared as local variables using
    eval
  4. The while loop iterates over each method name

Notice that the loop refers to each method using
methods[0], then methods.shift() when it's
no longer needed, which keeps the loop control simple.

This is useful if you want to cut down code inside a library. It's safe
because the shortcuts are bound to the anonymous function, but novices
may find navigating the code difficult. Tracking down where
each comes from in a big project might be difficult, so
avoid this technique if you're working on a large project with
colleagues with mixed skills.

This is flexible way of achieving similar results to with: