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