Как объявить переменную в определенной области в coffeescript?

Я пытаюсь написать тест жасмина в coffeescript, который использует блок beforeEach. Это сталкивается с проблемой изменения масштаба переменной coffeescript. Вот что я хотел бы написать:

describe 'PhoneDetailCtrl', () ->
  beforeEach () ->
    scope = angular.scope()
    $browser = scope.$service('$browser')

  it 'should fetch phone detail', () ->
    scope.params = {phoneId:'xyz'}
    $browser.xhr.expectGET('phones/xyz.json').respond({name:'phone xyz'})
    ctrl = scope.$new(PhoneDetailCtrl)

    expect(ctrl.phone).toEqualData({})
    $browser.xhr.flush()

    expect(ctrl.phone).toEqualData({name:'phone xyz'})

Это не работает, потому что scope и $browser будут объявлены с помощью var в самой внутренней области. То есть, один раз в beforeEach, а затем снова в блоке it. Я могу заставить переменные объявляться в правильной области, инициализируя их, но это кажется очень странным:

describe 'PhoneDetailCtrl', () ->
  $browser = {}
  scope = {}
  beforeEach () ->
    scope = angular.scope()
    $browser = scope.$service('$browser')

  it 'should fetch phone detail', () ->
    scope.params = {phoneId:'xyz'}
    ...

Это работает, но javascript, который он компилирует, на самом деле

describe('PhoneListCtrl', function() {
  var $browser, ctrl, scope;
  $browser = {};
  ctrl = {};
  scope = {};

где мне нужна только строка var $browser, ctrl, scope;. Могу ли я написать это более кратко в coffeescript?

Ответ 1

Вы делаете это правильно.

Это описано в документации CoffeeScript. Я бы не стал беспокоиться о том, что он создает. Да, это немного беспорядочно, если вы должны сами написать это, но это одна из тех вещей, с которыми вам приходится жить, когда вы используете репитера, такого как CoffeeScript.

Однако у вас есть несколько вариантов, которые довольно приятны.

Вы можете поместить переменные в текущий контекст, если хотите (что, вероятно, будет вашим объектом jasmine.Spec для любопытных, поэтому это относительно безопасное и подходящее место для размещения переменных... просто не перезаписывайте существующие vars в контексте.):

describe 'PhoneDetailCtrl', () ->
  beforeEach () ->
    @scope = angular.scope()
    @$browser = @scope.$service('$browser')

it 'should fetch phone detail', () ->
  @scope.params = {phoneId:'xyz'}
  #... etc

Вы также можете настроить свою собственную переменную для хранения вещей

describe 'PhoneDetailCtrl', () ->
  setup = {}

  beforeEach () ->
    setup.scope = angular.scope()
    setup.$browser = setup.scope.$service('$browser')

  it 'should fetch phone detail', () ->
    setup.scope.params = {phoneId:'xyz'}
    #... etc

Ответ 2

Ваш тест можно записать следующим образом:

describe "MyGame", ->
    mygame = null
    beforeEach inject (_MyGame_) ->
        mygame = _MyGame_

    it "should have two players", ->
        expect(mygame.opponents.length).toEqual 2

Более чистый синтаксис - без необходимости делать вещи глобальными.