alonisser
alonisser

Reputation: 12068

Angular.js unittest something that happens in run phase (rootScope event listening)

I have something that must be on rootScope (also suggestions are welcome) a listener on stateChangeError events that reroutes them for error handling. something like:

$rootScope.$on('$stateChangeError', function(event, toState, toParams, fromState, fromParams, error){
          if(error.status === 404 ){
              event.preventDefault();
              $state.go('404');
          } else if(error.status === 500){
              event.preventDefault();
              $state.go('500');
          }

      });

I can't find how can I access the run phase in my unit testing? to unittest the specific listeners? I want to test if $state.go is called.

I'll appreciate help/suggestions - Thanks!

Upvotes: 0

Views: 159

Answers (1)

ŁukaszBachman
ŁukaszBachman

Reputation: 33735

If you want to test that Angular calls $state.go() then you are writing an integration test, which might be tricky if framework does not support such type of testing (I'm not sure if it does).

Usually to resolve such issues I use the following trick:

  1. I test the function, not the listener.
  2. I test that this function is properly registered in the listener.

Before I describe it to you, switch your mind a little bit and forget about this anonymous function function(event, toState, toParams, fromState, fromParams, error){...} and simply - name it! var myLogic = function (event, toState, toParams, fromState, fromParams, error){...} Can you see the difference? You no longer have an anonymous callback, now you have your own piece of logic which has to be tested.

Now, if you focus on unit testing, then you are not really interested in testing if Angular's listener mechanism works as expected. What you want to test is that the function that was triggered does what it needs to do, i.e. call $state.go(). So, since you now have your myLogic function, then you can now test it as you want!

// --------- Real class ---------
var myLogic = function(component1, component2) {
   component1.do();
}

$rootScope.$on("event", myLogic);

// --------- Tests pseudocode ---------

// Test that your logic does what it is supposed to be doing

// When
myLogic(comp1Mock, comp2Mock);
// Then
expect(comp1.do).toHaveBeenCalled();

// Test that your logic was attached to proper place in the framework. 
// To do that, you have to mock part of the framework. Fortunately in 
// Angular all parts of framework component/services are injected to 
// a controller.

// When - your controller is initialized
// Then
expect(rootScopeMock.on).toHaveBeenCalledWith("event", myLogic);

Voila!

Upvotes: 1

Related Questions