transclude template oninit onchanges create componentes component angularjs unit-testing angularjs-directive karma-runner

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.