【问题标题】:Spy for $rootScope.$broadcast is not working when everything else is?$rootScope.$broadcast 的间谍在其他一切正常时不起作用?
【发布时间】:2016-09-20 22:54:14
【问题描述】:

我有一个要测试的键盘快捷键指令。其目的是用事件数据触发$rootScope.$broadcast()。在应用程序中它可以正常工作,但我无法让这个该死的测试像我想要的那样彻底通过。

(function(){
    'use strict';

    angular
        .module('app.common')
        .directive('keyboardShortcuts', keyboardShortcuts);

    // @ngInject
    function keyboardShortcuts($document, $rootScope){
        return {
            restrict: 'A',
            link
        }

        function link(scope, el, attrs){
            $document.bind('keypress', event => {
                console.log('detected keypress');
                $rootScope.$broadcast('keyboardShortcut', event);

                scope.$digest(); // seems to make no difference
            });
        }
    }

})();

对于单元测试,我添加了一个$scope.$on 处理程序来显示广播实际上正在制作和收听,但由于某种原因间谍没有做它的工作。

describe('KeyboardShortcuts Directive', function(){
    'use strict';

    let $element;
    let $scope;
    let vm;
    let $document;
    let $rootScope;

    const mockKeyboardEvent = {
        type: 'keypress',
        bubbles: true,
        altKey: false,
        ctrlKey: false,
        shiftKey: false,
        which: 106
    }

    beforeEach(module('app.common'));

    beforeEach(inject(function(_$rootScope_, $compile, _$document_){
        $element = angular.element('<div keyboard-shortcuts></div>');
        $rootScope = _$rootScope_.$new();
        $document = _$document_;

        $scope = $rootScope.$new();
        $compile($element)($scope);
        $scope.$digest();

        spyOn($rootScope, '$broadcast');
    }));

    ////////////

    it('should broadcast when a key is pressed', function(){
        $scope.$on('keyboardShortcut', (event, data) => {
            console.log('wtf!?');
            expect(data.which).toBe(106);
        });

        $document.triggerHandler(mockKeyboardEvent);

        $scope.$digest(); // seems to make no difference

        expect($rootScope.$broadcast).toHaveBeenCalled();
    });
});

这是控制台输出。您可以看到代码似乎可以正常工作。

[15:33:57] Starting 'build:common:js'...
[15:33:58] Finished 'build:common:js' after 227 ms
[15:33:58] Starting 'test:common'...
20 09 2016 15:33:58.250:INFO [karma]: Karma v1.3.0 server started at http://localhost:9876/
20 09 2016 15:33:58.250:INFO [launcher]: Launching browser PhantomJS with unlimited concurrency
20 09 2016 15:33:58.253:INFO [launcher]: Starting browser PhantomJS
20 09 2016 15:33:58.797:INFO [PhantomJS 2.1.1 (Mac OS X 0.0.0)]: Connected on socket /#37Fv2zndO5Z6XAZ8AAAg with id 3035140
..
LOG: 'detected keypress'
LOG: 'wtf!?'
PhantomJS 2.1.1 (Mac OS X 0.0.0) KeyboardShortcuts Directive should broadcast when a key is pressed FAILED
    Expected spy $broadcast to have been called.

过去,在对控制器进行单元测试时,我也遇到过这样的问题。我试图监视在立即运行的 activate() 方法中运行的方法(Papa 风格),我能够通过将 spyOn(...) 方法 above 放在哪里让我的间谍工作控制器已实例化。在这种情况下,我尝试将我的spyOn 放在“beforeEach”内的各种位置,但似乎没有任何作用。

我还尝试了将expect..broadcast..beenCalled() 内容放在$on 处理程序中的明显解决方案,但这也不起作用,即使该断言通过并且完全证明a 已进行广播。

我有一种感觉,被监视的 $rootScope 与被注入并以其他方式工作的 $rootScope 不同,但我不知道这是怎么回事。

【问题讨论】:

    标签: unit-testing angularjs-directive jasmine


    【解决方案1】:

    正确的变量命名很重要。

    这个

    $rootScope = _$rootScope_.$new();
    

    是 Angular 单元测试中普遍存在的错误之一。

    问题是被称为$rootScope 的东西只是子作用域,而不是根作用域。看起来,很容易忘记这一点,所以

    spyOn($rootScope, '$broadcast');
    

    在某个范围内存根$broadcast 方法。

    应该是

        $rootScope = _$rootScope_;
        $scope = $rootScope.$new();
    

        $scope.$digest(); // seems to make no difference
    

    不应该存在,因为 jQuery/jqLit​​e 事件与摘要周期无关。

    【讨论】:

    • 更改$rootScope = _$rootScope_.new() 似乎已经成功了。我在另一个测试中遇到了一些问题,没有这样做,所以这就是我保留模式的原因。看来我得再去检查那些测试了。谢谢!
    猜你喜欢
    • 2016-06-09
    • 1970-01-01
    • 1970-01-01
    • 2019-06-24
    • 1970-01-01
    • 2016-03-21
    • 2018-03-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多