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

How to test if directive emited an event

本文关键字:指令 是否 出事件 测试 何测试      更新时间:2023-09-26

我有这个简单的指令:

    ...
    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()不会执行您希望它执行的操作。在这种情况下,element.scope()将返回元素的原始范围; element.isolateScope()将返回指令引入的隔离范围。

但是,还有另一种方法可以对此进行测试。由于 -ted 事件$emit冒泡到其父作用域,因此还可以测试其中一个父作用域是否接收了正确的事件。

未经测试的代码:

  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