lundi 7 décembre 2015

AngularJS - Simple deferred object is returning null in Unit Test

I am trying to do some unit tests with Jasmine and working with promises and deferred and such. But I am having problems with the spyOn function.

I have this simple as can be app.js:

var app = angular.module('app', []);

app.service('MainModel', function($q) {
  this.name = "Hello World!";

  var getNato = function() {
    var deferred = $q.defer();
    var theNatoAlphabet = ['Alpha', 'Bravo', 'Charlie', 'Delta', 'Echo', 'Foxtrot', 'Golf', 'Hotel', 'India'];
    deferred.resolve(theNatoAlphabet);
    return deferred.promise;
  };

  this.getNato = getNato();
});

app.controller('MainCtrl', function($scope, MainModel) {
  this.name = MainModel.name;

  var self = this;

  MainModel.getNato.then(function(data) {
    self.natoAlphabet = data;
    $scope.results = data;
  }).catch(function() {
    $scope.error = 'There has been an error!';
  });
});

Along with the spec file theSpec.js:

describe('Controller: MainCtrl', function() {

  beforeEach(angular.mock.module('app'));

  var $scope, $q, mockMainCtrl, $controller, scope, deferred, $location;

  beforeEach(angular.mock.inject(function(_$controller_, $rootScope, _$q_, MainModel) {
    $controller = _$controller_;
    scope = $rootScope.$new();
    var $scope = {};


    $q = _$q_;
    deferred = _$q_.defer();
    spyOn(MainModel, 'getNato').and.returnValue(deferred.promise);

    mockMainCtrl = $controller('MainCtrl', {
      $scope: $scope,
      MainModel: MainModel
    });

    scope.$digest();

    console.log(mockMainCtrl);

  }));

  it('Name from service, instantiated from controller, to be mocked correctly', function() {
    expect(mockMainCtrl.name)
      .toEqual("Hello World!");
  });

  it('Get [getNato] mocked deferred promise', function() {
    deferred.resolve([{ id: 1 }, { id: 2 }]);
    $scope.$apply();
    expect($scope.results).not.toBe(undefined);
    expect($scope.results).toEqual(['Alpha', 'Bravo', 'Charlie', 'Delta', 'Echo', 'Foxtrot', 'Golf', 'Hotel', 'India']);
    expect($scope.error).toBe(undefined);
  });
});

And the html task reporter (Which works fine) index.html:

<body ng-controller="MainCtrl as mainCtrl">

  <strong>{{mainCtrl.name}}</strong>

  <span ng-repeat="nato in mainCtrl.natoAlphabet">&dash; {{nato}} </span>

  <hr />

  <script type="text/javascript" src="http://ift.tt/1HRYdGJ"></script>
  <script data-require="angular-mocks@*" data-semver="1.4.3" src="http://ift.tt/1OfgABY"></script>
  <script type="text/javascript" src="theSpec.js"></script>

</body>

VIEW LIVE DEMO HERE: http://ift.tt/1HRYg5d

As you can see, the two-way data binding works. But the error breaks the runtime at TypeError: Cannot read property 'returnValue' of undefined which is the spyOn function.

If I take out (or comment) line 15 on theSpec.js which starts with spyOn(MainModel...

Then I get: TypeError: Cannot read property '$apply' of undefined

Anyway. What can I do fix this?

Thanks

Aucun commentaire:

Enregistrer un commentaire