unit test spy on $emit
Solution 1
According to the docs here, you are correct in your understanding of the difference between $emit
and $broadcast
. However, I think the problem is in your use of $scope
and $rootScope
. Your $rootScope
will be at the top level of your scope hierarchy. I'm guessing (just by looking at your snippets without being able to see all the code) that your $scope
in your controller is a nested controller, meaning that $scope
in your controller is a child of the app's $rootScope
.
Because of that, when your unit test spys on the $rootScope.$emit
function, it is not actually spying on your controller's $scope.$emit()
call. Those two "scopes" are different, not the same thing. So, you need to mock the $scope
that you provide for the controller and then do a spyOn
on that.
For example, in your beforeEach
:
var ctrl, scope;
beforeEach(function() {
module('<INSERT YOUR CONTROLLERS MODULE NAME HERE>');
inject(function($rootScope, $controller) {
scope = $rootScope.$new();
ctrl = $controller('<CTRL NAME HERE>', {$scope: scope});
});
});
This code will actually create a "mock" scope variable and will provide that object to your controller, which you can then do spies and other things with. Such as:
spyOn(scope, '$emit');
// do whatever triggers the "$emit" call
expect(scope.$emit).toHaveBeenCalledWith('resultSend');
I'm pretty sure that should fix your problem. Let me know if that needs more explanation.
Solution 2
If your directive has a controller, you could, and should, test that separately from the directive. That's the whole point of an MVC architecture, you can test the C seperately from the V. ;)
That said, it would be a plain-Jane controller test spec.
Another tip: You should do all of your set up in your beforeEach() block (i.e. spies and whatever) and then do the assertions in your it() blocks.
Finally: Make sure that the spy you're setting up, is on the scope you're passing into the controller you're testing.
![Maarten](https://i.stack.imgur.com/w7jY3.png?s=256&g=1)
Maarten
20+ years experience in web development, system administration and application management.
Updated on June 07, 2022Comments
-
Maarten about 2 years
I'm trying to spy on an $emit from a directive, but somehow I cannot get the spy to 'hear' the $emit.
This is the code in my directives' controller:
$scope.$on('send', function () { console.log('called'); $scope.$emit('resultSend', {'ok': true, 'data': ''}); });
This is my unit test:
var $rootScope, $compile, elm, element; beforeEach(inject(function ($injector) { $rootScope = $injector.get('$rootScope'); $compile = $injector.get('$compile'); elm = angular.element('<test></test>'); element = $compile(elm)($rootScope); })); it('should listen for the send broadcast and emit the resultSend', function () { spyOn($rootScope, '$emit'); $rootScope.$broadcast('send'); expect($rootScope.$emit).toHaveBeenCalledWith('resultSend'); });
The console.log output ('called') is printed out by Karma, so I guess the unit test broadcast event does work.
Does this have to do with $emit not broadcasting down but up, and if so, how do I catch it, and if not, how else do I handle this case?