簡體   English   中英

Node.js,Mocha,使閉包中的全局變量可用

[英]Node.js, Mocha, make globals in closures available

我目前正在使用Node設置一些mocha測試,一般來說它們都可以工作。 我現在遇到了一個我無法解決的問題。

我有一個包含以下內容的JS文件:MyClass.js( class MyClass + constructor: ->常規CoffeeScript輸出constructor: ->

編輯:這是瀏覽器代碼,我只想用Node來測試它。 (這甚至是可取的嗎?)

(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

我仍然得到同樣的錯誤。 任何想法都非常感謝!

你實際上並不想要窗口對象,你想要的是全局對象。 下面是一些可以在瀏覽器中獲取它的代碼(在這種情況下它將與'window'相同)或在節點中(在這種情況下它將與'global'相同)。

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

    }
});

由於您已經擁有不會污染全局名稱空間的范圍,因此可以將其減少為:

(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進行測試時,這應該是真的。

1)您正在尋找的是用於在Node中公開內容的module.exports

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

2)你也不需要Node中的IIFE,你可以刪除(function() {...

3)你總是可以在Github上查看一些流行的Node repo來查看示例,看看Mocha代碼,因為你正在使用它,你將學到一兩件事。

jsdom這樣的東西比PhantomJS輕,但提供了很多東西,你需要測試一些預期在適當的window運行的代碼。 我已經非常成功地使用它來測試在DOM樹中上下導航的代碼。

你問:

這是瀏覽器代碼,我只想用Node來測試它。 (這甚至是可取的嗎?)

這是非常可取的。 有一點像jsdom這樣的解決方案不會削減它,但只要你的代碼在jsdom處理的范圍內,就可以使用它並將啟動測試環境的成本保持在最低限度。

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM