Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sjtipton/6b0f5cc0928f000f97b2ffa83d3259e9 to your computer and use it in GitHub Desktop.
Save sjtipton/6b0f5cc0928f000f97b2ffa83d3259e9 to your computer and use it in GitHub Desktop.
When testing an Angular controller that has an injected service dependency, you will want to test the success/error callback handling, rather than re-testing the service (e.g. by hooking into $httpBackend functions)
describe('MyCtrl', function () {
var ctrl, scope, mockToaster, mockLog, mockMySvc, invokeController;
// Initialize a bare-bones behavior function for each tested service function
var mockMySvcSomeFunctionBehavior = function () {};
beforeEach(inject(function ($controller, $rootScope) {
mockMySvc = {
someFunction: function (success, error) {
mockMySvcSomeFunctionBehavior(success, error);
}
};
mockToaster = {
error: sinon.stub()
};
mockLog = {
error: sinon.stub()
};
sinon.spy(mockMySvc, 'someFunction');
invokeController = function () {
// Ensure to set scope here, so each call to invokeController has a fresh $rootScope instance
scope = $rootScope.$new();
ctrl = $controller('MyCtrl', {
$scope: scope,
$log: mockLog,
toaster: mockToaster,
'MySvc': mockMySvc
});
};
invokeController();
}));
describe('calling mySvc.someFunction', function () {
describe('on success', function () {
// define success response
var mockMySvcSomeFunctionResponse = {
data: {
foo: 'bar',
lorem: 'bacon',
ipsum: 'poutine'
}
};
// define success-specific behavior
var mockSuccessBehavior = function (success) {
success(mockMySvcSomeFunctionResponse);
};
// override bare-bones behavior function within this scope with the success-specific behavior
// and then invoke the controller
beforeEach(inject(function () {
mockMySvcSomeFunctionBehavior = mockSuccessBehavior;
invokeController();
}));
it('sets some property (e.g. data) to the scope as scope.[some property] (e.g. scope.data)', function () {
expect(scope.data).toBeTruthy();
expect(scope.data).toBe(mockMySvcSomeFunctionResponse);
});
});
describe('on error', function () {
// if you are testing for logging/toaster spy calls, it may be a good idea to track the prev/current call counts
// as they will increment as the spy is called
var previousLogCallCount, previousToasterCallCount, currentLogCallCount, currentToasterCallCount;
// define error response
var mockUserSessionSvcGetUserSessionResponse = { d: null };
// define error-specific behavior
var mockErrorBehavior = function (success, error) {
error(mockUserSessionSvcGetUserSessionResponse);
};
// override bare-bones behavior function within this scope with the success-specific behavior
// and then invoke the controller
beforeEach(inject(function () {
mockMySvcSomeFunctionBehavior = mockErrorBehavior;
previousLogCallCount = mockLog.error.callCount;
previousToasterCallCount = mockToaster.error.callCount;
invokeController();
currentLogCallCount = mockLog.error.callCount;
currentToasterCallCount = mockToaster.error.callCount;
}));
it('does not set some property (e.g. data) to the scope', function () {
expect(scope.data).toBe(undefined);
});
it('logs the error', function () {
expect(mockLog.error.called).toBe(true);
expect(currentLogCallCount).toBeGreaterThan(previousLogCallCount);
});
it('invokes a toaster error', function () {
expect(mockToaster.error.called).toBe(true);
expect(currentToasterCallCount).toBeGreaterThan(previousToasterCallCount);
});
});
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment