如何测试指令是否发出事件
How to test if directive emited an event
我有这个简单的指令:
...
var readyData = {
caption: ctrl.caption,
leftValue: ctrl.leftValue,
rightValue: ctrl.rightValue,
};
$scope.$emit($attrs.id + ".ready", readyData); //$scope is directive's scope and not $rootScope
}
我有以下测试:
describe("Directive: summaryItem", function () {
// load the directive"s module
beforeEach(module("summaryItem"));
it("Should emit the ready event", inject(function ($compile) {
element = angular.element("<summary-item id=\"summaryItem\"></summary-item>");
element = $compile(element)(scope);
scope.$digest();
var dscope = element.scope();
spyOn(dscope, "$emit");
//run code to test
expect(dscope.$emit).toHaveBeenCalledWith("summaryItem.ready");
}));
我收到以下错误:
Expected spy $emit to have been called with [ 'summaryItem.ready' ] but it was never called.
我该如何解决这个问题?谢谢!
更新
对于 @themyth92 请求,这里是完整的指令代码:
"use strict";
(function (angular) {
/**
* @ngdoc directive
* @name summaryItemApp.directive:summaryItem
* @description
* # summaryItem
*/
angular.module("summaryItem")
.directive("summaryItem", function () {
return {
templateUrl: "views/summary-item.html",
restrict: "E",
transclude: true,
controller: SummaryItemCtrl,
controllerAs: 'ctrl',
bindToController: true,
scope: {
options: "=",
caption: "="
}
};
});
function SummaryItemCtrl($scope, $attrs) {
var ctrl = this;
ctrl.caption = this.caption;
if(this.options) {
ctrl.leftValue = this.options.leftValue;
ctrl.rightValue = this.options.rightValue;
}
var readyData = {
caption: ctrl.caption,
leftValue: ctrl.leftValue,
rightValue: ctrl.rightValue
};
$scope.$emit($attrs.id + ".ready", readyData);
}
}(angular));
你的测试有两个问题。首先,事件将在第一个 $scope.$digest()
调用时触发。在您的测试中,您模拟 $emit
函数 在 摘要之后,因此这将不起作用。
此外,由于您的指令使用隔离作用域,element.scope()
does not do what you expect it to do。在这种情况下,element.scope()
将 return 元素的 原始 范围; element.isolateScope()
将 return 指令引入的隔离范围。
但是,还有另一种方法可以对此进行测试。因为 $emit
-ted 事件冒泡到它们的父范围,您还可以测试其中一个父范围是否收到了正确的事件。
未经测试的代码:
it("Should emit the ready event", inject(function ($compile) {
var emitted = false;
scope.$on('summaryItem.ready', function() {
emitted = true;
});
element = angular.element("<summary-item id=\"summaryItem\"></summary-item>");
element = $compile(element)(scope);
scope.$digest();
expect(emitted).toBe(true);
}));
作为一项改进,您还可以存储事件而不仅仅是 true
,这样您就可以对发出的事件执行各种 expects
。
我有这个简单的指令:
...
var readyData = {
caption: ctrl.caption,
leftValue: ctrl.leftValue,
rightValue: ctrl.rightValue,
};
$scope.$emit($attrs.id + ".ready", readyData); //$scope is directive's scope and not $rootScope
}
我有以下测试:
describe("Directive: summaryItem", function () {
// load the directive"s module
beforeEach(module("summaryItem"));
it("Should emit the ready event", inject(function ($compile) {
element = angular.element("<summary-item id=\"summaryItem\"></summary-item>");
element = $compile(element)(scope);
scope.$digest();
var dscope = element.scope();
spyOn(dscope, "$emit");
//run code to test
expect(dscope.$emit).toHaveBeenCalledWith("summaryItem.ready");
}));
我收到以下错误:
Expected spy $emit to have been called with [ 'summaryItem.ready' ] but it was never called.
我该如何解决这个问题?谢谢!
更新
对于 @themyth92 请求,这里是完整的指令代码:
"use strict";
(function (angular) {
/**
* @ngdoc directive
* @name summaryItemApp.directive:summaryItem
* @description
* # summaryItem
*/
angular.module("summaryItem")
.directive("summaryItem", function () {
return {
templateUrl: "views/summary-item.html",
restrict: "E",
transclude: true,
controller: SummaryItemCtrl,
controllerAs: 'ctrl',
bindToController: true,
scope: {
options: "=",
caption: "="
}
};
});
function SummaryItemCtrl($scope, $attrs) {
var ctrl = this;
ctrl.caption = this.caption;
if(this.options) {
ctrl.leftValue = this.options.leftValue;
ctrl.rightValue = this.options.rightValue;
}
var readyData = {
caption: ctrl.caption,
leftValue: ctrl.leftValue,
rightValue: ctrl.rightValue
};
$scope.$emit($attrs.id + ".ready", readyData);
}
}(angular));
你的测试有两个问题。首先,事件将在第一个 $scope.$digest()
调用时触发。在您的测试中,您模拟 $emit
函数 在 摘要之后,因此这将不起作用。
此外,由于您的指令使用隔离作用域,element.scope()
does not do what you expect it to do。在这种情况下,element.scope()
将 return 元素的 原始 范围; element.isolateScope()
将 return 指令引入的隔离范围。
但是,还有另一种方法可以对此进行测试。因为 $emit
-ted 事件冒泡到它们的父范围,您还可以测试其中一个父范围是否收到了正确的事件。
未经测试的代码:
it("Should emit the ready event", inject(function ($compile) {
var emitted = false;
scope.$on('summaryItem.ready', function() {
emitted = true;
});
element = angular.element("<summary-item id=\"summaryItem\"></summary-item>");
element = $compile(element)(scope);
scope.$digest();
expect(emitted).toBe(true);
}));
作为一项改进,您还可以存储事件而不仅仅是 true
,这样您就可以对发出的事件执行各种 expects
。