I'm trying to write a jasmine test in coffeescript that uses a beforeEach block. This runs into a problem with coffeescript's variable scoping. Here's what I'd like to write:
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'})
This doesn't work, though, because the scope
and $browser
will get declared with var
in the innermost scope. That is, once in the beforeEach
and then again in the it
block. I can force the variables to be declared in the right scope by initializing them, but this seems very strange:
describe 'PhoneDetailCtrl', () -> $browser = {} scope = {} beforeEach () -> scope = angular.scope() $browser = scope.$service('$browser') it 'should fetch phone detail', () -> scope.params = {phoneId:'xyz'} ...
This works, but the javascript it compiles to is actually
describe('PhoneListCtrl', function() { var $browser, ctrl, scope; $browser = {}; ctrl = {}; scope = {};
where all I need is the line var $browser, ctrl, scope;
. Can I write this more concisely in coffeescript?
In JavaScript, before using a variable, we need to declare and initialize it (assign value). Unlike JavaScript, while creating a variable in CoffeeScript, there is no need to declare it using the var keyword. We simply create a variable just by assigning a value to a literal as shown below.
To declare (create) a variable, you will specify the type, leave at least one space, then the name for the variable and end the line with a semicolon ( ; ). Java uses the keyword int for integer, double for a floating point number (a double precision number), and boolean for a Boolean value (true or false).
Description. let allows you to declare variables that are limited to the scope of a block statement, or expression on which it is used, unlike the var keyword, which declares a variable globally, or locally to an entire function regardless of block scope.
Do not use the same variable name in two scopes where one scope is contained in another. For example, No other variable should share the name of a global variable if the other variable is in a subscope of the global variable.
You are doing it the right way.
This is described in the CoffeeScript documentation. I wouldn't worry about the JS that it creates. Yes, it is a bit messy if you were to write it yourself, but this is one of the things that you have to live with when you use a re-writer like CoffeeScript.
You do, however, have a couple of options which are pretty nice.
You can put the variables in the current context if you wish (which happens to be your jasmine.Spec object for the curious, so it is a relatively safe and appropriate place to be putting variables... just don't overwrite existing vars in the context.):
describe 'PhoneDetailCtrl', () -> beforeEach () -> @scope = angular.scope() @$browser = @scope.$service('$browser') it 'should fetch phone detail', () -> @scope.params = {phoneId:'xyz'} #... etc
You can also setup your own variable in which to store things
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
Your test could be written like the following:
describe "MyGame", -> mygame = null beforeEach inject (_MyGame_) -> mygame = _MyGame_ it "should have two players", -> expect(mygame.opponents.length).toEqual 2
Much cleaner syntax - without the need to make things global.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With