Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can we test non-scope angular controller methods?

We have few methods in Angular Controller, which are not on the scope variable.

Does anyone know, how we can execute or call those methods inside Jasmine tests?

Here is the main code.

var testController = TestModule.controller('testController', function($scope, testService)
{

function handleSuccessOfAPI(data) {
    if (angular.isObject(data))
    {
       $scope.testData = data;
    }
}

function handleFailureOfAPI(status) {
    console.log("handleFailureOfAPIexecuted :: status :: "+status);
}

 // this is controller initialize function.
 function init() {
    $scope.testData = null; 

    // partial URL
    $scope.strPartialTestURL = "partials/testView.html;

    // send test http request 
    testService.getTestDataFromServer('testURI', handleSuccessOfAPI, handleFailureOfAPI);
}

 init();
}

Now in my jasmine test, we are passing "handleSuccessOfAPI" and "handleFailureOfAPI" method, but these are undefined.

Here is jasmine test code.

describe('Unit Test :: Test Controller', function() {
var scope;
var testController;

var httpBackend;
var testService;


beforeEach( function() {
    module('test-angular-angular');

    inject(function($httpBackend, _testService_, $controller, $rootScope) {

        httpBackend = $httpBackend;
        testService= _testService_;

        scope = $rootScope.$new();
        testController= $controller('testController', { $scope: scope, testService: testService});
            });
});

afterEach(function() {
       httpBackend.verifyNoOutstandingExpectation();
       httpBackend.verifyNoOutstandingRequest();
    });

it('Test controller data', function (){ 
    var URL = 'test server url';

    // set up some data for the http call to return and test later.
    var returnData = { excited: true };

    // create expectation
    httpBackend.expectGET(URL ).respond(200, returnData);

    // make the call.
    testService.getTestDataFromServer(URL , handleSuccessOfAPI, handleFailureOfAPI);

    $scope.$apply(function() {
        $scope.runTest();
    });

    // flush the backend to "execute" the request to do the expectedGET assertion.
    httpBackend.flush();

    // check the result. 
    // (after Angular 1.2.5: be sure to use `toEqual` and not `toBe`
    // as the object will be a copy and not the same instance.)
    expect(scope.testData ).not.toBe(null);
});
});
like image 460
furqan kamani Avatar asked Apr 07 '14 19:04

furqan kamani


People also ask

What are controllers used for in angular?

The controller in AngularJS is a JavaScript function that maintains the application data and behavior using $scope object. You can attach properties and methods to the $scope object inside a controller function, which in turn will add/update the data and attach behaviours to HTML elements.

How do I run a unit test in AngularJS?

Load the Angular App beforeEach(module('MyApp')); //3. Describe the object by name describe('compute', function () { var compute; //4. Initialize the filter beforeEach(inject(function ($filter) { compute = $filter('compute', {}); })); //5. Write the test in the it block along with expectations.

Are there controllers in angular?

AngularJS ControllersAngularJS applications are controlled by controllers. The ng-controller directive defines the application controller. A controller is a JavaScript Object, created by a standard JavaScript object constructor.

Why are controllers used in AngularJS?

AngularJS application mainly relies on controllers to control the flow of data in the application. A controller is defined using ng-controller directive. A controller is a JavaScript object that contains attributes/properties, and functions.

How do I unit test an AngularJS controller?

To unit test an AngularJS controller, you can take advantage of Angular’s dependency injection and inject your own version of the services those controllers depend on to control the environment in which the test takes place and also to check that the expected results are occurring.

What is $scope in AngularJS?

In AngularJS, $scope is the application object (the owner of application variables and functions). The controller creates two properties (variables) in the scope ( firstName and lastName ). The ng-model directives bind the input fields to the controller properties (firstName and lastName).

How to invoke the controller from the controller in AngularJS?

AngularJS will invoke the controller with a $scope object. In AngularJS, $scope is the application object (the owner of application variables and functions). The controller creates two properties (variables) in the scope (firstName and lastName). The ng-model directives bind the input fields to the controller properties (firstName and lastName).

Is there a better solution for angular component testing?

In reality, this isn’t practical, so ultimately we’ll need to find a better solution for Angular component testing. Luckily for us, an Angular project created using the Angular CLI comes with Karma and Jasmine to make testing simple by automating the process. Jasmine is a behavior development testing framework.


2 Answers

I know this is an old case but here is the solution I am using.

Use the 'this' of your controller

.controller('newController',['$scope',function($scope){
    var $this = this;
    $this.testMe = function(val){
        $scope.myVal = parseInt(val)+1;
    }
}]);

Here is the test:

describe('newDir', function(){
var svc, 
    $rootScope,
    $scope,
    $controller,
    ctrl;


 beforeEach(function () {
    module('myMod');
 });

 beforeEach(function () {
    inject(function ( _$controller_,_$rootScope_) {

        $controller = _$controller_;
        $rootScope = _$rootScope_;
        $compile = _$compile_;
        $scope = $rootScope.$new();
        ctrl = $controller('newController', {'$rootScope': $rootScope, '$scope': $scope });
    });
});

it('testMe inc number', function() {

    ctrl.testMe(10)
    expect($scope.myVal).toEqual(11);
});

});

Full Code Example

like image 78
tmc Avatar answered Oct 15 '22 09:10

tmc


As is you won't have access to those functions. When you define a named JS function it's the same as if you were to say

var handleSuccessOfAPI = function(){};

In which case it would be pretty clear to see that the var is only in the scope within the block and there is no external reference to it from the wrapping controller.

Any function which could be called discretely (and therefore tested) will be available on the $scope of the controller.

like image 45
shaunhusain Avatar answered Oct 15 '22 09:10

shaunhusain