为什么在用RequireJS运行Mochatesting时看到“define not defined”?

我想了解如何开发独立的Javascript代码。 我想用testing和模块编写Javscript代码,从命令行运行。 所以我已经安装了node.jsnpm以及库requirejsunderscoremocha

我的目录结构如下所示:

 > 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就是testing:

 > 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) ... 

所以我的问题是:

  • 这是结构代码的正确方法吗?
  • 为什么我的testing不能运行?
  • 学习这种东西的最好方法是什么? 我很难用Googlefind很好的例子。

谢谢…

[抱歉 – 暂时张贴错误代码的结果; 现在修好]

PS我正在使用requirejs,因为我也想在以后的浏览器中运行这个代码(或其中的一部分)。

更新/解决scheme

下面的答案中没有的东西是我需要使用mocha -u tdd作为上面的testing样式。 这是最后的testing(也需要断言)和它的使用:

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

你的testing没有运行的原因是因为src/utils.js不是一个有效的Node.js库。

根据RequireJS文档,为了与Node.js和CommonJS require标准共存,需要在src/utils.js文件的顶部添加一些样板文件,以便加载RequireJS的define函数。

然而,因为RequireJS被devise为能够要求“经典的”面向Web浏览器的源代码,所以我倾向于使用下面的模式和我想在浏览器中运行的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中运行,你就可以开始testing了。 尽pipe它是后继testing框架,但我个人仍然比摩卡更喜欢expresso。

摩卡的文档缺乏如何设置这个东西,而这是令人费解的,因为它所做的所有魔术技巧。

我发现使用require.js在Mocha下的Node中获取浏览器文件的关键是:Mocha 必须使用addFile将文件添加到它的套件中:

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

其次,使用beforeEach和可选的callbackasynchronous加载你的模块:

 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); }); }); }); 

我创build了一个引导程序,以便如何使这一切工作: https : //github.com/clubajax/mocha-bootstrap

你试图运行为浏览器(AMD)devise的JS模块,但在后端可能无法正常工作(因为模块加载commonjs的方式)。 正因为如此,你将面临两个问题:

  1. 定义没有定义
  2. 0testing运行

在浏览器中define将被定义。 当你需要requirejs时,它会被设置。 但nodejs加载模块commonjs的方式。 在这种情况下定义没有定义。 但是当我们需要requirejs的时候它会被定义的!

这意味着现在我们需要asynchronous的代码,而且会带来第二个问题,即asynchronous执行的问题。 https://github.com/mochajs/mocha/issues/362

这是一个完整的工作示例。 看看我必须configurationrequirejs(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) }) }); }) 

对于你想testing的模块:

 > 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(); }) 

以防大卫的答案不够清楚,我只需要添加这个:

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

在RequireJS文档( “使用AMD或者RequireJS构build节点模块” )中所描述的js文件的顶部,在同一个文件夹中添加amdefine包:

 npm install amdefine 

这将在内部创build带有amdefine模块的node_modules文件夹。

我不使用requirejs所以我不确定这个语法是什么样的,但是这是我在nodebrowser运行代码的方法:

对于导入,请确定我们是在节点还是浏览器中运行:

 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 } 

然后,其他文件需要使用的任何function,我们将其导出到根目录:

 root.bar = Bar; 

例如, GitHub是一个很好的来源。 只要去看看你最喜欢的库的代码,看看他们是如何做到的:)我用mocha来testing一个JavaScript库,可以在浏览器和节点中使用。 代码可以在https://github.com/bunkat/later上find