Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save DavidFrahm/6643032 to your computer and use it in GitHub Desktop.
Save DavidFrahm/6643032 to your computer and use it in GitHub Desktop.
AngularJS controller unit test when using service to handle $resource calls

When you use $resource within a service, you don't need to impose mocking $httpBackend on your controller. If you want tests for the $resource, those should be in the unit tests for the service.

The controller should only test things directly under its control, which means testing the service directly.

The examples below show how to mock a $resource service factory, in the simplest way I could come up with.

TODO:

  • These are real-world examples and it might be helpfule to visitors if I removed all the extra junk that isn't directly related to testing $resource.
  • Should this be updated to be a better example of utilizing promises?
'use strict';
Controllers.
controller('TxController', function($rootScope, $scope, $routeParams, $navigate, Envelopes, BankAccounts, LastEditedEnvelope) {
log('TxController()');
var _this = this;
_this.getToday = function() {
// return new Date().toJSON().slice(0,10);
var date = new Date();
var day = date.getDate();
var month = date.getMonth() + 1;
var year = date.getFullYear();
if (month < 10) month = "0" + month;
if (day < 10) day = "0" + day;
var today = year + "-" + month + "-" + day;
return today;
};
log('$routeParams.envelopeId: ' + $routeParams.envelopeId);
if ($routeParams.envelopeId) {
$scope.envelopeId = parseInt($routeParams.envelopeId);
log('envelopeId: ' + $scope.envelopeId);
}
$scope.tx = {
"date": _this.getToday(),
"type": "expense",
"envelopeId": $scope.envelopeId
};
Envelopes.get({},
function success(response) {
log('success response: ' + angular.toJson(response));
if (response.success === true) {
$scope.envelopes = response.data;
} else {
log('Envelopes.get() > Failure');
$scope.messages = 'Unable to retrieve data';
return;
}
}, function error(response) {
// TODO: Can we get others? status, headers, config
$scope.logAjaxError(response);
log('Login error');
$scope.messages = 'Unable to retrieve data at this time';
});
$scope.save = function(txInput) {
log('save()');
log("txInput: " + angular.toJson(txInput));
// TODO: Create angular service for messages?
$scope.messages = null;
if ($scope.TxNewForm.$invalid) {
log('Form is invalid');
return;
}
// TODO: Call Envelope.save()
log('txInput.envelopeId: ' + txInput.envelopeId);
LastEditedEnvelope.id = txInput.envelopeId;
log('LastEditedEnvelope: ' + angular.toJson(LastEditedEnvelope));
$scope.navigateBack();
};
$scope.navigateBack = function() {
$navigate.back();
};
});
'use strict';
describe('Controller', function() {
var userProfileWithApiKey = {
"apiKey": "MY-VALID-API-KEY"
};
var jsonEnvelopesSuccess = {
"success": true,
"data": [{
"id": 6,
"type": "Spending",
"description": "Gas",
"balance": 20000,
"monthlyAmount": 20000,
"archived": false,
"splitFunding": false,
"autoTransferLocked": false,
"overflow": false,
"warning": false
}]
};
beforeEach(function() {
// spyOn(window, 'getUserProfile').andReturn(userProfileWithApiKey);
angular.mock.module('Controllers');
angular.mock.module('ajoslin.mobile-navigate');
angular.mock.module('deviceServices');
angular.mock.module('appServices');
});
describe('TxController', function() {
var controller;
var scope;
var routeParams;
var mockEnvelopesServiceTemplate = {
get: function(parameters, success, error) {
log('parameters: ' + angular.toJson(parameters));
log('success: ' + success);
log('error: ' + error);
// return success({"success": true,"message": null, "data": jsonEnvelopesSuccess});
return error({
"success": false,
"message": "Mocked failure",
"data": null
});
},
save: function(parameters, postData, success, error) {
log('parameters: ' + angular.toJson(parameters));
log('postData: ' + angular.toJson(postData));
log('success: ' + success);
log('error: ' + error);
// return success({"success": true,"message": null, "data": "whatever"});
return error({
"success": false,
"message": "Mocked failure",
"data": null
});
}
};
beforeEach(inject(function($controller, $rootScope, $routeParams) {
log('beforeEach inject: after');
scope = $rootScope.$new();
scope.logAjaxError = function(data, status, headers, config) {};
spyOn(scope, 'logAjaxError').andReturn();
routeParams = {};
controller = $controller('TxController', {
$scope: scope,
$routeParams: routeParams,
Envelopes: {
get: function() {}
}
});
}));
it('should be defined', function() {
expect(controller).toBeDefined();
});
it('should have a tx scope variable', function() {
expect(scope.tx).toBeDefined();
});
it('should default tx date to todays date', function() {
expect(scope.tx.date).toBeDefined();
expect(scope.tx.date).toEqual(controller.getToday());
});
it('should default tx type to expense', function() {
expect(scope.tx.type).toEqual('expense');
});
it('should not default tx envelopeId to anything', function() {
expect(scope.tx.envelopeId).toEqual(undefined);
});
it('should set tx envelopeId route parameter envelopeId as integer', inject(function($controller) {
routeParams.envelopeId = '123'; // Always strings
controller = $controller('TxController', {
$scope: scope,
$routeParams: routeParams,
Envelopes: {
get: function() {}
}
});
expect(scope.tx.envelopeId).toEqual(123);
}));
it('should have an messages scope variable when envelopes data is not successful', inject(function($controller) {
var mockEnvelopesService = {
get: function(parameters, success, error) {
log('parameters: ' + angular.toJson(parameters));
log('success: ' + success);
log('error: ' + error);
return success({
"success": false,
"message": "Mocked data failure",
"data": null
});
}
};
controller = $controller('TxController', {
$scope: scope,
$routeParams: routeParams,
Envelopes: mockEnvelopesService
});
log('scope.messages: ' + scope.messages);
expect(scope.messages).toBeDefined();
}));
it('should have an messages scope variable when envelopes request throws error', inject(function($controller) {
var mockEnvelopesService = {
get: function(parameters, success, error) {
return error();
}
};
controller = $controller('TxController', {
$scope: scope,
$routeParams: routeParams,
Envelopes: mockEnvelopesService
});
log('scope.messages: ' + scope.messages);
expect(scope.messages).toBeDefined();
}));
it('should have an envelopes scope variable when envelopes data is returned/successful', inject(function($controller) {
var mockEnvelopesService = {
get: function(parameters, success, error) {
log('parameters: ' + angular.toJson(parameters));
log('success: ' + success);
log('error: ' + error);
return success({
"success": true,
"message": null,
"data": jsonEnvelopesSuccess
});
}
};
controller = $controller('TxController', {
$scope: scope,
$routeParams: routeParams,
Envelopes: mockEnvelopesService
});
log('scope.envelopes: ' + scope.envelopes);
expect(scope.envelopes).toBeDefined();
}));
});
});
'use strict';
angular.module('appServices', ['ngResource'])
.value('LastEditedEnvelope', {})
.factory('Login', function($resource) {
return $resource(getApiDomain() + '/api/register', {}, {});
})
.factory('Envelopes', function($resource, ApiKey) {
return $resource(getApiDomain() + '/api/envelopes', {}, {
get: {
method: 'GET',
params: {
"apiKey": ApiKey.getApiKey()
}
}
})
})
.factory('BankAccounts', function($resource, ApiKey) {
return $resource(getApiDomain() + '/api/bankAccounts', {}, {
get: {
method: 'GET',
params: {
"apiKey": ApiKey.getApiKey()
}
}
});
})
;
@baktun14
Copy link

Hi, thanks for this example. I'm new to unit testing and i'm utilizing the ngResource just like this, but with the $promise. It would be great if you could demonstrate it using the $promise.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment