Как модульное тестирование изолированной области директивы в AngularJS



что такое хороший способ модульного тестирования изолированной области в AngularJS



JSFiddle показывает модульный тест



директива фрагмент



    scope: {name: '=myGreet'},
link: function (scope, element, attrs) {
//show the initial state
greet(element, scope[attrs.myGreet]);

//listen for changes in the model
scope.$watch(attrs.myGreet, function (name) {
greet(element, name);
});
}


Я хочу убедиться, что директива прослушивает изменения-это делает не работа с изолированной объем:



    it('should watch for changes in the model', function () {
var elm;
//arrange
spyOn(scope, '$watch');
//act
elm = compile(validHTML)(scope);
//assert
expect(scope.$watch.callCount).toBe(1);
expect(scope.$watch).toHaveBeenCalledWith('name', jasmine.any(Function));
});


обновление:
Я получил его для работы, проверив, были ли ожидаемые наблюдатели добавлены в дочернюю область, но она очень хрупкая и, вероятно, использует аксессоры в недокументированном виде (ака могут быть изменены без предварительного уведомления!).



//this is super brittle, is there a better way!?
elm = compile(validHTML)(scope);
expect(elm.scope().$$watchers[0].exp).toBe('name');


обновление 2:
Как я уже упоминал, это хрупко! Идея все еще работает, но в более новых версиях AngularJS метод доступа изменился с scope() до isolateScope():



//this is STILL super brittle, is there a better way!?
elm = compile(validHTML)(scope);
expect(elm.isolateScope().$$watchers[0].exp).toBe('name');
653   4  

4 ответов:

посмотреть angular element api docs. Если вы используете элемент.область() вы получаете область элемента, которую вы определили в свойстве scope вашей директивы. Если вы используете элемент.isolateScope () вы получаете весь изолированный объем. Например, если ваша директива выглядит примерно так:

scope : {
 myScopeThingy : '='
},
controller : function($scope){
 $scope.myIsolatedThingy = 'some value';
}

затем вызов стихии.scope() в вашем тесте вернет

{ myScopeThingy : 'whatever value this is bound to' }

но если вы вызываете элемент.isolateScope() вы получите

{ 
  myScopeThingy : 'whatever value this is bound to', 
  myIsolatedThingy : 'some value'
}

Это верно для углового 1.2.2 или 1.2.3, точно не уверен. В предыдущих версиях у вас был только элемент.масштаб.)(

можно сделать var isolateScope = myDirectiveElement.scope() чтобы изолировать область.

вам действительно не нужно проверять, что $watch был вызван.. это больше тестирование angularjs, чем тестирование вашего приложения. Но я думаю, что это просто пример для вопроса.

переместить логику в отдельный контроллер, т. е.:

//will get your isolate scope
function MyCtrl($scope)
{
  //non-DOM manipulating ctrl logic here
}
app.controller(MyCtrl);

function MyDirective()
{
  return {
    scope     : {},
    controller: MyCtrl,
    link      : function (scope, element, attrs)
    {
      //moved non-DOM manipulating logic to ctrl
    }
  }
}
app.directive('myDirective', MyDirective);

и проверить последний, как и любой контроллер-передача объекта scope непосредственно (см. контроллерыздесь для примера).

Если вам нужно вызвать $watch в вашем тесте, сделайте:

describe('MyCtrl test', function ()
{
  var $rootScope, $controller, $scope;

  beforeEach(function ()
  {
    inject(function (_$rootScope_, _$controller_)
    {
      // The injector unwraps the underscores (_) from around the parameter names when matching
      $rootScope = _$rootScope_;
      $controller = _$controller_;
    });

    $scope = $rootScope.$new({});
    $scope.foo = {x: 1}; //initial scope state as desired
    $controller(MyCtrl, {$scope: $scope}); //or by name as 'MyCtrl'
  });

  it('test scope property altered on $digest', function ()
  {
    $scope.$digest(); //trigger $watch
    expect($scope.foo.x).toEqual(1); //or whatever
  });
});

Я не уверен, что это возможно с изолированной областью (хотя я надеюсь, что кто-то докажет, что я ошибаюсь). Область изоляции, которая создается в директиве, ну, изолирована, поэтому метод $watch в директиве отличается от области, за которой вы шпионите в модульном тесте. Если вы измените scope: {} на scope: true, область директивы будет наследовать прототипически, и ваши тесты должны пройти.

Я думаю, что это не самое идеальное решение, потому что иногда (много времени), изолировать область-это хорошо.

Comments

    Ничего не найдено.