如何测试指令是否发出事件

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