Ошибки Angular / Karma Unit Test после 14 тестов - независимо от самого теста

0

Общая проблема

Мы строим приложение AngularJS и используем карму/жасмин для модульных тестов. После того, как мы запустили карму и смогли успешно запустить тесты, мы столкнулись с действительно странной ошибкой.

По какой-то причине мы не можем запускать более 14 отдельных тестов. Каким-то образом число кажется релевантным, так как не имеет значения, какие тесты я удаляю или добавляю.

В настоящее время есть два контроллера и одна служба, которые имеют тесты.

Когда мы добавим больше тестов к любому из спецификаций, gulp test-unit gulp потерпит неудачу с ошибкой инжектора, где он заявляет, что он не может загрузить модуль без особых особенностей. Даже когда новый тест expect(true).toEqual(true); только expect(true).toEqual(true); Как я писал, неважно, где и какой тест мы добавляем, он всегда терпит неудачу с более чем 14 тестами.

Даже когда мы удаляем все тесты и просто проверяем "true = true". Я не мог найти ничего в конфигурации кармы, что ограничивает количество тестов, которые можно запустить. Я также не нашел ничего похожего в Интернете. Что я не вижу?

(Я знаю о несогласованном наименовании)

Обновить:

Я теперь заметил, что тесты, в соответствии с журналом отладки кармы, работают успешно. Тем не менее ошибка все же появляется. Но это, возможно, не проблема кармы.

Это наш конфиг Karma:

карма-unit.conf.js

var sharedConfig = require('./karma-shared.conf');

module.exports = function (config) {
  var conf = sharedConfig();

  conf.files = conf.files.concat([

    //extra testing code
    'bower_components/angular-mocks/angular-mocks.js',

    //mocha stuff
    'tests/mocha.conf.js',

    //test files
    './tests/unit/**/*.js'
  ]);

  config.set(conf);
};

карма-shared.conf.js

module.exports = function() {
    return {
        basePath: '../',
        frameworks: ['jasmine','mocha'],
        reporters: ['progress'],
        browsers: ['Chrome', 'Safari'],
        autoWatch: true,

        // these are default values anyway
        singleRun: false,
        colors: true,

        files : [
            //3rd Party Code

            //App-specific Code
            'build/vendor.js',
            'build/vendor.ui.js',
            'build/vendor.datatables.js',
            'build/app.js',

            //Test-Specific Code

        ]
    };
};

Это три спецификации:

LoginCtrlSpec.js

describe('LoginController', function () {
  var loginCtrl'enter code here'
    , scope
    , UserService
    , $controller
    , $rootScope
    , validUser = '[email protected]'
    , inValidUser = '[email protected]'
    , password = 'superst(r/l)ongpassword'
    , backendIsFunctional = true
    , theCookies = {}
    ;
  var userObject = {
    email: validUser,
    first_name: 'Maria',
    last_name: 'Tortilla',
    id: 1,
    authentication_token: 'thisisaveryvalidtoken'
  };
// load other modules and provide services
  beforeEach(function () {
    module('app.auth');
    module('ui.router');
    module(function ($provide) {
      /**/
      $provide.service('UserService', function () {
        this.login = function (email, password) {
          //prepare responses for success and failure
          var successResponse = {
            first_name: 'Maria',
            last_name: 'Tortilla',
            authentication_token: '69XyesVbU4ja8HYGtTN4',
            authentication_token_created_at: '2016-07-20T11:34:42.567Z',
            has_changed_password: true,
            data: {
              user: {}
            }
          };
          var failureResponse = {
            status: 401,
            data: {
              user: {}
            }
          };
          //check credentials
          if (
            email === '[email protected]' &&
            password === 'superst(r/l)ongpassword'
          ) {
            //return success response
            return {
              then: function (success, error) {
                success(successResponse);
              }
            }
          } else {
            //return error response
            return {
              then: function (success, error) {
                error(failureResponse);
              }
            }
          }
        };
        this.getCurrentUser = function () {
          return {
            then: function (success, error) {
              if (backendIsFunctional) {
                success(userObject);
              } else {
                error({});
              }
            }
          }
        };
        this.updateCurrentUser = function () {
          return {
            then: function (callback) {
              callback(userObject);
            }
          }
        };
        this.setCurrentUser = function (user) {
          this.currentUser = user;
        };
        this.currentUser = {};
      });
      /**/
      $provide.service('lazyScript', function () {
        return {
          register: function (args) {
            return {
              then: function (callback) {
              }
            }
          }
        }
      });
      /**/
      $provide.service('$state', function () {
        this.go = jasmine.createSpy();
      });
      /**/
      $provide.service('$cookies', function () {
        return {
          putObject: function (name, data) {
            // console.log('put '+name+' with '+data);
            theCookies[name] = data;
          },
          remove: function (name) {
            // console.log('removed cookie '+name);
            delete theCookies[name];
          },
          getObject: function (name) {
            return theCookies[name];
          }
        };
      });
      /**/
    });
  });
  // inject dependencies
  beforeEach(inject(function ($injector) {
    $controller = $injector.get('$controller');
    $rootScope = $injector.get('$rootScope');
    // $state = $injector.get('$state');
    scope = $rootScope.$new();
    loginCtrl = $controller('LoginCtrl', {
      '$scope': scope
    });
  }));
  // perform some tests
  /**/
  it('forwards the user to the dashboard after successful login', function () {
    expect(loginCtrl).not.toBe(null);
    spyOn(scope, 'finishAndEnter');
    scope.email = validUser;
    scope.password = password;
    scope.login();
    $rootScope.$apply();
    expect(scope.finishAndEnter).toHaveBeenCalled();
  });
  /**/
  it('denies access with invalid credentials', function () {
    spyOn(scope, 'finishAndEnter');
    scope.email = inValidUser;
    scope.login();
    $rootScope.$apply();
    expect(scope.finishAndEnter).not.toHaveBeenCalled();
  });
  /**/
  it('should not let the user complete her profile without first or last name', function () {
    spyOn(scope, 'demandPersonalInfo');
    scope.updateDetails = {first_name: undefined, last_name: undefined};
    scope.updateUserDetails();
    expect(scope.demandPersonalInfo).toHaveBeenCalled();
  });
  /**/
  it('should not let the user complete her profile without only first name', function () {
    spyOn(scope, 'demandPersonalInfo');
    scope.updateDetails = {first_name: 'Maria', last_name: undefined};
    scope.updateUserDetails();
    expect(scope.demandPersonalInfo).toHaveBeenCalled();
  });
  /**/
  it('should not let the user complete her profile without only last name', function () {
    spyOn(scope, 'demandPersonalInfo');
    scope.updateDetails = {first_name: undefined, last_name: 'Tortilla'};
    scope.updateUserDetails();
    expect(scope.demandPersonalInfo).toHaveBeenCalled();
  });
  /**/
   it('should let a user update her profile with first and last name', function () {
    spyOn(scope, 'demandPersonalInfo');
    scope.updateDetails = {first_name: 'Maria', last_name: 'Tortilla'};
    console.log(scope.updateDetails);
    scope.updateUserDetails();
    expect(scope.demandPersonalInfo).not.toHaveBeenCalled();
  });
   /**/
});

AdminControllerSpec.js

describe('Unit: testing AdministrationController Controller module', function () {
  'use strict';
  //references to mocked services
  var mockUserService;


  beforeEach(function () {
    //mock userservice
    module(function ($provide) {
      $provide.service('UserService', function () {
        this.getCurrentUser = jasmine.createSpy('getCurrentUser');
      });
    });

    //load admin module
    module('app.admin');
  });

  var adminCtrl, scope;

  beforeEach(inject(function ($controller, $rootScope, UserService) {

    //catch injected UserService and assign to mocked one
    mockUserService = UserService;

    scope = $rootScope.$new();
    adminCtrl = $controller('AdministrationController', {
      '$scope': scope
    });
  }));

  describe('AdministrationController', function () {

    it('AdministrationController should be existing', function () {
      expect(adminCtrl).not.toBe(null);
    });
    it('means that hello is hello', function () {
      expect(scope.hello).toEqual('Hello');
    });
    it('is helgig', function () {
      //call a method that uses the userservice
      scope.login();

      //the userservice should have been called from login()
      expect(mockUserService.getCurrentUser).toHaveBeenCalled();

    });
  });

});

UserServiceSpec.js

describe('UserService', function () {

  var UserService;

  var validUserName = '[email protected]';
  var validUserPassword = 'goopassword';
  var inValidUserName = '[email protected]';
  var backendIsWorking = true;
  // var qReturnesUser = false;
  var validUser = {
    'email': '[email protected]',
    'first_name': 'Maria',
    'last_name': 'Tortilla',
    'authentication_token': 'yeahSomeT0k3nIThink_dontYu?'
  };

  var updatedUser = {
    'first_name': 'Harro',
    'email': '[email protected]',
    'last_name': 'Tortilla',
    'authentication_token': 'yeahSomeT0k3nIThink_dontYu?'
  };

  var updateUserResponse = {
    status: 200,
    user: updatedUser
  };

  var httpSuccessResponse = {
    data: validUser
  };
  var httpErrorResponse = {
    data: {
      status: 401,
      user: {}
    }
  };

  //mocked cookie dictionary
  var theCookies = {};

  //load modules
  beforeEach(function () {
    module('ngResource');
    module('app.common');
    module(function ($provide) {

      $provide.service('$q', function () {
        return {
          defer: function () {
            return {
              resolve: function () {
              },
              reject: function () {
              },
              promise:{
                then: function(){}
              }
            };
          }
        };
      });
      $provide.service('$http', function () {
        return function (config) {

          var pw = config.data.password;
          var user = config.data.email;

          var responseObject = {};

          //login and logout response
          if (config.url.indexOf('sign_in') >= 0 || config.url.indexOf('sign_out') >= 0) {
            responseObject = {
              //success portion of response
              success: function (callback) {
                var response;

                //decide which actual response should be returned
                if (pw === validUserPassword && user === validUserName) {
                  response = httpSuccessResponse;
                  callback(response);
                } else {
                  response = httpErrorResponse;
                }
                //return chained error portion
                return {
                  error: function (callback) {
                    callback(response);
                  }
                }
              }
            };
          }

          return responseObject;
        }
      });
      $provide.service('$cookies', function () {
        return {
          putObject: function (name, data) {
            // console.log('put '+name+' with '+data);
            theCookies[name] = data;
          },
          remove: function (name) {
            // console.log('removed cookie '+name);
            delete theCookies[name];
          },
          getObject: function(name){
            return theCookies[name];
          }
        };
      });
      $provide.factory('User', function () {
        return {
          update: function (user, successCallback, errorCallback) {

            if (backendIsWorking) {
              successCallback(updateUserResponse);
            } else {
              errorCallback(httpErrorResponse);
            }
          },
          get: function (user, successCallback, errorCallback) {
            if (backendIsWorking) {
              successCallback(validUser);
            } else {
              errorCallback(httpErrorResponse);
            }
          }
        }
      });
    });
  });

  //inject stuff
  beforeEach(inject(function ($injector) {
    // UserService = _UserService_;
    $resource = $injector.get('$resource');
    UserService = $injector.get('UserService');
  }));

  //do the tests
  it('should have UserSerivce defined', function () {
    // console.log(UserService);
    expect(UserService).toBeDefined();
  });

  it('should have a user object after login', function () {
    UserService.login(validUserName, validUserPassword);
    expect(UserService.currentUser).toBeDefined();
    expect(UserService.currentUser).toEqual(validUser);
  });

  it('should have a empty user object after invalid login', function () {
    UserService.login(inValidUserName, validUserPassword);
    expect(UserService.currentUser).toBeDefined();
    expect(UserService.currentUser).toEqual(null);
  });

  it('should clear the user object after logout', function () {
    UserService.currentUser = validUser;
    expect(UserService.currentUser).toBeDefined();
    UserService.logout();
    expect(UserService.currentUser).toBe(null);
  });

  it('should set the current user', function () {
    expect(UserService.currentUser).toBe(null);
    UserService.setCurrentUser(validUser);
    expect(UserService.currentUser).toEqual(validUser);
  });

  it('should update the users data', function () {
    spyOn(UserService, 'setCurrentUser');
    UserService.currentUser = validUser;
    UserService.updateCurrentUser();
    expect(UserService.setCurrentUser).toHaveBeenCalledWith(updatedUser);
  });
});

Наконец, это Ошибка, которую мы получаем:

#

Независимо от того, какой тест мы удалим, он всегда является той же ошибкой.

 Error: [$injector:modulerr] http://errors.angularjs.org/1.5.8/$injector/modulerr?p0=app&p1=%5B%24injector%3Amodulerr%5D%20http%3A%2F%2Ferrors.angularjs.org%2F1.5.8%2F%24injector%2Fmodulerr%3Fp0%3DngCookies%26p1%3D%255B%2524injector%253Anomod%255D%2520http%253A%252F%252Ferrors.angularjs.org%252F1.5.8%252F%2524injector%252Fnomod%253Fp0%253DngCookies%250Ahttp%253A%252F%252Flocalhost%253A9876%252Fbase%252Fbuild%252Fvendor.js%253F9b2b4c4d081dd795c95280a4f7af90157c7ae917%253A129%253A417%250Ahttp%253A%252F%252Flocalhost%253A9876%252Fbase%252Fbuild%252Fvendor.js%253F9b2b4c4d081dd795c95280a4f7af90157c7ae917%253A148%253A100%250Ab%2540http%253A%252F%252Flocalhost%253A9876%252Fbase%252Fbuild%252Fvendor.js%253F9b2b4c4d081dd795c95280a4f7af90157c7ae917%253A147%253A143%250Ahttp%253A%252F%252Flocalhost%253A9876%252Fbase%252Fbuild%252Fvendor.js%253F9b2b4c4d081dd795c95280a4f7af90157c7ae917%253A147%253A386%250Ahttp%253A%252F%252Flocalhost%253A9876%252Fbase%252Fbuild%252Fvendor.js%253F9b2b4c4d081dd795c95280a4f7af90157c7ae917%253A162%253A473%250Aq%2540http%253A%252F%252Flocalhost%253A9876%252Fbase%252Fbuild%252Fvendor.js%253F9b2b4c4d081dd795c95280a4f7af90157c7ae917%253A130%253A359%250Ag%2540http%253A%252F%252Flocalhost%253A9876%252Fbase%252Fbuild%252Fvendor.js%253F9b2b4c4d081dd795c95280a4f7af90157c7ae917%253A162%253A320%250Ahttp%253A%252F%252Flocalhost%253A9876%252Fbase%252Fbuild%252Fvendor.js%253F9b2b4c4d081dd795c95280a4f7af90157c7ae917%253A162%253A489%250Aq%2540http%253A%252F%252Flocalhost%253A9876%252Fbase%252Fbuild%252Fvendor.js%253F9b2b4c4d081dd795c95280a4f7af90157c7ae917%253A130%253A359%250Ag%2540http%253A%252F%252Flocalhost%253A9876%252Fbase%252Fbuild%252Fvendor.js%253F9b2b4c4d081dd795c95280a4f7af90157c7ae917%253A162%253A320%250Acb%2540http%253A%252F%252Flocalhost%253A9876%252Fbase%252Fbuild%252Fvendor.js%253F9b2b4c4d081dd795c95280a4f7af90157c7ae917%253A166%253A337%250Ac%2540http%253A%252F%252Flocalhost%253A9876%252Fbase%252Fbuild%252Fvendor.js%253F9b2b4c4d081dd795c95280a4f7af90157c7ae917%253A143%253A392%250ABc%2540http%253A%252F%252Flocalhost%253A9876%252Fbase%252Fbuild%252Fvendor.js%253F9b2b4c4d081dd795c95280a4f7af90157c7ae917%253A144%253A180%250Ahttp%253A%252F%252Flocalhost%253A9876%252Fbase%252Fbuild%252Fapp.js%253F3b907e783e3f83ec76cf288ed98d542361f9ed3a%253A287%253A22%250Aj%2540http%253A%252F%252Flocalhost%253A9876%252Fbase%252Fbuild%252Fvendor.js%253F9b2b4c4d081dd795c95280a4f7af90157c7ae917%253A2%253A26930%250AfireWith%2540http%253A%252F%252Flocalhost%253A9876%252Fbase%252Fbuild%252Fvendor.js%253F9b2b4c4d081dd795c95280a4f7af90157c7ae917%253A2%253A27739%250Aready%2540http%253A%252F%252Flocalhost%253A9876%252Fbase%252Fbuild%252Fvendor.js%253F9b2b4c4d081dd795c95280a4f7af90157c7ae917%253A2%253A29543%250AI%2540http%253A%252F%252Flocalhost%253A9876%252Fbase%252Fbuild%252Fvendor.js%253F9b2b4c4d081dd795c95280a4f7af90157c7ae917%253A2%253A29728%0Ahttp%3A%2F%2Flocalhost%3A9876%2Fbase%2Fbuild%2Fvendor.js%3F9b2b4c4d081dd795c95280a4f7af90157c7ae917%3A129%3A417%0Ahttp%3A%2F%2Flocalhost%3A9876%2Fbase%2Fbuild%2Fvendor.js%3F9b2b4c4d081dd795c95280a4f7af90157c7ae917%3A163%3A224%0Aq%40http%3A%2F%2Flocalhost%3A9876%2Fbase%2Fbuild%2Fvendor.js%3F9b2b4c4d081dd795c95280a4f7af90157c7ae917%3A130%3A359%0Ag%40http%3A%2F%2Flocalhost%3A9876%2Fbase%2Fbuild%2Fvendor.js%3F9b2b4c4d081dd795c95280a4f7af90157c7ae917%3A162%3A320%0Ahttp%3A%2F%2Flocalhost%3A9876%2Fbase%2Fbuild%2Fvendor.js%3F9b2b4c4d081dd795c95280a4f7af90157c7ae917%3A162%3A489%0Aq%40http%3A%2F%2Flocalhost%3A9876%2Fbase%2Fbuild%2Fvendor.js%3F9b2b4c4d081dd795c95280a4f7af90157c7ae917%3A130%3A359%0Ag%40http%3A%2F%2Flocalhost%3A9876%2Fbase%2Fbuild%2Fvendor.js%3F9b2b4c4d081dd795c95280a4f7af90157c7ae917%3A162%3A320%0Acb%40http%3A%2F%2Flocalhost%3A9876%2Fbase%2Fbuild%2Fvendor.js%3F9b2b4c4d081dd795c95280a4f7af90157c7ae917%3A166%3A337%0Ac%40http%3A%2F%2Flocalhost%3A9876%2Fbase%2Fbuild%2Fvendor.js%3F9b2b4c4d081dd795c95280a4f7af90157c7ae917%3A143%3A392%0ABc%40http%3A%2F%2Flocalhost%3A9876%2Fbase%2Fbuild%2Fvendor.js%3F9b2b4c4d081dd795c95280a4f7af90157c7ae917%3A144%3A180%0Ahttp%3A%2F%2Flocalhost%3A9876%2Fbase%2Fbuild%2Fapp.js%3F3b907e783e3f83ec76cf288ed98d542361f9ed3a%3A287%3A22%0Aj%40http%3A%2F%2Flocalhost%3A9876%2Fbase%2Fbuild%2Fvendor.js%3F9b2b4c4d081dd795c95280a4f7af90157c7ae917%3A2%3A26930%0AfireWith%40http%3A%2F%2Flocalhost%3A9876%2Fbase%2Fbuild%2Fvendor.js%3F9b2b4c4d081dd795c95280a4f7af90157c7ae917%3A2%3A27739%0Aready%40http%3A%2F%2Flocalhost%3A9876%2Fbase%2Fbuild%2Fvendor.js%3F9b2b4c4d081dd795c95280a4f7af90157c7ae917%3A2%3A29543%0AI%40http%3A%2F%2Flocalhost%3A9876%2Fbase%2Fbuild%2Fvendor.js%3F9b2b4c4d081dd795c95280a4f7af90157c7ae917%3A2%3A29728
at build/vendor.js:163
Chrome 52.0.2743 (Mac OS X 10.11.5): Executed 15 of 15 ERROR (0.187 secs / 0.123 secs)
Safari 9.1.1 (Mac OS X 10.11.5): Executed 15 of 15 ERROR (0.005 secs / 0.045 secs)

Любое понимание того, что может быть неправильно, было бы весьма признательно.

  • 0
    Происходит ли это, если вы просто запускаете свои тесты с кармой ( karma run ) без Gulp в качестве посредника?
  • 0
    Да, это все еще происходит. Я также заметил, что тесты действительно выполняются, так как отладчик Karma регистрирует УСПЕХ для каждого теста и сообщает, что пропущено 0. Кажется, что ошибка происходит после запуска тестов и, в конце концов, может даже не быть проблемой кармы.
Показать ещё 1 комментарий
Теги:
unit-testing
jasmine
karma-runner

1 ответ

0
Лучший ответ

Оказывается, угловые куки не были упакованы в vendor.js.

Вывод показал себя после того, как мы начали тестирование с несжатым кодом, и нам удалось получить некоторые прочитанные сообщения об ошибках. Оттуда это было довольно очевидно через короткое время. Модуль не был загружен, потому что он недоступен.

Поэтому мы добавили

{"chunks": {
    ...
    "vendor":{
        ....
        "angular-cookies",
        ...
    }
  }
} 

а также

 {"chunks": {
    ...
    "paths_uncompressed":{
        ....
         "angular-cookies": "bower_components/angular-cookies/angular-cookies.js"
        ...
    }
  }
} 

Вот и все. Благодарю!

Ещё вопросы

Сообщество Overcoder
Наверх
Меню