0
votes

There is probably too many of this sort of question on here, but none that I have found come up with one good solution. The problem, in my view, should be too common. dirty pseudocode: Acontroller

app.controller('Acontroller',function($scope,$q, Aservice){

  $scope.someScopeVariable = null;

  function refresh(){
    $q.all([
    Aservice.getCollectionA().then(function(results){
      return $scope.collectionA = results}),
    Aservice.getCollectionB().then(function(results){
      return $scope.collectionB = results})
     ]);
    };

    $scope.someScopeFunction = function(){
       Aservice.someServerUpdateCall().then(function(){
         refresh().then(function(){
           $scope.someScopeVariable = 'woot'
         }
       }
     }
 })

Is this really just really poorly written? I am tearing out my remaining stubble of hair on my bald head trying to test that someScopeFunction.

How would you test this? (Jasmine (1.3) on Karma)

I can test the first tier of the promise, but I cant simply assert that refresh function is called. I can mock the service but am having a hell of a time getting a spy on that refresh function. I would assume I have to instantiate the controller (a found a solution like that), though that does seem a little mad.

So (pardon the coffeescript):

describe 'Acontroller', ->
  mockService = {}
  aResponseObject =
    a:1
    b:2
  beforeEach -> module('app')

  beforeEach inject ($controller,$q, $rootScope) ->

    emptyPromise = ->
      defer = $q.defer
      defer.resolve()
      defer.promise


    responsePromise = ->
      defer = $q.defer()
      defer.resolve([aResponseObject],[aResponseObject])
      defer.promise

    mockService.getCollectionA = jasmine.createSpy('getCollectionA').andReturn responsePromise()
    mockService.getCollectionB = jasmine.createSpy('getCollectionB').andReturn responsePromise()
    mockService.someServerUpdateCall = jasmine.createSpy('someServerUpdateCall').andReturn emptyPromise()
    scope = $rootScope.$new()
    $controller 'Acontroller',
      $scope: scope
      Aservice: mockService

    $rootScope.$apply  ## resolve promises

  describe 'someScopeFunction', ->

    it 'should call Aservice with someServerUpdateCall', ->

      scope.someScopeFunction()
      scope.$digest
      expect(Aservice.someSererUpdateCall).toHaveBeenCalled() ##this should work

That expectation works fine, though confirming the the next call to refresh is where I'm at a loss. Seeing as its not tied to the scope, I would assume I have to instantiate the Controller?

I've played around with other strategies including something like:

done = false
refresh = jasmine.createSpy('refresh')

scope.someScopeFunction().then() -> done = true

waitsFor -> done

runs ->
  scope.$apply ->
    expect(refresh).toHaveBeenCalled()

To no avail though, promise is not resolved.

I heard Mocha makes async calls a little more straightforward, though I really dread trying to start over.

1

1 Answers

0
votes

So, i think I figured it out. I changed the original function on the scope to inject the refresh() function instead. Then called $digest on scope after injecting a spy on the test which returned a promise.

$scope.someScopeFunction = (refreshFn=refresh)
  Aservice.someServerUpdateCall().then ->
    refreshFn().then ->
      $scope.someScopeVariable = 'woot'

The test would then be:

describe 'Acontroller', ->

  mockService = {}
  mocks = {}
  aResponseObject =
    a:1
    b:2
  beforeEach -> module('app')

  beforeEach inject ($controller,$q, $rootScope) ->

    mocks.emptyPromise = ->
      defer = $q.defer
      defer.resolve()
      defer.promise


    mocks.responsePromise = ->
      defer = $q.defer()
      defer.resolve([aResponseObject],[aResponseObject])
      defer.promise

    mockService.getCollectionA = jasmine.createSpy('getCollectionA').andReturn mocks.responsePromise()
    mockService.getCollectionB = jasmine.createSpy('getCollectionB').andReturn mocks.responsePromise()
    mockService.someServerUpdateCall = jasmine.createSpy('someServerUpdateCall').andReturn mocks.emptyPromise()

    scope = $rootScope.$new()

    $controller 'Acontroller',
      $scope: scope
      Aservice: mockService

    $rootScope.$apply  ## resolve promises

  describe 'someScopeFunction', ->

    it 'should call refresh() after someServerUpdateCall', ->
      refresh = jasmine.createSpy('refresh').andReturn(mocks.emptyPromise())
      scope.someScopeFunction(refresh)
      scope.$digest ->
        expect(refresh).toHaveBeenCalled()