如何在AngularJS Karma单元测试中触发`$on`事件?

6
我正在尝试在控制器中触发$scope.$on()方法,该方法在我$rootScope.broadcast()一个事件时被触发。我发现这个问题很有用:如何测试Angular中的事件?,但是我仍然无法检测$rootScope通过控制器的$scope广播的事件。
到目前为止,我已经成功测试了相应的$rootScope上调用了$broadcast方法,但没有测试到$rootScope上调用$broadcast后相应的$scope上是否调用了$on方法。
我试图在我的测试中直接使用$rootScope.$broadcast,但我的spy没有监听到事件。
这是我的控制器:
angular.module('app.admin.controllers.notes', [])
    .controller('NotesCtrl', function($scope) {

      $scope.$on('resource-loaded', function(event, resource) { // I want to test this
        $scope.parentType = resource.type;
        $scope.parentId = resource.id;
      });

    });

这是我的测试:

describe('The notes controller', function() {

  beforeEach(module('app.admin.controllers.notes'));

  var scope, rootScope, NotesCtrl;

  beforeEach(inject(function($controller, $injector, $rootScope) {
    rootScope = $rootScope;
    scope = $rootScope.$new(); // I've tried this with and without $new()
    NotesCtrl = $controller('NotesCtrl', {$scope: scope}); // I've tried explicitly defining $rootScope here
  }));

  it('should respond to the `resource-loaded` event', function() {
    spyOn(scope, '$on');
    rootScope.$broadcast('resource-loaded'); // This is what I expect to trigger the `$on` method
    expect(scope.$on).toHaveBeenCalled();
  });

});

这里是plunkr链接。我包含了一个$broadcast方法的通过测试,仅仅是为了参考,因为我以同样的方式设置了测试。

我读过很多关于在AngularJS中测试事件的问题,似乎总是涉及到作用域问题。我听说在Karma单元测试中,$rootScope$scope是相同的东西,但我不确定影响是什么。我试过将$rootScope$scope定义为同一个对象,也尝试在测试期间显式注入$rootScopeNotesCtrl中,但没有任何能让我的测试变为绿色的方法。

我该如何使得NotesCtrl中的$on方法在这个测试中被触发?

3个回答

12

问题在于你正在监视$on函数,这导致它无法正常工作。当不进行监视时,它可以正常工作:http://plnkr.co/edit/hNEj7MmDDKJcJ7b298OB?p=info。而原因其实很简单,当事件被广播时,调用的不是$on()函数,而是之前作为参数传递给$on()的回调函数即监听器。

请注意,通过监视$on函数,您在此处并未测试您的代码。您所试图测试的只是子作用域接收事件时是否能正常工作,因此您实际上是在测试AngularJS本身。


2
这真的很晚了,但是对于将来找到这个问题的人,您可以在创建间谍时添加.and.callThrough()来测试这种情况。 - Amy Blankenship

1
尝试使用 <\p>。
$rootScope.$emit('resource-loaded');

在我的测试中运行良好。


$emit 发送消息到作用域树的上层;$broadcast 则向下传递。 - Richard

1

@kirill.buga

使用$broadcast是正确的,而不是$emit,因为:

https://docs.angularjs.org/api/ng/type/$rootScope.Scope 通过作用域层次结构向上分派事件名称,通知已注册的$rootScope.Scope侦听器。

@ben-harold的问题在于尝试监视$on而不是$on中代码的结果。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接