Получение углового контроллера через $ scope в модульном тесте

0

Я пытаюсь получить контроллер через $ scope в моем тесте на жасмин, но терпеть неудачу. Кто-нибудь знает, почему?

При использовании синтаксиса controllerAs объект контроллера помещается в объект $ scope с использованием имени, указанного в контроллереAs. Таким образом, выполнив приведенный ниже код в браузере, используя ng-app = 'MyApp' для загрузки в угловое, я могу использовать инструменты chrome-dev для поиска и выбора элемента директивы и введите $0.scope().myDirCtrl в консоли. Это дает объект контроллера, поэтому почему я не могу получить объект контроллера в своем модульном тесте?

Выполнение сниппета ниже приведет к созданию автономной среды тестирования браузера жасмина. Спецификация для теста указана в нижней части фрагмента. Код, с которым я столкнулся, заключается в следующем:

expect($scope.myDirCtrl).toBeDefined();

/* --------------------------------------
    Source code
   --------------------------------------*/
(function(angular) {
  'use strict';

  // Setup the template -----------------
  angular.module('MyApp.tpls', [])
  .run(['$templateCache', function($templateCache) {
    $templateCache.put('partials/myDirective.html',
                       '<div>{{myDirCtrl.testValue}}</div>');
  }]);

  // Setup the app ----------------------
  angular.module('MyApp', ['MyApp.tpls'])
    .directive('myDirective', myDirective)
    .controller('MyDirectiveController', MyDirectiveController);

  function myDirective() {
    return {
      restrict        : 'E',
      templateUrl     : 'partials/myDirective.html',
      transclude      : true,
      controllerAs    : 'myDirCtrl',
      bindToController: true,
      scope           : {},
      controller      : 'MyDirectiveController'
    };
  }

  MyDirectiveController.$inject = ['$scope'];
  function MyDirectiveController($scope) {
    var ctrl = this;
    ctrl.testValue = 'Only a test';
  }
})(angular);



/* --------------------------------------
    Test specifications
   --------------------------------------*/
(function (module) {
  'use strict';
  
  // Define the tests -------------------
  describe('My directive test', function () {
    var $compile, $rootScope, $scope;

    beforeEach(module('MyApp'));
    beforeEach(inject(function(_$compile_, _$rootScope_) {
      $compile   = _$compile_;
      $rootScope = _$rootScope_;
      $scope     = $rootScope.$new();
    }));

    it('scope should contain a controller reference', function () {
      var element = $compile(angular.element('<my-directive></my-directive>'))($scope);
      $scope.$digest();
      expect($scope.myDirCtrl).toBeDefined();
    });
  });
})(module);
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.4/jasmine.css">

<script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.4/jasmine.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.4/jasmine-html.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.4/boot.min.js"></script>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.1/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.1/angular-mocks.js"></script>
Теги:
unit-testing
jasmine

1 ответ

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

Проблема в том, что $scope в вашей спецификации - это не та область, которая используется в MyDirectiveController. Директива создает еще одну область для контроллера, которая становится дочерним элементом вашей спецификации. Вы должны быть в состоянии проверить это с помощью угловых внутренних свойств в своем тесте:

it('scope should contain a controller reference', function () {
    var element = $compile(angular.element('<my-directive></my-directive>'))($scope);
    $scope.$digest();

    // controller is actually in a child scope
    console.log($scope.$$childHead.myDirCtrl);

    expect($scope.myDirCtrl).toBeDefined();
});

Но я бы не стал полагаться на эти частные свойства Angular, такие как $$childHead, потому что они считаются частными и не являются частью публичного API. Я думаю, что это Q/A AngularJS - доступ к охвату ребенка может помочь вам решить эту проблему.

  • 0
    Ты прав. expect(angular.element('> *', element).scope().myDirCtrl).toBeDefined(); дает истину. Это всегда верно для директив, или это то, что верно только для конкретной установки DDO? Если последнее, какие настройки представляют собой необходимость создания новой детской площадки для размещения контроллера? transclue : true ?
  • 1
    В вашей директиве у вас есть scope: {} свойств scope: {} . Определяя это дополнительное свойство, вы заставляете директиву создавать собственную так называемую «изолированную» область видимости. ( документы ). Если вы удалите его, он унаследует от родительской области и тест будет пройден.
Показать ещё 1 комментарий

Ещё вопросы

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