Mocha + RequireJS = тестирование AMD

Мне сложно подключиться к Mocha для приложения на основе RequireJS, возможно, вы сможете что-то придумать:). После многих часов, когда я пытался загрузить модули AMD и просто console.log, некоторые "уволенные" данные о том, что модуль загружен... ничего не случилось - программа только что закончилась и распечатала некоторую информацию о мокке.

var facade = requirejs(['../../public/js/scripts/widgets/widgets/article/main.js'],      
    function(mod) {
        console.log('fired')
});
// run with: $ mocha -u tdd test.js --reporter spec

и я придумал, как это сделать, чтобы проверить обратные вызовы:

setTimeout((function() {
    console.log('fired');
}), 5000);
// run with: $ mocha -u tdd test.js --reporter spec

тоже не работает. Итак, наконец, я запустил оба с

$ node test.js 

и, наконец, это сработало. Итак, вопрос: Как запустить тест Mocha с обработкой обратных вызовов, поскольку они необходимы для тестирования AMD?

Ответ 1

Как вы это делаете, mocha не собирается ничего делать с вашим файлом, потому что он не видит в нем набор тестов. Требовать JS планируется вызвать обратный вызов, но mocha выйдет, прежде чем это может произойти. То же самое с вашим примером тайм-аута.

Ниже приведен пример.

Файл test.js:

'use strict';
var requirejs = require("requirejs");
requirejs.config({
    baseUrl: '.',
    nodeRequire: require
});

suite('Something', function(){
    var foo;

    suiteSetup(function (done){
        // This saves the module foo for use in tests. You have to use
        // the done callback because this is asynchronous.
        requirejs(['foo'],
                  function(mod) {
            console.log("fired!");
            foo = mod;
            done();
        });
    });

  suite('blah', function(){
    test('blah', function(){
      if (foo.test !==  "test")
          throw new Error("failed!");
    });
  });
});

Файл foo.js:

define(function () {
   return {test: "test"};
});

При запуске:

mocha -u tdd test.js

Вы увидите, что обратный вызов запущен и тест проходит.

Для людей, которые читают этот вопрос и путают использование suite, suiteSetup, test... Mocha поддерживает несколько интерфейсов. Код здесь использует интерфейс TDD (OP вызывает Mocha с -u tdd), который экспортирует suite, suiteSetup, test и т.д. В интерфейсе BDD по умолчанию эквиваленты describe, before и it соответственно.

Ответ 2

Я сконфигурировал соответствующий шаблон для использования мокко в среде RequireJS. Это может быть не совсем то, что вы хотите, но это может быть полезно. https://github.com/x2es/boilerplate-karma-mocha-chai-requirejs

Еще одно замечание - если ваш script размещен в "/public", имеет смысл протестировать его в среде браузера вместо nodejs. Для этого вам нужно посмотреть на какого-нибудь тестирователя, такого как JsTestDriver (https://code.google.com/p/js-test-driver/) или карма-бегун (http://karma-runner.github.io/). Или другое...

В сжатом виде в документации по карме (http://karma-runner.github.io/0.8/plus/RequireJS.html)

var tests = [];
for (var file in window.__karma__.files) {
  if (window.__karma__.files.hasOwnProperty(file)) {
    if (/Spec\.js$/.test(file)) {
      tests.push(file);
    }
  }
}

requirejs.config({
    // Karma serves files from '/base'
    baseUrl: '/base/src',

    paths: {
        'jquery': '../lib/jquery',
        'underscore': '../lib/underscore',
    },

    shim: {
        'underscore': {
            exports: '_'
        }
    },

    // ask Require.js to load these files (all our tests)
    deps: tests,

    // start test run, once Require.js is done
    callback: window.__karma__.start
});

когда мы вынуждаем requirejs предварительно загружать все необходимые spec файлы, используя

require.config({
  deps: ['array', 'of', 'our', 'spec', 'files']
})

В этой среде каждый spec файл должен быть регулярным модулем RequireJS.

Пример спецификации теста для такой среды:

define(['chai'], function(chai) {
  var expect = chai.expect;

  describe('bootstrap', function() {
    it('should...', function() {
      expect('a').to.equal('a');
    });
  });
});