Npm + Mocha + RequireJS

У меня есть время, пытаясь настроить node/npm с помощью Mocha и RequireJS. Вот что я сделал.

Я создал каталог testing/с этой структурой:

testing/
   |
   +-- package.json
   |
   +-- README.md
   |
   +-- test/
         |
         +-- mocha.opts
         |
         +-- widgets/
                |
                +--mywidget/
                       |
                       +-- test.js

Вот что каждый соответствующий файл содержит:

package.json:

{
    "name":"testing-project",
    "version":"2.5.0",
    "description":"Testing Project",
    "keywords":["test"],
    "engines": { "node": ">= 0.7.0 < 0.11.0" },
    "scripts" : {
        "test": "./node_modules/.bin/mocha"
    },
    "devDependencies": {
        "mocha": ">= 1.18.2",
        "requirejs": ">= 2.1.11",
        "should": ">= 3.2.0",
        "expect.js": ">= 0.3.1"
    }
}

тест/mocha.opts:

--require expect.js
--require should
--require requirejs
--require mocha
--reporter spec
--ui tdd
--recursive
--growl

тест/виджеты/MyWidget/test.js

'use strict';
var requirejs = require('requirejs');
// Also tried with:  require('../../../r.js')  which I downloaded from RequireJS' site

requirejs.config({
    baseUrl: '../../../../',
    nodeRequire: require
});

console.log('before require');
requirejs(['mywidget/trunk/src/mywidgetfile.js'], function(myObj){
    console.log('after require');

    var expect = require('expect.js');

    // Instead of the above "requirejs['mywidget..." line, I've also tried:
    // var myObj = requirejs('mywidget/trunk/src/mywidgetfile.js');   AND:
    // var myObj = requirejs('../../../../mywidget/trunk/src/mywidgetfile.js');

    describe('My Widget', function(){
        describe('my-widget#getInfo', function(){

            it('should pass this test', function(done){
                expect( myObj.returnString('test') ).to.equal( 'test' );

                done();
            })
        })
    });
});
console.log('done');

Он выведет строки консоли "before require" и "done", но до тех пор, пока у меня есть requirejs (['mywidget... line in, он не попадет после запроса. Если я удалю строку requirejs (и соответствующую строку закрытия/рамки), и вместо этого используйте прямую строку "var myObj =", я получаю "не могу найти модуль", и если я использую вторую строку "var myObj", я получаю "Reference Error: define не определено".

Я пытаюсь упаковать все это для удобства для других разработчиков с помощью npm, так что я запускаю команду "npm test" из верхнего каталога "testing/".

Я искал ответы и много чего делал, но, похоже, мне не нужен файл с использованием RequireJS и определение "define()". Я могу выполнить тесты, это не проблема... он просто пытается вставить RequireJS в микс, который возникает, когда у меня возникают проблемы.

Любая помощь будет огромной!

Спасибо!

Ответ 1

В том, что вы показываете нам, происходит множество проблем. Вы неправильно используете как RequireJS, так и Mocha.

RequireJS

Я уверен, что ваш baseUrl неверен. Кажется, вы думаете, что текущий рабочий каталог Mocha будет установлен на test/widgets/mywidget/, когда он выполнит тесты в test/widgets/mywidget/test.js. Это не так. Рабочий каталог находится где угодно, когда вы запускаете npm test. Согласно вашему описанию вы находитесь в testing/ при запуске. Мне непонятно, какова ценность вашего baseUrl, потому что вы не предоставляете достаточно информации в своем вопросе, но я надеюсь, что из объяснения, которое я вам дал, вы можете понять.

Теперь вы можете подумать: "Конечно, мой baseUrl правильный, потому что, когда я выполняю requirejs(['mywidget/trunk/src/mywidgetfile.js'], function(myObj){, я не получаю ошибку". Это было бы неправильным выводом. Хотя этот вызов requirejs предусматривает загрузку вашего модуля, RequireJS не получает возможность попробовать его загрузить, потому что Mocha выходит, прежде чем RequireJS попытается загрузить его. Вы можете проверить это, заменив путь вашего модуля на полный мусор, и вы не получите ошибку.

После устранения этой проблемы baseUrl использование var myObj = requirejs('mywidget/trunk/src/mywidgetfile.js') будет работать так, как вы ожидаете. Таким образом, вы сможете избежать использования асинхронной формы require (это форма, которая использует массив зависимостей в качестве первого аргумента). (Функция requirejs, которую вы используете, является просто псевдонимом для функции, обычно называемой require в документации RequireJS.)

Мокко

Ваши тесты не выполняются, потому что Mocha их не видит. Способ работы Mocha - это прочитать все тестовые файлы, которые он находит, а затем выполнить их. Обратные вызовы для каждого вызова describe выполняются сразу, а обратные вызовы к каждому вызову it записываются как тесты, которые нужно запустить. Как только Mocha закончит выяснять, какие тесты существуют, он запускает их.

Что происходит с вашим тестовым файлом, так это то, что Mocha выполняет его, как обычно. Однако в верхней части тестового файла нет вызова describe или it. В вашем обратном вызове есть вызовы requirejs, но помните, что я сказал выше: RequireJS не получает возможность загрузить модуль, чтобы он не получал возможность запустить обратный вызов. (И даже если бы это запустило его, было бы слишком поздно.) Таким образом, Моча не видит никаких тестов и выходов сразу.

Путь вперед

Выясните baseUrl, который вам нужен, и тогда это должно работать:

'use strict';
var requirejs = require('requirejs');

requirejs.config({
    baseUrl: <whatever value is needed here>,
    nodeRequire: require
});

var myObj = requirejs('mywidget/trunk/src/mywidgetfile.js');

describe('My Widget', function() {
// etc...

Возможно, вы также захотите полностью отказаться от RequireJS из своего тестового набора. Я написал библиотеку, которая также работает в Node, как в браузере. Он состоит из модулей AMD и загружен RequireJS в браузере, но я не использую RequireJS в наборе тестов. Это loader Я использую для загрузки своих модулей в Node. Там также amdefine, который я не использовал, но должен давать аналогичные возможности.