In my AngularJS application, I have a controller called MenuCtrl that utilizes a service provided by "$mdSidenav" from Angular Material. This service is created using a factory method.
angular.module('leopDirective', [])
.controller('MenuCtrl', function ($scope,$timeout,$mdSidenav,$log) {
$scope.mdSidenav = $mdSidenav;
$scope.close = function () {
$mdSidenav('left').close().then(function() {$scope.closed=true; });
};
});
I am currently attempting to mock the $mdSidenav service in order to test my controller. Below is the Jasmine test code I am working on:
describe('Controller: MenuCtrl', function() {
var $rootScope, $scope, $controller, $q, menuCtrl,
mock__mdSidenav = function(component) {
return {
// THIS FUNCTION IS EMPTY SINCE $Q IS NOT AVAILABLE
close: function() {}
}
};
beforeEach(function() {
module('leopDirective', function($provide) {
// MOCK UP MUST BE PROVIDED BEFORE INJECTING $Q
$provide.value('$mdSidenav', mock__mdSidenav);
});
inject(function($injector) {
$rootScope = $injector.get('$rootScope');
$controller = $injector.get('$controller');
$q = $injector.get('$q');
$scope = $rootScope.$new();
});
menuCtrl = $controller("MenuCtrl", { $scope: $scope });
});
it('should create the $mdSidenav object', function() {
var deferred = $q.defer(),
promise = deferred.promise;
// NOW THAT $Q IS AVAILABLE, I TRY TO FILL UP THE FUNCTION
mock__mdSidenav.close = function() {
return promise.then(function(response){return response.success;});
};
// force `$digest` to resolve/reject deferreds
$rootScope.$digest();
// INVOKE FUNCTION TO TEST
$scope.close();
});
});
The issue I'm facing is figuring out how to create a function in the mock that returns a promise:
- Creating a promise relies on $q,
- $q needs to be injected within the "inject" block,
- However, $provide must be used inside the "module" block before injecting,
- Therefore, the function in the mock object (mock__mdSidenav().close()) has to be empty before invoking "$provide" and then somehow filled later.
Unfortunately, this approach is leading to an error message (see Demo plnkr), indicating that creating an empty function first and filling it later does not work:
TypeError: Cannot read property 'then' of undefined
at Scope.$scope.close (app.js:7:35)
What is the correct way to mock a service with a function that returns a promise?