我目前正在使用Node设置一些mocha测试,一般来说它们都可以工作。我现在遇到了一个我无法解决的问题。
我有一个包含以下内容的JS文件:MyClass.js
(class MyClass
+ constructor: ->
)的常规CoffeeScript输出
(function() {
window.MyClass = (function() {
function MyClass() {
// Do something cool here
}
return MyClass;
})();
}).call(this);
我现在在我的测试文件中需要MyClass.js。一旦我运行它,它会直接抛出错误
TESTFILE:
var myclass = require('MyClass.js');
...
describe('MyClass', function() { ... });
错误:
ReferenceError: window is not defined.
到目前为止,我理解为什么会发生这种情况,Node中不存在窗口。但我无法想出一个解决方案。我实际上并不特别需要真正的window
对象,所以我想嘲笑它就足够了。但它不是......
var window = {},
myclass = require('myclass.js');
...
describe('MyClass', function() { ... });
此命令也没有帮助:$ mocha --globals window
我仍然以同样的错误结束。 任何想法都非常感谢!
答案 0 :(得分:3)
您实际上并不想要窗口对象,您想要的是全局对象。以下是一些可以在浏览器中获取的代码(在这种情况下,它将与' window'相同)或在节点中(在这种情况下它将与' global&#39相同) ;)
var global = Function('return this')();
然后设置内容,而不是在'窗口上。
注意:还有其他获取全局对象的方法,但这样做的好处是它也可以在严格模式代码中运行。
答案 1 :(得分:2)
使用以下代码,您可以在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');
}
});
由于您已经有一个不会污染全局名称空间的范围,您可以将其缩小为:
(function (exports) {
function MyClass() {
// Do something cool here
}
exports(MyClass);
})(function (exported) {
// see above
});
我不是AMD,require.js和其他模块加载器的专家,但我认为应该很容易扩展这种模式以支持其他环境。
修改强>
在评论中,您说上述解决方案在转换回CoffeeScript时无效。因此,我建议另一种解决方案。我没有尝试过,但也许这可能是解决问题的方法:
global.window = {}; // <-- should be visible in your myclass.js
require('myclass.js');
var MyClass = global.window.MyClass;
describe('MyClass', function() {
var my = new MyClass();
...
});
这是一段可怕的代码,但如果它有效,可能出于测试目的就足够了。
由于node.js的模块加载行为,仅当您的require('myclass.js')
是节点进程中此文件的第一个要求时,此方法才有效。但是在使用Mocha进行测试时,这应该是真的。
答案 2 :(得分:1)
1)您正在寻找的是module.exports
来揭示Node中的内容:
http://openmymind.net/2012/2/3/Node-Require-and-Exports/
2)你也不需要Node中的IIFE,你可以删除(function() {...
3)你总是可以在Github上查看一些流行的Node repo来查看示例,看看Mocha代码,因为你正在使用它,你将学到一两件事。
答案 3 :(得分:1)
像jsdom这样的东西比PhantomJS轻,但是提供了一些测试代码的东西,这些代码需要运行正确的window
。我used it非常成功地测试了在DOM树中上下导航的代码。
你问:
这是浏览器代码,我只想用Node来测试它。 (这甚至是可取的吗?)
这是非常可取的。有一点像jsdom这样的解决方案不会削减它,但只要你的代码在jsdom处理的范围内,就可以使用它并将启动测试环境的成本保持在最低限度。
答案 4 :(得分:1)
@hgoebl:由于我不是OP,我无法添加他原来的CoffeeScript代码,但这是我的例子:
pubsub.coffee:
window.PubSub = window.PubSub || {}
PubSub.subscribe = ( subject, callback )->
现在测试:
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 )->
和测试:
`window = {}`
assert = require "assert"
pubsub = require './pubsub.coffee'
describe "pubsub.http interface", ->
it "should perform a http request", ->
window.PubSub.subscribe 1, 2
解决方案的主要缺点是,我必须在实现和测试中明确提到window对象。在浏览器中执行的用户代码应该能够省略它。
我现在想出了另一个解决方案:
window = window || exports
window.PubSub = window.PubSub || {}
PubSub = PubSub || window.PubSub
PubSub.subscribe = ( subject, callback )->
然后在测试中,只需要PubSub命名空间:
PubSub = require( './pubsub.coffee' ).PubSub
最后,kybernetikos应用的解决方案看起来像这样:
global = `Function('return this')()`
global.PubSub = global.PubSub || {}
PubSub.subscribe = ( subject, callback )->
现在,PubSub名称空间位于全局名称空间中,只需要包含mocha测试的文件中的简单需求:
require( './pubsub.coffee' )