Node.js,Mocha,使封闭的全局variables可用

我目前正在使用Node设置一些摩卡testing,一般来说,它们都可以工作。 我现在遇到了一个我无法解决的问题。

我有一个JS文件,其中包含以下内容:MyClass.js( class MyClass + constructor: ->常规CoffeeScript输出constructor: ->

编辑:这是浏览器代码,我只是想使用节点来testing它。 (这甚至是可取的?)

 (function() { window.MyClass = (function() { function MyClass() { // Do something cool here } return MyClass; })(); }).call(this); 

我现在在我的testing文件中需要MyClass.js。 一旦我运行它,它直接抛出一个错误

TESTFILE:

 var myclass = require('MyClass.js'); ... describe('MyClass', function() { ... }); 

错误:

 ReferenceError: window is not defined. 

到目前为止,我明白为什么会发生这种情况,Node中不存在窗口。 但我不能想出一个解决scheme。 我其实并不需要真正的window对象,所以我认为嘲笑它就足够了。 但是这不是…

 var window = {}, myclass = require('myclass.js'); ... describe('MyClass', function() { ... }); 

这个命令也没有帮助: $ mocha --globals window

我仍然有同样的错误。 任何想法都非常感谢!

你实际上不需要窗口对象,你想要的是全局对象。 这里有一些代码可以在浏览器中获得(在这种情况下,它将与“窗口”相同)或节点(在这种情况下,它将与“全局”相同)。

 var global = Function('return this')(); 

然后设置一下,而不是在“窗口”上。

注意:获取全局对象还有其他方法,但是这样做的好处是可以在严格的模式代码中工作。

通过以下代码,您可以在Web浏览器环境和Node.js中使用类对象,而无需修改。 (对不起,我不知道如何把它翻译成CoffeeScript)

 (function (exports) { var MyClass = (function() { function MyClass() { // Do something cool here } return MyClass; })(); exports(MyClass); })(function (exported) { if (typeof module !== 'undefined' && module.exports) { module.exports = exported; } else if (typeof window !== 'undefined') { window.MyClass = exported; } else { throw new Error('unknown environment'); } }); 

由于您已经有了一个不污染全局名称空间的范围,因此您可以将其减less到:

 (function (exports) { function MyClass() { // Do something cool here } exports(MyClass); })(function (exported) { // see above }); 

我不是AMD,require.js和其他模块加载器方面的专家,但我认为应该很容易扩展这种模式来支持其他环境。

编辑

在一个评论中,你说上面的解决scheme在翻译回CoffeeScript时不起作用。 因此,我build议另一个解决scheme。 我还没有尝试过,但也许这可能是解决您的问题的一种方法:

 global.window = {}; // <-- should be visible in your myclass.js require('myclass.js'); var MyClass = global.window.MyClass; describe('MyClass', function() { var my = new MyClass(); ... }); 

这是一段很糟糕的代码,但是如果它能够正常工作,那么为了testing的目的就足够了。

由于node.js的模块加载行为,这只有在您的require('myclass.js')是节点进程中该文件的第一个需求时才有效。 但在摩卡testing的情况下,这应该是真实的。

1)你正在寻找的是module.exports暴露的东西在节点:

http://openmymind.net/2012/2/3/Node-Require-and-Exports/

2)你也不需要节点的IIFE,你可以删除(function() {...

3)你可以看看Github上的一些stream行的Node repo来看例子,看看你使用的Mocha代码,你会学到一两件事。

像jsdom这样的东西比PhantomJS更轻,但是还提供了很多东西,你需要testing那些希望用适当的window运行的代码。 我已经使用它成功地testing了在DOM树中上下导航的代码。

你问:

这是浏览器代码,我只是想用Node来testing它。 (这甚至是可取的?)

这是非常可取的。 有一点像jsdom这样的解决scheme不会削减它,但只要你的代码是在jsdom处理的极限内,就可以使用它,并保持启动一个testing环境所需的最低成本。

@hgoebl:因为我不是OP,我不能添加他原来的CoffeeScript代码,但这里是我的例子:

pubsub.coffee:

 window.PubSub = window.PubSub || {} PubSub.subscribe = ( subject, callback )-> 

现在testing:

 assert = require "assert" pubsub = require './pubsub.coffee' describe "pubsub.http interface", -> it "should perform a http request", -> PubSub.subscribe 1, 2 

到目前为止,对我而言,

 window.PubSub = window.PubSub || {} window.PubSub.subscribe = ( subject, callback )-> 

和testing:

 `window = {}` assert = require "assert" pubsub = require './pubsub.coffee' describe "pubsub.http interface", -> it "should perform a http request", -> window.PubSub.subscribe 1, 2 

解决scheme的主要缺点是我必须在实现和testing中明确提及窗口对象。 在浏览器中执行的用户代码应该可以忽略它。

我现在想出了另一个解决scheme:

 window = window || exports window.PubSub = window.PubSub || {} PubSub = PubSub || window.PubSub PubSub.subscribe = ( subject, callback )-> 

然后在testing中,只需要PubSub命名空间:

 PubSub = require( './pubsub.coffee' ).PubSub 

最后,应用kybernetikos的解决scheme如下所示:

 global = `Function('return this')()` global.PubSub = global.PubSub || {} PubSub.subscribe = ( subject, callback )-> 

和现在一样,PubSub命名空间位于全局命名空间中,只是在包含mochatesting的文件中需要一个简单的需求:

 require( './pubsub.coffee' )