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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/21093506/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 20:01:32  来源:igfitidea点击:

Mocking the event object in AngularJS event unit testing

javascriptunit-testingangularjsangularjs-controller

提问by Nicolás Straub

I have the following test:

我有以下测试:

    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 () {};
    }));

which tests this code:

测试此代码:

$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();
    }
});

event.$stopPropagation doesn't call the mock event, and dump(arguments) shows that it is being passed into the event right after the real event object:

event.$stopPropagation 不调用模拟事件,并且 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}
}

how can I make it so the event object is the mock event and not the real event object itself? Am I approaching this the right way? I'm quite new to Angular and any comments on the code/test would be greatly appreciated.

我怎样才能让事件对象是模拟事件而不是真实的事件对象本身?我是否以正确的方式接近这个?我对 Angular 很陌生,对代码/测试的任何评论都将不胜感激。

If you need any more related code please tell me.

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

采纳答案by michael

In this line:

在这一行:

$rs.$broadcast('$locationChangeStart', eventStub);

you provide an argument that will be transmittet alongside with the event, not the event itself. That's why you will get here:

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

$rootScope.$on('$locationChangeStart', function (event) 

2 objects as arguments. The full signature for your event should be:

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

$rootScope.$on('$locationChangeStart', function (event, eventStub) 

So: you can't test the call of stopPropagation in the way you have tried it.

所以:您不能以您尝试过的方式测试 stopPropagation 的调用。

If you have a look at the angular src (line 12185...) you will see, that the event is created without any possibility to mock this object. And the $scope itself is not mocked by angular-mock.

如果您查看 angular src(第 12185 行...),您将看到,该事件是在创建时无法模拟此对象的。并且 $scope 本身并没有被 angular-mock 嘲笑。

If one want to test that preventDefault is called, i would write a service that has a function that calls preventDefault. This service can easily be spyed on.

如果要测试调用了 preventDefault ,我会编写一个具有调用 preventDefault 的函数的服务。这项服务很容易被监视。

回答by Jono

$scope.$broadcastreturns the Eventobject, so you can do this:

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

var event = $scope.$broadcast("someEvent");
expect(event.defaultPrevented).toBeTruthy();