aurelius
aurelius

Reputation: 4076

How to unit test angular controller having multiple $resource calls

I have a controller that does multiple $resource calls to the backend when initialized. This works fine, but now I need to add unit tests with jasmine, and here comes the issue, I get an error when I try to save the state of an object inside the controller.

At controller initialization I make 3 $resource calls to populate 3 dropdowns, after making the selections on the 3 dropdowns and input a value in another input text, I press submit(save) and my entity is saved.

I do not have much experience with angular so I really need help, if other resources are required just ask and I will add them to this post. Thanks!

Now I need to unit test this save function and I get an error:

Chrome 41.0.2272 (Windows 7) permissionController should call the service successfully FAILED
        Error: Unexpected request: POST http://localhost:8080/webapp-1.0.0-SNAPSHOT/v1/actions/search
        No more request expected
            at $httpBackend (C:/_workspace/webapp/Platform/ui/src/main/uidev/node_modules/angular-mocks/angular-mocks.js:1220:9)
            at sendReq (C:/_workspace/webapp/Platform/ui/src/main/uidev/app/lib/js/angular.js:9628:9)
            at serverRequest (C:/_workspace/webapp/Platform/ui/src/main/uidev/app/lib/js/angular.js:9344:16)
            at processQueue (C:/_workspace/webapp/Platform/ui/src/main/uidev/app/lib/js/angular.js:13189:27)
            at C:/_workspace/webapp/Platform/ui/src/main/uidev/app/lib/js/angular.js:13205:27
            at Scope.$eval (C:/_workspace/webapp/Platform/ui/src/main/uidev/app/lib/js/angular.js:14401:28)
            at Scope.$digest (C:/_workspace/webapp/Platform/ui/src/main/uidev/app/lib/js/angular.js:14217:31)
            at Function.$httpBackend.flush (C:/_workspace/webapp/Platform/ui/src/main/uidev/node_modules/angular-mocks/angular-mocks.js:1519:38)
            at Object.<anonymous> (C:/_workspace/webapp/Platform/ui/src/main/uidev/test/unit/authz/permission/create-permission-controller-test.js:28:21)

This is the controller:

angular.module('platform.authz').controller('permissionController', function($translatePartialLoader,
 PermissionService, ActionService, ResourceService, EnvironmentService, $scope, $state) {

'use strict';
$translatePartialLoader.addPart('authz/permission');

var controller = this;
controller.permission = {};

function errorMessageHandler(response) {
    var errorMessages = [];
    response.data.messages.forEach(function(message, i) {
        errorMessages[i] = {type: 'danger', text: message.description};
    });
    controller.notificationMessages = errorMessages;
}

controller.populateActions = function() {
    ActionService.searchRequestObject().search({search: ''}).$promise.then(function(data) {
        controller.actions = data;
    }, errorMessageHandler);
};

controller.populateResources = function() {
    ResourceService.searchRequestObject().search({search: ''}).$promise.then(function(data) {
        controller.resources = data;
    }, errorMessageHandler);
};

controller.populateEnvironments = function() {
    EnvironmentService.searchRequestObject().search({search: ''}).$promise.then(function(data) {
        controller.environments = data;
    }, errorMessageHandler);
};

controller.getPermissionSaveRequest = function() {
    var permissionSaveRequest = {};
    permissionSaveRequest.name = controller.permission.name;
    permissionSaveRequest.actionId = controller.permission.action.id;
    permissionSaveRequest.resourceId = controller.permission.resource.id;
    permissionSaveRequest.environmentId = controller.permission.environment.id;
    return permissionSaveRequest;
};

controller.save = function() {
    PermissionService.createRequestObject().create(controller.getPermissionSaveRequest()).$promise.then(function() {
        controller.notificationMessages = [
            {type: 'success', text: 'Save has been successful!'}
        ];
        controller.permission = {};
        $scope.permissionDetailsForm.$setPristine();
    }, errorMessageHandler);
};

controller.cancel = function cancel() {
    $state.reload();
};

controller.actions = controller.populateActions();
controller.resources = controller.populateResources();
controller.environments = controller.populateEnvironments();
});

This is one of the service that is called upon controller initialization (all 3 services look the same)

angular.module('platform.authz').factory('ActionService', function($resource, $log, configService) {
'use strict';

return {
    searchRequestObject: function() {
        return $resource(configService.getUrlForService('action') + '/' + 'search', {}, {
            search: {method: 'POST', isArray: true}
        });
    }
    };
});

And this is my unit test tryout:

describe('permissionController', function() {
'use strict';

var httpBackend, permissionController, state, scope;

beforeEach(module('platform'));

beforeEach(inject(function(_$httpBackend_, $controller, _$state_, configService, $rootScope) {
    state = _$state_;
    spyOn(state, 'go');
    spyOn(state, 'transitionTo');
    spyOn(configService, 'getUrlForService')
            .and.callFake(function(name) {
                return CONFIG.get('MAIN_URL_FOR_REST_SERVICES') + name + 's';
            }
    );
    httpBackend = _$httpBackend_;
    scope = $rootScope.$new();
    permissionController = $controller('permissionController', {$scope: scope});
}));

it('should call the service successfully', function() {
    permissionController.permission = {'name': 'all', 'action': {'id': 1, 'name': 'all'}, 'resource': {'id': 1, 'name': 'all'}, 'environment': {'id': 1, 'name': 'all'}};
    httpBackend
        .whenPOST(CONFIG.get('MAIN_URL_FOR_REST_SERVICES') + 'permissions', permissionController.getPermissionSaveRequest())
        .respond(200, 'created');
    permissionController.save();
    httpBackend.flush();
    expect(permissionController.errorMessages[0].text).toBe('Error');
    });
});

Upvotes: 0

Views: 777

Answers (2)

aurelius
aurelius

Reputation: 4076

fix is here:

describe('permissionController', function() {
'use strict';

var $httpBackend, permissionController, scope;

beforeEach(module('platform'));

beforeEach(inject(function($injector, _$state_, configService) {
    $httpBackend = $injector.get('$httpBackend');
    scope = $injector.get('$rootScope').$new();
    scope.permissionDetailsForm = {$setPristine: function() {
    }};

    var state = _$state_;
    spyOn(state, 'go');
    spyOn(state, 'transitionTo');
    spyOn(configService, 'getUrlForService')
            .and.callFake(function(name) {
                return CONFIG.get('MAIN_URL_FOR_REST_SERVICES') + name + 's';
            }
    );

    var $controller = $injector.get('$controller');

    $httpBackend.when('POST', CONFIG.get('MAIN_URL_FOR_REST_SERVICES') + 'actions/search').respond(200,
            '[{"name": "all","id": "1"}]'
    );
    $httpBackend.when('POST', CONFIG.get('MAIN_URL_FOR_REST_SERVICES') + 'resources/search').respond(200,
            '[{"name": "all","id": "1"}]'
    );
    $httpBackend.when('POST', CONFIG.get('MAIN_URL_FOR_REST_SERVICES') + 'environments/search').respond(200,
            '[{"name": "all","id": "1"}]'
    );

    permissionController = $controller('permissionController', {$scope: scope});
    $httpBackend.flush();
}));

it('should call the service successfully', function() {
    permissionController.permission =
        {'name': 'all', 'action': {'id': 1, 'name': 'all'}, 'resource': {'id': 1, 'name': 'all'},
         'environment': {'id': 1, 'name': 'all'}};
    $httpBackend
            .whenPOST(CONFIG.get('MAIN_URL_FOR_REST_SERVICES') + 'permissions',
                permissionController.getPermissionSaveRequest())
            .respond(200, 'created');
    permissionController.save();
    $httpBackend.flush();
    expect(permissionController.notificationMessages[0].text).toBe('Save has been successful!');
});
});

Upvotes: 0

CodeBreakers
CodeBreakers

Reputation: 94

The problem is you are making 3 $resource calls when the controller is loaded, the controller is loaded when your test is executed. So you should make sure (in a beforeEach for example) to also mock those backend calls. You are now only mocking the one you expect when one is pressing save, but before the save event, your controller is already doing some backend communication. The exception you got is telling you this: "unexpected request".

Upvotes: 1

Related Questions