mochaとnodelint

mochaを使ってみようと思って、

describe('Array', function(){
  describe('#indexOf()', function(){
    it('should return -1 when the value is not present', function(){
      [1,2,3].indexOf(5).should.equal(-1);
      [1,2,3].indexOf(0).should.equal(-1);
    })
  })
})

のようなテストを用意してみたら、nodelintに怒られる。

$ nodelint sample.js
The "sys" module is now called "util". It should have a similar interface.
sample.js, line 1, character 1: 'describe' was used before it was defined.
describe('Array', function(){
sample.js, line 3, character 5: 'it' was used before it was defined.
it('should return -1 when the value is not present', function(){
2 errors

"describe"とか"it"がどこにも宣言されていないので当然っちゃ当然。
自分はnodelintの結果をflymakeでhighlightさせるようにしているので、こういうのが出ると結構困る。
nodelintでflymake - すぎゃーんメモ


で、そもそもこのtestファイルはどう扱われるのか?bin/mochaを覗いてみると、

function load(files, fn) {
  var pending = files.length;
  files.forEach(function(file){
    delete require.cache[file];
    suite.emit('pre-require', global, file);
    suite.emit('require', require(file), file);
    suite.emit('post-require', global, file);
    --pending || fn();
  });
}

というあたりで"pre-require"イベントをemitしたあとで、requireされているのが分かる。lib/interfaces/bdd.jslib/interfaces/tdd.jsでは、"pre-require"を受け取ったときに引数で渡されたglobalオブジェクトにそれぞれで使う関数を登録してやっている。事前にこういう処理を挟んでおくことで、testファイルがrequireされても正常に動く、ということらしい。

なので、実際に読まれるのはglobalから生えた関数たちなので、

global.describe('Array', function(){
  global.describe('#indexOf()', function(){
    global.it('should return -1 when the value is not present', function(){
      [1,2,3].indexOf(5).should.equal(-1);
      [1,2,3].indexOf(0).should.equal(-1);
    });
  });
});

とか

var describe = global.describe;
var it = global.it;

describe('Array', function(){
  describe('#indexOf()', function(){
    it('should return -1 when the value is not present', function(){
      [1,2,3].indexOf(5).should.equal(-1);
      [1,2,3].indexOf(0).should.equal(-1);
    });
  });
});

とかいう具合に書いておけばtestの効果は変わらず、nodelintに警告されることもなく済む。


他にもっと良い方法は無いだろうか…