単体テストしたいディレクティブがありますが、分離されたスコープにアクセスできないという問題が発生しています。ディレクティブは次のとおりです。
_<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');
};
}
};
});
_
そして、これが私のユニットテストです:
_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プリプロセッサのバグですか?
前もって感謝します。
私も同じ問題を抱えていました。 templateUrl
を使用して$compile(element)($scope)
を呼び出すと、ダイジェストサイクルが自動的に開始されないようです。したがって、手動でオフに設定する必要があります。
_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()
。
Angularjs 1.3では、アプリの設定でdebugInfoEnabled
を無効にすると次のようになります。
_$compileProvider.debugInfoEnabled(false);
_
isolateScope()
はundefined
も返します!
isolateScope()
が定義される前に、_$httpBackend
_をモックしてフラッシュする必要がありました。 $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を使用しています。
karma-ng-html2js-preprocessor プラグインを構成できます。 HTMLテンプレートをJavaScript文字列に変換し、Angularの$templateCache
サービスに配置します。
構成でmoduleName
を設定した後、テストでモジュールを宣言できます。そうすれば、どこでも$httpBackend
でモックする必要なしに、すべての本番テンプレートを使用できます。
beforeEach(module('partials'));
プラグインのセットアップ方法はここにあります: http://untangled.io/how-to-unit-test-a-directive-with-templateurl/
私の場合、分離スコーププロパティのないディレクティブでスコープを分離しようとしたときに、これに遭遇し続けました。
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();
});
});