Search code examples
angularjsjasminegoogle-closure-compilergoogle-closure-library

Angularjs controller's $scope undefined whille unit testing and using Google Closure Library


My question is quite simple but hard to answer... how to inject a $scope to an AngularJs controller under test using google closure tools.

The controller is quite simple, basically it performs a http request to the server through the _getOrganisations function

Here is the actual controller:

goog.provide 'MyModule.controllers.Menu'

MyModule.controllers.Menu = ($scope, $http, $location, SomeService) ->
  _getOrganisations = () ->

    $http({SomeRequestOptions})
      .success(_handleGetOrganisationsSuccessCallback)
      .error(_handleGetOrganisationsErrorCallback)

  _handleGetOrganisationsSuccessCallback = (result, status) ->
    $scope.organisations = result

  _handleGetOrganisationsErrorCallback = (err, status) ->
    [...]

  $scope.toggleMenu = () ->
    angular.element('.nav-collapse').collapse('toggle')

  _getOrganisations()

Here is how I tried to test my controller

describe 'menu controller', () =>

    result=
        org1 : ''
        org2 : ''
        org3 : ''

    beforeEach () ->
        goog.require 'MyModule.controllers.Menu'

        inject ($rootScope, $controller, $http, $httpBackend) ->
            scope = $rootScope.$new()
            httpBackend = $httpBackend
            httpBackend.whenGET({SomeRequestOptions}).respond result
            menuController = $controller new MyModule.controllers.Menu(), {$scope : scope, $http : $http}

    it 'should get organisations properly', () ->
        expect(scope.organisations).toEqual(result)

When I'm trying to assign my actual controller to the menuController, $scope is undefined... What am I missing here ?


Solution

  • I can see a scope problem with the code in your test. I commented directly in the code.

    describe 'menu controller', () =>
    
        result=
            org1 : ''
            org2 : ''
            org3 : ''
    
        beforeEach () ->
            goog.require 'MyModule.controllers.Menu'
    
            inject ($rootScope, $controller, $http, $httpBackend) ->
                # here you define a variable inside a function...
                scope = $rootScope.$new()
                httpBackend = $httpBackend
                httpBackend.whenGET({SomeRequestOptions}).respond result
                menuController = $controller new MyModule.controllers.Menu(), {$scope : scope, $http : $http}
    
        it 'should get organisations properly', () ->
            # here you try to access the variable from outside the function
            expect(scope.organisations).toEqual(result)
    

    I haven't tested the code but I'm quite sure something like this would solve it. According to this post. http://odetocode.com/blogs/scott/archive/2013/06/10/simple-unit-tests-with-angularjs.aspx

    describe 'menu controller', () =>
        scope = null
        result=
            org1 : ''
            org2 : ''
            org3 : ''
    
        beforeEach () ->
            goog.require 'MyModule.controllers.Menu'
    
            inject ($rootScope, $controller, $http, $httpBackend) =>
                scope = $rootScope.$new()
                httpBackend = $httpBackend
                httpBackend.whenGET({SomeRequestOptions}).respond result
                menuController = $controller new MyModule.controllers.Menu(), {$scope : scope, $http : $http}
    
        it 'should get organisations properly', () ->
            expect(scope.organisations).toEqual(result)