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:
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.
If you need any more related code please tell me.
$scope.$broadcast
returns the Event
object, so you can do this:
var event = $scope.$broadcast("someEvent");
expect(event.defaultPrevented).toBeTruthy();
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:
$rootScope.$on('$locationChangeStart', function (event, eventStub)
So: you can't test the call of stopPropagation in the way you have tried it.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With