0
votes

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/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) 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.

2
You seem to have forgotten to include angular-mocks.js.JB Nizet
Thanks @JBNizet. I did miss that. But I get a new error now. I updated the questions.Jop.pop

2 Answers

1
votes

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);
  });

});
0
votes

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);
  });
});