angularjsunit-testingmocha.jschaihttpbackend

mocked backend GET request not caught by service method


I'm building a test for a controller name GeneController that uses a service called Gene to make a bunch of API GET requests. I've mocked the main GET request like this and I'm pretty sure it's working properly:

    $httpBackend.expectGET '/api/knowledge/genes/param1'
      .respond(200, JSON.stringify({
      data: {
      mutationsUrl: 'http://localhost:3000/api/knowledge/genes/param1/mutations',
      frequenciesUrl: 'http://localhost:3000/api/knowledge/genes/param1/frequencies',
      annotationUrl: 'http://localhost:3000/api/knowledge/genes/param1/annotation',
      sections: {
        description: {
          data: 'holder'
          }
        }
      }
      }))

Controller: GeneController

    .controller 'GeneController', Array '$scope', '$routeParams', '$http', 'Gene', ($scope, $routeParams, $http, Gene) ->

    $scope.entity = Gene.get($routeParams
      (entity) ->
        $scope.description = entity.data.sections.description.data

        entity.getUrl entity.data.mutationsUrl, {limit: 10}, (err, mutationsData) ->
          if ! err?
            for m in mutationsData.data
              m.selected = true
            $scope.mutations = mutationsData

        entity.getUrl entity.data.frequenciesUrl, {}, (err, frequenciesData) ->
          if ! err?
            $scope.frequencies = frequenciesData

        entity.getUrl entity.data.annotationUrl, {}, (err, annotationData) ->
          if ! err?
            $scope.annotation = annotationData

      (error) ->
        console.log error
    )

Service: Gene

    .factory 'Gene', Array '$resource', '$http', ($resource, $http) ->
      Gene = $resource '/api/knowledge/genes/:gene', {},
        query:
          method: 'GET'

      Gene.prototype.getUrl = (url, options, callback) ->
        $http {method: 'GET', url: url, params: options}
          .then (res) ->  # Success callback
            callback null, res.data
          ,(res) -> # Error callback
            callback res.status, res.data

      Gene

The problem I'm having is with the "secondary" GET requests that are being facilitated by the Gene.prototype.getUrl method. I think the method itself is working fine because the proper content (from mutations, frequencies, and annotation) is displaying on the webpage. However these GET requests are failing and I'm getting the following error from mocha: "undefined is not an object (evaluating 'mutationsData.data')".

I've mocked the responses to these GET requests to no avail. Here is my test for the controller.

Test

 ...

 describe 'GeneController', () ->

    Gene = undefined

    beforeEach inject (_$controller_, $rootScope, _Gene_, _$httpBackend_) ->
      scope = $rootScope.$new()
      controller = _$controller_ 'GeneController', {
        $scope: scope
        $routeParams: { gene:  'param1' }
      }
      Gene: _Gene_
      $httpBackend = _$httpBackend_

    describe 'valid response', () ->

      beforeEach () ->
        $httpBackend.whenGET 'http://localhost:3000/api/knowledge/genes/param1/mutations'
          .respond(200, JSON.stringify({
            data: "something"
          }))

        $httpBackend.whenGET 'http://localhost:3000/api/knowledge/genes/param1/frequencies'
          .respond(200, JSON.stringify({
            data: 'somethingelse'
        }))

        $httpBackend.whenGET 'http://localhost:3000/api/kowledge/gene/param1/annotation'
          .respond(200, JSON.stringify({
            data: 'somethingelser'
        }))

        $httpBackend.expectGET '/api/knowledge/genes/param1'
          .respond(200, JSON.stringify({
          data: {
            mutationsUrl: 'http://localhost:3000/api/knowledge/genes/param1/mutations',
            frequenciesUrl: 'http://localhost:3000/api/knowledge/genes/param1/frequencies',
            annotationUrl: 'http://localhost:3000/api/knowledge/genes/param1/annotation',
            sections: {
              description: {
                data: 'holder'
              }
            }
          }
        }))

        $httpBackend.flush()

      it "should set $scope.description when the Gene is called", () ->
        expect(scope.description).to.equal "holder"

Any help with this problem would be very much appreciated. I'm quite thoroughly stuck on this. Thank you in advance :)


Solution

  • The controller was making calls to our Rest API in a non-Restful way. I have split each GET request into its own code block, using restangular to implement promises:

    .controller 'GeneController', Array '$scope', '$routeParams', 'Gene', 'Restangular', ($scope, $routeParams, Gene, Restangular) ->
    
        _genes_ = Restangular.all('knowledge').all('genes')
    
        _genes_.get($routeParams.gene).then (results) ->
          $scope.entity = results.data
          $scope.description = $scope.entity.data.sections.description.data
        .catch (error) ->
          console.log 'Unable to load genes data'
    
        _genes_.all($routeParams.gene).get('mutations').then (results) ->
          for m in results.data.data
            m.selected = true
          $scope.mutations = results.data
        .catch (error) ->
          console.log 'Unable to load mutations data'
    
        _genes_.all($routeParams.gene).get('frequencies').then (results) ->
          $scope.frequencies = results.data
        .catch (error) ->
          console.log 'Unable to load frequencies data'
    
        _genes_.all($routeParams.gene).get('annotation').then (results) ->
          $scope.annotation = results.data
        .catch (error) ->
          console.log 'Unable to load annotation data'