How to test controllers in angularjs

A test for a controller follows similar a pattern to the one for a service. Let’s have a look at the fragment of the ProjectsEditCtrl controller from the sample application. This controller in question is responsible for the editing projects in the administration part of the application. Here we are going to test methods of the controller responsible for adding and removing project’s team members:

angular.module('admin-projects', [])
  .controller('ProjectsEditCtrl', function($scope, project) {

    $scope.project = project;

    $scope.removeTeamMember = function(teamMember) {
      var idx = $scope.project.teamMembers.indexOf(teamMember);
      if(idx >= 0) {
        $scope.project.teamMembers.splice(idx, 1);
      }
    };

    //other methods of the controller
  });

The logic of the presented controllers is not complex and will let us to focus on the test itself:

describe('ProjectsEditCtrl tests', function () {

  var $scope;
  beforeEach(module('admin-projects'));
  beforeEach(inject(function ($rootScope) {
    $scope = $rootScope.$new();
  }));

  it('should remove an existing team member', inject(function ($controller) {

    var teamMember = {};
    $controller('ProjectsEditCtrl', {
      $scope: $scope,
      project: {
        teamMembers: [teamMember]
      }
    });

    //verify the initial setup
    expect($scope.project.teamMembers).toEqual([teamMember]);

    //execute and verify results
    $scope.removeTeamMember(teamMember);
    expect($scope.project.teamMembers).toEqual([]);
  }));
});

The removeTeamMember method that we want to test here will be defined on a $scope and it is the ProjectsEditCtrl controller that defines this method. To effectively test the removeTeamMember method we need to create a new scope, a new instance of the ProjectsEditCtrl controller and link the two together. Essentially we need to manually do the job of the ng-controller directive.

Let’s turn our attention to the beforeEach section for one more moment, as there are interesting things going on in there. Firstly we are getting access to the $rootScope service and creating a new $scope instance ($scope.$new()). We do so to simulate what would happen in a running application, where the ng-controller directive would create a new scope.

To create an instance of the controller we can use the $controller service (please notice how the inject function can be placed on the beforeEach section as well as on the it level).

Note

Look how easy it is to specify controller’s constructor arguments while invoking the $controller service. This is dependency injection at its best; we can provide both a fake scope and test data to exercise controller’s implementation in complete isolation.

Deven Rathore

Deven is an Entrepreneur, and Full-stack developer, Constantly learning and experiencing new things. He currently runs CodeSource.io and Dunebook.com.

Published by
Deven Rathore

Recent Posts

Are There any Similarities Between Web Design and Art?

You may be surprised at how many of the same skills are involved!  Let’s get…

1 day ago

Tips on Increasing your organic traffic on WordPress

Introduction  As more and more people are using online services nowadays, most of the business…

2 days ago

Five Reasons You Should Start a Social Media Campaign

Small businesses need all the advertisements they can get. Traditional avenues for advertising, such as…

3 days ago

Top 10 SEO Writing Tips for Beginners 2021

Search Engine Optimization. It’s complicated, to say the least. Search engines, like Google, are constantly…

2 weeks ago

Should you become a freelancer in 2021? Pros and Cons

Freelancing and working from home was long considered idyllic by many, but the global pandemic…

2 weeks ago

The Leading Renewable Energy Trends in 2021

The past year saw slowdowns in the ongoing shift toward renewable energy in many countries…

2 weeks ago