2013-12-19 2 views
8

В настоящее время я устанавливаю некоторые тесты мокко с использованием узла и вообще они работают. Я столкнулся с проблемой, которую я не могу решить.Node.js, Mocha, make globals in closures available

У меня есть файл JS, содержащий следующее: MyClass.js (Общий CoffeeScript выход для class MyClass + constructor: ->)

EDIT: Это код браузера, я просто хочу, чтобы использовать узел, чтобы проверить его. (Это даже желательно?)

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

До сих пор, я понимаю, почему это происходит, окно не существует в узле. Но я не могу придумать решение. Я действительно не нуждаюсь в реальном объекте window специально, поэтому я думал, что насмехается, этого будет достаточно. Но это не так ...

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

Эта команда также не помогает: $ mocha --globals window

Я до сих пор в конечном итоге с той же ошибкой. Любая идея очень ценится!

+0

Почему именно вам нужен объект окна? – Simon

+0

В противном случае я не смог бы позвонить ему из другого места, поскольку он завернут. MyClass сам создан для браузера, хотя я просто думал об использовании Node для его проверки (я также пытался использовать jsdom или что-то подобное, но я тоже не смог) – pabera

+0

с помощью 'var window', вы создаете локальную переменную окна , Мы хотим глобальную переменную. Я пробовал 'window = {}', и похоже, что он может работать таким образом. –

ответ

1

1) То, что вы ищете является module.exports выставить вещи в узле:

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

2) Кроме того, вам не нужно IIFE в узле, вы можете отказаться от (function() {...

3) Вы всегда можете взглянуть на некоторые популярные репозитории Node на Github, чтобы увидеть примеры, посмотрите на код Mocha, так как вы его используете, вы узнаете кое-что.

+0

Как я уже указывал в своем комментарии выше, MyClass сам по себе является тем, что я вызываю только в браузере, это не код на стороне сервера. Я просто пытался использовать Node для тестирования, а не запускать Mocha в браузере ... Я также попытался добавить DOM в свой тестовый файл (jsdom), но это не помогло. module.exports не помогает мне, так как мне пришлось бы поместить это в MyClass, который я не могу сделать (поскольку он не работает в узле) – pabera

+0

А, ок. Хорошо, если бы я был вами, я бы посмотрел на что-то, что запускало вещи в безголовом браузере, таком как Phantomjs, с тест-бегуном, как кармаджи. По крайней мере, вы проверили бы, что произойдет в браузере. –

+0

да .. Я думаю, что я не обойти это. спасибо в любом случае – pabera

1

Что-то вроде jsdom легче, чем PhantomJS, и при этом предоставляет немало вещей, необходимых для проверки кода, который, как ожидается, будет работать с правильным window. У меня есть used it с большим успехом, чтобы проверить код, который перемещается вверх и вниз по дереву DOM.

Вы спрашиваете:

This is browser code, I just want to use Node to test it. (Is that even desirable?)

Это очень желательно. Там, где решение, подобное jsdom, не будет его обрезать, но пока ваш код находится в пределах того, что обрабатывает jsdom, он может также использовать его и сохранить стоимость запуска тестовой среды до необходимого минимума.

2

С помощью следующего кода вы можете использовать свой классный объект в среде веб-браузера и 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 это должно быть правдой.

+0

Я думаю, проблема в том, что область, которую вы создали, построена компилятором coffeeScript и не принимает никаких аргументов. –

+0

Не могли бы вы расширить свой пост кодом CS? – hgoebl

+0

Поскольку я не оп, я добавил свое решение в качестве ответа. –

1

@hgoebl: Как я не ОП, я не могу добавить свой исходный код 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 || 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 находится в глобальном пространстве имен, так же как и реали требуют необходимо в файле, который содержит тесты мокко:

require('./pubsub.coffee') 
3

Вы фактически не хотите объект окна, что вы хотите это глобальный объект. Вот код, который может получить его в браузере (в этом случае он будет таким же, как «окно») или в узле (в этом случае он будет таким же, как «global»).

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

Затем задайте вещи на этом, а не на «окне».

Примечание: существуют другие способы получения глобального объекта, но это имеет то преимущество, что оно будет работать и в коде строгого режима.

+0

Спасибо за совместное использование, я постараюсь это завтра. –

+0

Работает как шарм :-) –

+0

Можете ли вы подробно объяснить, почему нужен вызов функции? –