在AngularJS事件单元测试中模拟事件对象

Nic*_*aub 9 javascript unit-testing angularjs angularjs-controller

我有以下测试:

    it('Should keep location when user rejects confirmation', inject(function ($controller, $rootScope) {
        var confirmStub = sinon.stub(),
            eventStub = {
                preventDefault: sinon.spy()
            };

        miscServiceStub = function () {
            this.confirm = confirmStub;
        };

        confirmStub.returns(false);

        initializeController($controller, 'Builder', $rootScope);

        $rs.$broadcast('$locationChangeStart', eventStub);
        expect(confirmStub).toHaveBeenCalledOnce();
        expect(confirmStub).toHaveBeenCalledWith('Are you sure you want to leave? you will loose any unsaved changes.');
        expect(eventStub.stopPropagation).toHaveBeenCalledOnce();

        miscServiceStub = function () {};
    }));
Run Code Online (Sandbox Code Playgroud)

测试此代码:

$rootScope.$on('$locationChangeStart', function (event) {
    dump(arguments);
    if (!$miscUtils.confirm('Are you sure you want to leave? you will loose any unsaved changes.')){
        event.preventDefault();
    }
});
Run Code Online (Sandbox Code Playgroud)

event.$ stopPropagation不调用mock事件,dump(arguments)显示它正在真实事件对象之后传递给事件:

Chromium 31.0.1650 (Ubuntu) DUMP: Object{
    0: Object{name: '$locationChangeStart', targetScope: Scope{$id: ..., $$childTail: ..., $$childHead: ..., $$prevSibling: ..., $$nextSibling: ..., $$watchers: ..., $parent: ..., $$phase: ..., $root: ..., this: ..., $$destroyed: ..., $$asyncQueue: ..., $$postDigestQueue: ..., $$listeners: ..., $$isolateBindings: ..., activeTab: ..., routeParams: ...}, preventDefault: function () { ... }, defaultPrevented: false, currentScope: Scope{$id: ..., $$childTail: ..., $$childHead: ..., $$prevSibling: ..., $$nextSibling: ..., $$watchers: ..., $parent: ..., $$phase: ..., $root: ..., this: ..., $$destroyed: ..., $$asyncQueue: ..., $$postDigestQueue: ..., $$listeners: ..., $$isolateBindings: ..., activeTab: ..., routeParams: ...}}, 
    1: Object{stopPropagation: spy}
}
Run Code Online (Sandbox Code Playgroud)

我怎样才能使它成为事件对象是模拟事件而不是真实事件对象本身?我是以正确的方式接近这个吗?我对Angular很新,对代码/测试的任何评论都会非常感激.

如果您需要更多相关代码,请告诉我.

小智 37

$scope.$broadcast返回Event对象,所以你可以这样做:

var event = $scope.$broadcast("someEvent");
expect(event.defaultPrevented).toBeTruthy();
Run Code Online (Sandbox Code Playgroud)


mic*_*ael 3

在这一行中:

$rs.$broadcast('$locationChangeStart', eventStub);
Run Code Online (Sandbox Code Playgroud)

您提供的参数将与事件一起传输,而不是事件本身。这就是为什么你会到达这里:

$rootScope.$on('$locationChangeStart', function (event) 
Run Code Online (Sandbox Code Playgroud)

2 个对象作为参数。您的活动的完整签名应为:

$rootScope.$on('$locationChangeStart', function (event, eventStub) 
Run Code Online (Sandbox Code Playgroud)

因此:您无法以您尝试过的方式测试 stopPropagation 的调用。

如果您查看 Angular src(第 12185 行...),您将看到,创建事件时没有任何可能模拟该对象。并且 $scope 本身并没有被 Angular-Mock 模拟。

如果想测试 PreventDefault 是否被调用,我会编写一个服务,该服务具有调用 PreventDefault 的函数。这项服务很容易被监视。