Reset broadcast () after each test case when using andCallThrough ()

I use the following code below reset $broadcast after each test case, but it seems to be $rootScope.$broadcast.reset(); does not work properly, as the test below should return 1, but it returns 6.

It seems that the reason for this is andCallThrough() , since before I used it without the function andCallThrough() , but after some refactory it gave me an error that TypeError: Cannot read property 'defaultPrevented' of undefined , so I had to use to prevent this error.

The question is, how do I reset broadcast when using andCallThrough or is there another more accurate approach?

 beforeEach(function() { spyOn($http, 'post'); spyOn($rootScope, '$broadcast').andCallThrough(); }); afterEach(function() { $http.post.reset(); $rootScope.$broadcast.reset(); }); it('should make a POST request to API endpoint', function() { $http.post.andCallThrough(); var response = { id: '123', role: 'employee', email: ' user@email.com ', username: 'someUsername' }; $httpBackend.expectPOST(apiUrl + 'login').respond(response); service.login(); $httpBackend.flush(); $timeout.flush(); expect($rootScope.$broadcast.callCount).toBe(1); expect($rootScope.$broadcast).toHaveBeenCalledWith(AUTH_EVENTS.loginSuccess, response); }); 
+5
source share
3 answers

After a long study of how everything works in this situation, finally the tests are passed and the solution is current:

The problem is not that the relay method () or reset not called after each test case when using andCallThrough (). The problem is that $rootScope.$broadcast.andCallThrough(); triggered by other events, and the .callCount() function returned 6 , which basically means $broadcast spy was called 6 times. In my case, I am only interested in the AUTH_EVENTS.loginSuccess event and make sure that it is broadcast only once.

 expect($rootScope.$broadcast.callCount).toBe(1); expect($rootScope.$broadcast).toHaveBeenCalledWith(AUTH_EVENTS.loginSuccess, response); 

So digging in the $rootScope.$broadcast.calls method gave me an array of all the calls, from which two of the above should be extracted. Therefore, the solution:

 it('should make a POST request to API endpoint', function() { $http.post.andCallThrough(); var response = { id: '123', role: 'employee', email: ' user@email.com ', username: 'someUsername' }; $httpBackend.expectPOST(apiUrl + 'login').respond(response); service.login(); $httpBackend.flush(); $timeout.flush(); var loginSuccessTriggerCount = _($rootScope.$broadcast.calls) .chain() .map(function getFirstArgument(call) { return call.args[0]; }) .filter(function onlyLoginSuccess(eventName) { return eventName === AUTH_EVENTS.loginSuccess; }) .value().length; expect(loginSuccessTriggerCount).toBe(1); }); 
+4
source

Another approach. This is pseudo-code similar to coffeescript. Ask in the comments if some expressions are not clear. I must say that this is not a direct answer to your question. Just a method of doing things like this differently.

Cleaner Tests

We introduce a variable that will be processed by the spy for broadcasting. I use pure spyware because spyOn can work poorly in some cumbersome cases when we are dealing with overriding or mixing a method.

 rootScope$broadcastSpy = jasmine.createSpy() 

We need to replace the original implementation with a stub that will handle spies and their states. The usual definition of stubs says that it is an entity that does not have its own logic. So, we do it in a clean way and do not put any logic here. Only the marker (which is represented by the spy).

 beforeEach module ($provide) -> $provide.value '$rootScope', $broadcast: rootScope$broadcastSpy return 

Of course, we need to talk with jasmine when we need to reset the spy.

 beforeEach -> rootScope$broadcastSpy.reset() 

Let me define a testing area where we will prepare all the necessary services and place them declaratively in context (i.e. this ).

 instance = (fnAsserts) -> inject (loginService, $httpBackend, $timeout, apiUrl, AUTH_EVENTS) -> fnAsserts.call service: loginService apiUrl: apiUrl AUTH_EVENTS: AUTH_EVENTS '$httpBackend': $httpBackend '$timeout': $timeout 

Record the test in Blackbox mode. We simply set the initial state, then start the action and at the end we give the opportunity to check our marker for changes.

 it 'should make a POST request to API endpoint', instance -> # Given response = { id: '123', role: 'employee', email: ' user@email.com ', username: 'someUsername' } @$httpBackend.expectPOST(@apiUrl + 'login').respond(response) # When @service.login() # Then @$httpBackend.flush() @$timeout.flush() expect(rootScope$broadcastSpy.callCount).toBe(1) expect(rootScope$broadcastSpy).toHaveBeenCalledWith(@AUTH_EVENTS.loginSuccess, response) 

As you can see, we can associate calls with instances, add additional information to them and write each test in a cleaner way, because we see the state, scope, mocks and other necessary things in one place. We use closure only for the marker, and it ensures that side effects are minimized.

+2
source

I ended up here for the first part of the question

Reset broadcast ()

and this works for me:

 $rootScope.$broadcast.calls.reset() 
0
source

Source: https://habr.com/ru/post/1212005/


All Articles