template - create component angularjs
isolateScope() devuelve undefined al usar templateUrl (5)
Tengo una directiva a la que quiero hacer una prueba de unidad, pero me estoy topando con el problema de que no puedo acceder a mi alcance aislado. Aquí está la directiva:
<my-directive></my-directive>
Y el código detrás de él:
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'');
};
}
};
});
Y aquí está mi prueba de unidad:
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();
});
});
Pero cuando imprimo el alcance aislado, resulta en undefined
. Sin embargo, lo que realmente me confunde es que si en lugar de templateUrl
simplemente uso una template
en mi directiva, entonces todo funciona: isolateScope()
tiene un objeto de scope
completo como valor de retorno y todo es genial. Sin embargo, de alguna manera, al usar templateUrl
se rompe. ¿Es esto un error en ng-mocks
o en el preprocesador Karma?
Gracias por adelantado.
Con Angularjs 1.3, si deshabilita debugInfoEnabled
en la configuración de la aplicación:
$compileProvider.debugInfoEnabled(false);
isolateScope()
devuelve undefined
también!
En mi caso, seguí encontrándome con esto en los casos en que intentaba aislar un ámbito en una directiva sin propiedad de aislar el ámbito.
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();
});
});
Puede configurar el complemento karma-ng-html2js-preprocessor . Convierte las plantillas HTML en una cadena javascript y las coloca en el servicio $templateCache
Angular.
Después de establecer un nombre de moduleName
en la configuración, puede declarar el módulo en sus pruebas y luego todas sus plantillas de producción estarán disponibles sin necesidad de burlarse de ellas con $httpBackend
todas partes.
beforeEach(module(''partials''));
Puede encontrar cómo configurar el complemento aquí: http://untangled.io/how-to-unit-test-a-directive-with-templateurl/
Tuve que burlarme y vaciar el $httpBackend
antes de que isolateScope()
fuera definido. Tenga en cuenta que $scope.$digest()
no hizo ninguna diferencia.
Directiva:
app.directive(''deliverableList'', function () {
return {
templateUrl: ''app/directives/deliverable-list-directive.tpl.html'',
controller: ''deliverableListDirectiveController'',
restrict = ''E'',
scope = {
deliverables: ''='',
label: ''@''
}
}
})
prueba:
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});
}));
Estoy usando Angular 1.3.
Yo tuve el mismo problema. Parece que cuando se llama a $compile(element)($scope)
junto con el uso de templateUrl
, el ciclo de resumen no se inicia automáticamente. Por lo tanto, necesita configurarlo manualmente:
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();
});
No estoy seguro de por qué la función $compile
no hace esto por usted, pero debe ser algo de idiosincrasia con la forma en que funciona templateUrl
, ya que no necesita hacer la llamada a $scope.$digest()
si utiliza una plantilla en línea.