Почему при запуске теста Mocha с RequireJS отображается сообщение «определение не определено»? - PullRequest
38 голосов
/ 16 февраля 2012

Я пытаюсь понять, как разработать автономный код Javascript.Я хочу написать код Javscript с тестами и модулями, запущенными из командной строки.Поэтому я установил node.js и npm вместе с библиотеками requirejs, underscore и mocha.

Моя структура каталогов выглядит следующим образом:

> tree .
.
├── node_modules
├── src
│   └── utils.js
└── test
    └── utils.js

где src/utils.js - это небольшой модуль, который я пишу, со следующим кодом:

> cat src/utils.js 
define(['underscore'], function () {

    "use strict";

    if ('function' !== typeof Object.beget) {
        Object.beget = function (o) {
            var f = function () {
            };
            f.prototype = o;
            return new f();
        };
    }

});

и test/utils.js - это тест:

> cat test/utils.js 
var requirejs = require('requirejs');
requirejs.config({nodeRequire: require});

requirejs(['../src/utils'], function(utils) {

    suite('utils', function() {
        test('should always work', function() {
            assert.equal(1, 1);
        })
    })

});

, который я затем пытаюсь запуститьиз каталога верхнего уровня (поэтому mocha видит каталог test):

> mocha

node.js:201
        throw e; // process.nextTick error, or 'error' event on first tick
              ^
Error: Calling node's require("../src/utils") failed with error: ReferenceError: define is not defined
    at /.../node_modules/requirejs/bin/r.js:2276:27
    at Function.execCb (/.../node_modules/requirejs/bin/r.js:1872:25)
    at execManager (/.../node_modules/requirejs/bin/r.js:541:31)
    ...

Итак, мои вопросы:

  • Это правильный способ структурировать код?
  • Почему мой тест не выполняется?
  • Как лучше всего научиться этому?Я с трудом нахожу хорошие примеры в Google.

Спасибо ...

[извините - на мгновение выложил результаты из неверного кода;исправлено сейчас]

PS Я использую requirejs, потому что позже я также хочу запустить этот код (или его часть) из браузера.

Обновление / Решение

Что-то, чего нет в ответах ниже, это то, что мне нужно было использовать mocha -u tdd для тестового стиля выше.Вот последний тест (который также требует подтверждения) и его использование:

> cat test/utils.js 

var requirejs = require('requirejs');
requirejs.config({nodeRequire: require});

requirejs(['../src/utils', 'assert'], function(utils, assert) {

    suite('utils', function() {
        test('should always work', function() {
            assert.equal(1, 1);
        })
    })

});
> mocha -u tdd

  .

  ✔ 1 tests complete (1ms)

Ответы [ 5 ]

18 голосов
/ 16 февраля 2012

Причина, по которой ваш тест не выполняется, заключается в том, что src/utils.js не является допустимой библиотекой Node.js.

В соответствии с документацией RequireJS, чтобы сосуществовать с Node.js и CommonJSтребуется стандарт, вам нужно добавить немного шаблона в начало вашего src/utils.js файла, чтобы была загружена функция RequireJS define.

Однако, поскольку RequireJS был разработан длячтобы требовать «классический» исходный код, ориентированный на веб-браузер, я склонен использовать следующий шаблон с моими библиотеками Node.js, которые я также хочу запускать в браузере:

if(typeof require != 'undefined') {
    // Require server-side-specific modules
}

// Insert code here

if(typeof module != 'undefined') {
    module.exports = whateverImExporting;
}

Преимущество в том, что не требуетсядополнительная библиотека для других пользователей Node.js и в целом хорошо работает с RequireJS на клиенте.

Как только вы запустите свой код в Node.js, вы можете начать тестирование.Лично я все еще предпочитаю expresso, а не mocha, хотя это тестовый фреймворк.

5 голосов
/ 17 марта 2013

В документации Mocha отсутствует информация о том, как настроить этот материал, и его сложно понять из-за всех волшебных уловок, которые он делает под капотом.

Я нашел ключи для получения файлов браузера с помощью require.js для работы в Mocha под узлом: Mocha имеет для добавления файлов в свои наборы с addFile:

mocha.addFile('lib/tests/Main_spec_node');

И во-вторых, используйте beforeEach с дополнительным обратным вызовом для асинхронной загрузки ваших модулей:

describe('Testing "Other"', function(done){
    var Other;
    beforeEach(function(done){
        requirejs(['lib/Other'], function(_File){
            Other = _File;
            done(); // #1 Other Suite will run after this is called
        });
    });

    describe('#1 Other Suite:', function(){
        it('Other.test', function(){
            chai.expect(Other.test).to.equal(true);
        });
    });
});

Я создал загрузчик, чтобы заставить все это работать: https://github.com/clubajax/mocha-bootstrap

1 голос
/ 11 мая 2017

Вы пытаетесь запустить модули JS, предназначенные для браузеров (AMD), но в бэкэнде это может не сработать (так как модули загружаются способом commonjs). Из-за этого вы столкнетесь с двумя проблемами:

  1. определение не определено
  2. 0 тестовых прогонов

В браузере будет определено define. Это будет установлено, когда вам потребуется что-то с requirejs. Но nodejs загружает модули обычным способом. define в этом случае не определяется. Но это будет определено, когда нам потребуется с помощью requirejs!

Это означает, что теперь нам требуется асинхронный код, и это приносит вторую проблему - проблему с асинхронным выполнением. https://github.com/mochajs/mocha/issues/362

Вот полный рабочий пример. Посмотрите, что мне пришлось настроить requirejs (amd) для загрузки модулей, мы не используем require (node ​​/ commonjs) для загрузки наших модулей.

> cat $PROJECT_HOME/test/test.js

var requirejs = require('requirejs');
var path = require('path')
var project_directory = path.resolve(__dirname, '..')

requirejs.config({
  nodeRequire: require, 
  paths: {
    'widget': project_directory + '/src/js/some/widget'
  }
});

describe("Mocha needs one test in order to wait on requirejs tests", function() {
  it('should wait for other tests', function(){
    require('assert').ok(true);
  });
});


requirejs(['widget/viewModel', 'assert'], function(model, assert){

  describe('MyViewModel', function() {
    it("should be 4 when 2", function () {
        assert.equal(model.square(2),4)
    })
  });

})

А для модуля, который вы хотите проверить:

> cat $PROJECT_HOME/src/js/some/widget/viewModel.js

define(["knockout"], function (ko) {

    function VideModel() {
        var self = this;

        self.square = function(n){
            return n*n;
        }

    }

    return new VideModel();
})
0 голосов
/ 21 августа 2017

На всякий случай Ответ Дэвида был недостаточно ясен, мне просто нужно добавить это:

if (typeof define !== 'function') {
    var define = require('amdefine')(module);
}

В начало файла js, где я использую define, так какописано в RequireJS docs ( "Создание модулей узлов с AMD или RequireJS" ) и в той же папке добавьте пакет amdefine:

npm install amdefine

Это создаст папку node_modulesamdefine модуль внутри.

0 голосов
/ 16 февраля 2012

Я не использую requirejs, поэтому я не уверен, как выглядит этот синтаксис, но это то, что я делаю для запуска кода как внутри node, так и browser:

Дляимпорт, определите, работаем ли мы в узле или браузере:

var root =  typeof exports !== "undefined" && exports !== null ? exports : window;

Тогда мы можем правильно захватить любые зависимости (они будут уже доступны, если в браузере или мы используем require):

var foo = root.foo;
if (!foo && (typeof require !== 'undefined')) {
    foo = require('./foo');
}

var Bar = function() {
    // do something with foo
}

И затем, для любой функциональности, которая должна использоваться другими файлами, мы экспортируем ее в корневой каталог:

root.bar = Bar;

Что касается примеров, GitHub - отличный источник.Просто зайдите и посмотрите код вашей любимой библиотеки, чтобы увидеть, как они это сделали :) Я использовал mocha, чтобы протестировать библиотеку javascript, которую можно использовать как в браузере, так и в узле.Код доступен на https://github.com/bunkat/later.

...