简体   繁体   中英

Unit testing in AngularJS with Jasmine and Chutzpah

I am trying to write Unit test cases for existing SPA project built on angularJS. I get the "Can't find variable: module" error whenever I try to execute the code.

I installed the libraries using npm.

I used Chutzpah and Jasmine libraries for this.

appModule.js

(function () {
    'use strict';

    angular.module('app', [
        'ngMessages',
        'ui.router',
        'ui.router.title'
    ]).run(['REQ_TOKEN', function (REQ_TOKEN) {
        //...
    }]).config(['$httpProvider', function ($httpProvider) {
        $httpProvider.defaults.headers.common["X-Requested-With"] = 'XMLHttpRequest';
    }]);
})();

site.js

(function () {
    'use strict';

    window.deferredBootstrapper.bootstrap({
        element: window.document,
        module: 'app',
        resolve: {
            REQ_TOKEN: ['$http', function ($http) {
                return $http.get('/.../', { ignoreLoadingBar: true, params: { ts: new Date().getTime() } });
            }]
        }
    });
})();

appController.js:

(function () {
'use strict';

  angular
      .module('app')
      .controller('appController', appController);

  appController.$inject = ['apiServices', '$scope'];

  function appController(apiServices, $scope) {
    $scope.value = 5;
  }
})();

apiServices.js

(function () {
'use strict';

  angular
      .module('app')
      .factory('apiServices', apiServices);

  apiServices.$inject = ['$http', '$log', '$q'];

  function apiServices($http, $log, $q) {
    var clientServicesPath = '/api/ClientServices',
    service =
       {  .......  };

    return service;
  }
})();

appControllerSpec.js

/// <reference path="../../../lib/angular/angular.js" />
/// <reference path="../../../lib/angular-deferred-bootstrap/angular-deferred-bootstrap.js" />
/// <reference path="../../../lib/angular-ui-router/release/angular-ui-router.js" />
/// <reference path="../../../lib/angular-ui-router-title/angular-ui-router-title.js" />
/// <reference path="../../../lib/angular-messages/angular-messages.js" />

/// <reference path="../../modules/appmodule.js" />
/// <reference path="../../site.js" />
/// <reference path="../../factories/sharedfunctions.js" />

/// <reference path="../../services/apiservices.js" />
/// <reference path="../../controllers/appcontroller.js" />
/// <reference path="../../../../node_modules/jasmine/bin/jasmine.js" />
/// <reference path="../../../../node_modules/jasmine/lib/jasmine.js" />
/// <reference path="../../../../node_modules/jasmine-ajax/lib/mock-ajax.js" />
/// <reference path="../../../lib/angular-mocks/angular-mocks.js" />

describe('When using appController ', function () {
  //initialize Angular
  beforeEach(module('app'));   
  var ctrl, scope, apiServices;

  beforeEach(inject(function ($injector) {
    apiServices = $injector.get('apiServices');
  }));

  beforeEach(inject(function ($controller, $rootScope, apiServices) {
    scope = $rootScope.$new();
    var ctrl = $controller('appController', { $scope: scope, apiServices: apiServices });
  }));

  it('initial value is 5', function () {
    expect(scope.value).toBe(5);
  });
});

I get the following error:

Test 'When using appController :initial value is 5' failed Error: [$injector:unpr] Unknown provider: REQ_TOKENProvider <- REQ_TOKEN http://errors.angularjs.org/1.5.1/ $injector/unpr?p0=REQ_TOKENProvider%20%3C-%20REQ_TOKEN in file:///C:/Users/Bhanu/......./lib/angular/angular.js (line 4418) at getService (file:///C:/Users/Bhanu/......./lib/angular/angular.js:4571:46) at file:///C:/Users/Bhanu/......./lib/angular/angular.js:4423:48 at getService (file:///C:/Users/Bhanu/......./lib/angular/angular.js:4571:46) at injectionArgs (file:///C:/Users/Bhanu/......./lib/angular/angular.js:4595:68) at invoke (file:///C:/Users/Bhanu/......./lib/angular/angular.js:4617:31) Error: [$injector:unpr] Unknown provider: REQ_TOKENProvider <- REQ_TOKEN http://errors.angularjs.org/1.5.1/ $injector/unpr?p0=REQ_TOKENProvider%20%3C-%20REQ_TOKEN in file:///C:/Users/Bhanu/......./lib/angular/angular.js (line 4418) at getService (file:///C:/Users/Bhanu/......./lib/angular/angular.js:4571:46) at file:///C:/Users/Bha nu/......./lib/angular/angular.js:4423:48 at getService (file:///C:/Users/Bhanu/......./lib/angular/angular.js:4571:46) at injectionArgs (file:///C:/Users/Bhanu/......./lib/angular/angular.js:4595:68) at invoke (file:///C:/Users/Bhanu/......./lib/angular/angular.js:4617:31) in C:\\Users\\Bhanu.......\\js\\TestingJS\\controllers\\appControllerSpec.js (line 43)

0 passed, 1 failed, 1 total (chutzpah).

I have tried all the possible solutions but none worked for me. I ran the tests directly by right clicking the Test controller file and selecting the option "Run JS Tests".

I feel there are more pieces towards configuration. Please help me with this.

This is not the way you pass your controller services to you tests, and you are creating a new var ctrl variable withing forEach. Also, there is a single instance of the injector per application. You must get your controller and your service instance withing the same inject(...)

Wrong

var ctrl = $controller('appController', { $scope: scope, apiServices: apiServices });

Right

describe('When using appController ', function () {

  var ctrl, scope, apiServices;

  beforeEach(inject(function ($controller, $rootScope) {
    // Put it here for the sake of organization
    //initialize Angular
    module('app');

    scope = $rootScope.$new();
    // Get controller instance
    ctrl = $controller('appController');
    // Get service instance
    apiServices = $injector.get('apiServices');
  }));

  it('initial value is 5', function () {
    expect(scope.value).toBe(5);
  });

});

According to the documentation of deferredBootstrapper ,

Since the constants that deferredBootstrapper adds to your applications module are not available in your unit tests, it makes sense to provide them in a global beforeEach():

So, appControllerSpec.js should be

/// <reference path="../../../lib/angular/angular.js" />
/// <reference path="../../../lib/angular-deferred-bootstrap/angular-deferred-bootstrap.js" />
/// <reference path="../../../lib/angular-ui-router/release/angular-ui-router.js" />
/// <reference path="../../../lib/angular-ui-router-title/angular-ui-router-title.js" />
/// <reference path="../../../lib/angular-messages/angular-messages.js" />

/// <reference path="../../modules/appmodule.js" />
/// <reference path="../../site.js" />
/// <reference path="../../factories/sharedfunctions.js" />

/// <reference path="../../services/apiservices.js" />
/// <reference path="../../controllers/appcontroller.js" />
/// <reference path="../../../../node_modules/jasmine/bin/jasmine.js" />
/// <reference path="../../../../node_modules/jasmine/lib/jasmine.js" />
/// <reference path="../../../../node_modules/jasmine-ajax/lib/mock-ajax.js" />
/// <reference path="../../../lib/angular-mocks/angular-mocks.js" />

describe('When using appController ', function () {
  //initialize Angular
  beforeEach(module('app'));   
  var ctrl, scope, apiServices, REQ_TOKEN;

  beforeEach(function () {
      module(function ($provide) {
          $provide.constant('REQ_TOKEN', { token: '/dummyValue' });
      });
  });

  beforeEach(inject(function ($controller, $rootScope, apiServices) {
    scope = $rootScope.$new();
    REQ_TOKEN = $injector.get('REQ_TOKEN');
    apiServices = $injector.get('apiServices');
    var ctrl = $controller('appController', { $scope: scope});
  }));

  it('initial value is 5', function () {
    expect(scope.value).toBe(5);
  });
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM