2012-02-16 2 views
35

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

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

> 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, потому что я также хочу запустить этот код (или его часть) из браузера позже.

Update/Решение

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

> 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) 
+0

Для того, чтобы он работал, мне нужно установить модуль amdefine и добавить эту строку coffeescript = >> define = require ('amdefine') (module) if (typeof define! = 'Function') << = в мой файл «class», чтобы он работал (не тестовый файл). Это своего рода раздражает, так как нужно иметь задачу удалить это после тестирования – devric

ответ

15

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

Согласно документации RequireJS, чтобы сосуществовать с Node.js и CommonJS требует стандарт, вы должны add a bit of boilerplate в верхней части файла src/utils.js так загружен define функция RequireJS'S.

Однако, поскольку 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, вы можете начать тестирование. Я лично до сих пор предпочитаю экспрессу над моккой, хотя ее преемник тестирует рамки.

+1

спасибо! я не думаю, что вы также знаете, что мне нужно сделать, чтобы получить «набор» (от мокко), который нужно определить, так как с помощью шаблона мой тест теперь терпит неудачу? Кроме того, вы говорите, что «define» не будет работать для кода браузера? я не понимаю вашу мотивацию к альтернативному подходу выше - это «просто» вопрос стиля? –

+0

ах, я вижу вашу точку - вы не хотите определять содержимое узла для веб-браузеров. –

+0

Это не слишком сложно, вам не хватает шаблона '' require ('mocha') ''. Это взято прямо из уст лошади (https://github.com/visionmedia/mocha/blob/master/test/suite.js). (Я новичок в StackOverflow, не знал, что вы не можете иметь многострочный исходный код в комментариях.) –

-1

Я не использую 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.

4

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

Я нашел ключи, чтобы получить файлы браузера с помощью require.js работать в Мокко под Node: 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

+0

+1 для решения проблемы загрузки зависимостей requirejs в beforeEach – bennidi

1

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

  1. определяют не определен
  2. 0 тестов запустить

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

Это означает, что теперь мы требуем код асинхронно, и это приносит вторую проблему, проблему с выполнением async. 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

Только в случае David's answer не было достаточно ясно, мне просто нужно добавить следующее:

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

К началу из файла js, где я использую define, как описано в документах RequireJS ("Building node modules with AMD or RequireJS"), и в той же папке добавьте пакет amdefine:

npm install amdefine 

Это создает node_modules папку с amdefine модулем внутри.

 Смежные вопросы

  • Нет связанных вопросов^_^