IsolateScope() возвращает undefined при использовании templateUrl
У меня есть директива, которую я хочу удалить, но я столкнулся с проблемой, что я не могу получить доступ к моей изолированной области. Здесь директива:
<my-directive></my-directive>
И код позади него:
angular.module('demoApp.directives').directive('myDirective', function($log) {
return {
restrict: 'E',
templateUrl: 'views/directives/my-directive.html',
scope: {},
link: function($scope, iElement, iAttrs) {
$scope.save = function() {
$log.log('Save data');
};
}
};
});
И вот мой unittest:
describe('Directive: myDirective', function() {
var $compile, $scope, $log;
beforeEach(function() {
// Load template using a Karma preprocessor (http://tylerhenkel.com/how-to-test-directives-that-use-templateurl/)
module('views/directives/my-directive.html');
module('demoApp.directives');
inject(function(_$compile_, _$rootScope_, _$log_) {
$compile = _$compile_;
$scope = _$rootScope_.$new();
$log = _$log_;
spyOn($log, 'log');
});
});
it('should work', function() {
var el = $compile('<my-directive></my-directive>')($scope);
console.log('Isolated scope:', el.isolateScope());
el.isolateScope().save();
expect($log.log).toHaveBeenCalled();
});
});
Но когда я распечатываю изолированную область, это приводит к undefined
. Что меня действительно смущает, если вместо templateUrl
я просто использую template
в моей директиве, тогда все работает: isolateScope()
имеет полностью scope
объект в качестве возвращаемого значения, и все отлично. Однако, как-то, при использовании templateUrl
он ломается. Является ли это ошибкой в ng-mocks
или в препроцессоре Karma?
Спасибо заранее.
Ответы
Ответ 1
У меня была та же проблема. Кажется, что при вызове $compile(element)($scope)
в сочетании с использованием templateUrl
цикл дайджеста не запускается автоматически. Итак, вам нужно установить его вручную:
it('should work', function() {
var el = $compile('<my-directive></my-directive>')($scope);
$scope.$digest(); // Ensure changes are propagated
console.log('Isolated scope:', el.isolateScope());
el.isolateScope().save();
expect($log.log).toHaveBeenCalled();
});
Я не уверен, почему функция $compile
не делает этого для вас, но это должно быть какая-то идиосинкразия с тем, как работает templateUrl
, так как вам не нужно звонить на $scope.$digest()
если вы используете встроенный шаблон.
Ответ 2
Мне приходилось высмеивать и стирать $httpBackend
, прежде чем isolateScope()
стал определяться. Обратите внимание, что $scope.$digest()
не имеет значения.
Директива
app.directive('deliverableList', function () {
return {
templateUrl: 'app/directives/deliverable-list-directive.tpl.html',
controller: 'deliverableListDirectiveController',
restrict = 'E',
scope = {
deliverables: '=',
label: '@'
}
}
})
Тест:
it('should be defined', inject(function ($rootScope, $compile, $httpBackend) {
var scope = $rootScope.$new();
$httpBackend.expectGET('app/directives/deliverable-list-directive.tpl.html').respond();
var $element = $compile('<deliverable-list label="test" deliverables="[{id: 123}]"></deliverable-list>')(scope);
$httpBackend.flush();
$httpBackend.verifyNoOutstandingExpectation();
$httpBackend.verifyNoOutstandingRequest();
expect($element).toBeDefined();
expect($element.controller).toBeDefined();
scope = $element.isolateScope();
expect(scope).toBeDefined();
expect(scope.label).toEqual('test');
expect(scope.deliverables instanceof Array).toEqual(true);
expect(scope.deliverables.length).toEqual(1);
expect(scope.deliverables[0]).toEqual({id: 123});
}));
Я использую Angular 1.3.
Ответ 3
С Angularjs 1.3, если вы отключите debugInfoEnabled в конфигурации приложения:
$compileProvider.debugInfoEnabled(false);
isolateScope() возвращает undefined также!!!
Ответ 4
Вы можете настроить karma-ng-html2js-preprocessor плагин. Он преобразует HTML-шаблоны в строку javascript и помещает их в службу Angular $templateCache
.
После установки a moduleName
в конфигурации вы можете объявить модуль в своих тестах, и тогда все ваши шаблоны будут доступны без необходимости издеваться над ними $httpBackend
.
beforeEach(module('partials'));
Вы можете найти, как настроить плагин здесь: http://untangled.io/how-to-unit-test-a-directive-with-templateurl/
Ответ 5
В моем случае я продолжал сталкиваться с этим в тех случаях, когда я пытался изолировать область действия в директиве без свойства изоляции.
function testDirective() {
return {
restrict:'EA',
template:'<span>{{ message }}</span>'
scope:{} // <-- Removing this made an obvious difference
};
}
function testWithoutIsolateScopeDirective() {
return {
restrict:'EA',
template:'<span>{{ message }}</span>'
};
}
describe('tests pass', function(){
var compiledElement, isolatedScope, $scope;
beforeEach(module('test'));
beforeEach(inject(function ($compile, $rootScope){
$scope = $rootScope.$new();
compiledElement = $compile(angular.element('<div test-directive></div>'))($scope);
isolatedScope = compiledElement.isolateScope();
}));
it('element should compile', function () {
expect(compiledElement).toBeDefined();
});
it('scope should isolate', function () {
expect(isolatedScope).toBeDefined();
});
});
describe('last test fails', function(){
var compiledElement, isolatedScope, $scope;
beforeEach(module('test'));
beforeEach(inject(function ($compile, $rootScope){
$scope = $rootScope.$new();
compiledElement = $compile(angular.element('<div test-without-isolate-scope-directive></div>'))($scope);
isolatedScope = compiledElement.isolateScope();
}));
it('element should compile', function () {
expect(compiledElement).toBeDefined();
});
it('scope should isolate', function () {
expect(isolatedScope).toBeDefined();
});
});