Reputation: 95
i have some issues when i try to test controller which uses promises with jasmine.
I have following jasmine test:
describe('Testing a controller', function () {
var $scope, $root, ctrl, $q, deferred;
var MockService;
beforeEach(function () {
module('myApp');
inject(function ($rootScope, $controller, $q) {
$root = $rootScope;
$scope = $rootScope.$new();
MockService = {
fetch: function () {
return {
get: function () {
deferred = $q.defer();
return {
$promise: deferred.promise
};
}
};
}
};
ctrl = $controller('myController', {
$scope: $scope,
$root: $rootScope,
MyService: MockService,
});
});
spyOn(MockService, 'fetch').andCallThrough();
});
it('Get data from promise', function () {
$scope.init();
deferred.resolve("It worked!");
$root.$digest();
expect(MockService.fetch).toHaveBeenCalled();
expect($scope.test).toBe('It worked!');
});
});
and this is the controller:
controllers.controller('myController', ['$scope','MyService'
function ($scope, myService) {
$scope.init = function () {
myService.fetch().get().$promise.then(function (data) {
$scope.test = data;
}, function (error) {
$scope.error = error;
});
};
}
]);
And the test keeps failing: "Expected undefined to be 'It Worked!'."
It seems that the promise gets resolved and "then" function is never called. Any ideas what's the issue ?
Upvotes: 3
Views: 1034
Reputation: 3569
The code as you've presented above seems to work (now that @dfsq's fix has been applied).
I've only been able to reproduce the error you're experiencing by commenting out either of the following lines:
deferred.resolve("It worked!");
$root.$digest();
... which makes me wonder if in your actual code (not the sample presented above) there is something wrong with the implementation of the equivalents of the above two lines of code.
Have you, perhaps, earlier in the same test done a deferred.reject()
, or deferred.resolve()
without passing a parameter?
A demo of your jasmine test using the HTMLReporter:
/* Angular App */
(function() {
"use strict";
angular.module('myApp', [])
.controller('myController', ['$scope', 'MyService',
function($scope, myService) {
$scope.init = function() {
myService.fetch().get().$promise.then(function(data) {
$scope.test = data;
}, function(error) {
$scope.error = error;
});
};
}
]);
})();
/* Unit Test */
(function() {
"use strict";
var consoleLog = document.querySelector('#log');
describe('Testing a controller', function() {
var $scope, $root, ctrl, $q, deferred;
var MockService;
beforeEach(function() {
module('myApp');
inject(function($rootScope, $controller, $q) {
$root = $rootScope;
$scope = $rootScope.$new();
MockService = {
fetch: function() {
return {
get: function() {
deferred = $q.defer();
return {
$promise: deferred.promise
};
}
};
}
};
ctrl = $controller('myController', {
$scope: $scope,
$root: $rootScope,
MyService: MockService,
});
});
spyOn(MockService, 'fetch').andCallThrough();
});
it('Get data from promise', function() {
consoleLog.innerHTML += "<p>" + [
"START OF TEST:",
"$scope.test: " + $scope.test,
"$scope.error: " + $scope.error
].join("<br />") + "</p>";
$scope.init();
deferred.resolve("It worked!");
$root.$digest();
expect(MockService.fetch).toHaveBeenCalled();
expect($scope.test).toBe('It worked!');
consoleLog.innerHTML += "<p>" + [
"END OF TEST:",
"$scope.test: " + $scope.test,
"$scope.error: " + $scope.error
].join("<br />") + "</p>";
});
});
})();
/* Jasmine Bootstrap */
(function() {
"use strict";
var jasmineEnv = jasmine.getEnv(),
htmlReporter = new jasmine.HtmlReporter();
jasmineEnv.addReporter(htmlReporter);
jasmineEnv.execute();
})();
<link rel="stylesheet" href="//cdn.jsdelivr.net/jasmine/1.3.1/jasmine.css" />
<script src="//cdn.jsdelivr.net/jasmine/1.3.1/jasmine.js"></script>
<script src="//cdn.jsdelivr.net/jasmine/1.3.1/jasmine-html.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.28/angular.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.28/angular-mocks.js"></script>
<pre id="log"></pre>
Upvotes: 2
Reputation: 193261
Looks like a simple problem: controller expects myService
by you are injecting completely another mock service MyService
(note "M"). As the result mock is never used but rather original one, which never resolves promise as you expect.
It should be:
ctrl = $controller('myController', {
$scope: $scope,
$root: $rootScope,
myService: MockService,
});
Upvotes: 0