我有以下测试:
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 () {}; }));
它测试这个代码:
$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(); } });
事件$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: ...,routeParams: ...}},1: Object{stopPropagation: spy} }
如何使它成为事件对象是模拟事件而不是真实的事件对象本身?我接近正确的路吗?我对Angular很新,对代码/测试的任何评论都将不胜感激.
如果您需要更多相关代码,请告诉我.
解决方法
在这行:
$rs.$broadcast('$locationChangeStart',eventStub);
您提供的一个参数将与事件一起传输,而不是事件本身.这就是为什么你会到这里:
$rootScope.$on('$locationChangeStart',function (event)
2个对象作为参数.您的活动的完整签名应为:
$rootScope.$on('$locationChangeStart',function (event,eventStub)
所以:你不能以你尝试的方式测试stopPropagation的调用.
如果你看到角度src(行12185 …),你会看到,事件被创建,没有任何可能模拟这个对象.而$范围本身并不被角度模拟所嘲笑.
如果要测试preventDefault被调用,我将编写一个具有调用preventDefault功能的服务.这个服务可以很容易地被窥探.