2016-07-15 15 views
1

Ich stehe mit Unitar Test mit Karma Kopf. Ich möchte die Zustandsübergänge überprüfen, also habe ich diesen Test erstellt. Die App beginnt mit dem landing Staat und von dort möchte ich gehen zu main. Dies ist eine sichere Route so zu login umgeleitet wird:Wie testet man Zustandsübergang in Winkel?

it('should go to loginpage before main', function() { 
    $scope.$apply(); 
    expect($state.current.name).toBe('landing');  
    $state.transitionTo('main'); 
    $scope.$apply(); 
    expect($state.current.name).toBe('login'); 
}); 

In meinem app.js ich habe:

$rootScope.$on('$stateChangeStart', function (event,next) { 
     console.log('statechange from:', $state.current.name) 
     //console.log('statechange to:',$state) 

     if (!next.authenticate) { 
      return; 
     } 

     //if next state is secure then check whether user is logged in: 

     if (next.authenticate) { 
      event.preventDefault(); 
      $state.transitionTo('login'); 
      console.log('goto login'); 
     } 


    }); 

Wenn ich meinen Test mit Karma laufen erhalte ich:

Chrome 51.0.2704 (Mac OS X 10.11.4) secure tests should go to loginpage before main FAILED 
    Expected '' to be 'landing'. 
     at Object.<anonymous> (/Users/dimitri/karma/basic_karma/appSpec.js:23:37) 
    Expected '' to be 'login'. 

Warum ist die $state.current.name leer?

Github ref: https://github.com/dimitri-a/basic_karma

Antwort

0

Es scheint, als ob Sie versuchen, zwei verschiedene Dinge zu testen. Zuerst testen Sie, ob der $stateChangeStart -Event ausgelöst wird. Zweitens testen Sie Ihren benutzerdefinierten Handler und die darin enthaltene Logik, wenn sie bei Bedarf umgeleitet wird.

Beim Gerätetest geht es darum, einen kleinen Teil Ihrer Anwendung zu testen. Das $stateChangeStart -Event ist nicht Teil Ihrer Anwendung, da es Teil der UI-Router-Komponente ist. Das Testen dieses Ereignisses liegt nicht in Ihrer Verantwortung. Noch besser; Der UI-Router hat eigene Testfälle erstellt, die prüfen, ob $stateChangeStart ausgelöst wird. Sie können sie selbst sehen right here. Sie können ziemlich sicher sein, dass das Ereignis ausgelöst wird, wenn es benötigt wird.

Also, wie testen wir Ihre eigene benutzerdefinierte Logik? Zuerst müssen wir den Handler $rootScope.$on refaktorieren.

$rootScope.$on('$stateChangeStart', handleStateChange); 

function handleStateChange(event, next) { 
    console.log('statechange from:', $state.current.name) 
    //console.log('statechange to:',$state) 

    if (!next.authenticate) { 
     return; 
    } 

    //if next state is secure then check whether user is logged in: 

    if (next.authenticate) { 
     event.preventDefault(); 
     $state.transitionTo('login'); 
     console.log('goto login'); 
    } 
} 

Auf diese Weise wir entkoppeln Sie benutzerdefinierte Logik aus dem Angular $rootScope und wir können für sich allein die Logik testen. Mach dir keine Sorgen, deine Logik wird immer noch laufen, wenn sich ein Zustand ändert.

Als nächstes den Test selbst. Wir müssen uns nicht mit $state.transitionTo befassen, weil wir diesen Teil der Anwendung nicht testen (wieder hat der ui-Router eigene Tests für $state.transitionTo). Wir brauchen nicht einmal $scope.$apply zu verwenden.

describe('handleStateChange()', function() { 

    var $state; 

    beforeEach(inject(function(_$state_) { 
     $state   = _$state_; 

     // we spy on the $state.transitionTo method, to check if it 
     // has been called by our test case. 
     spyOn($state, 'transitionTo'); 
    })); 

    it('should transition to login state when authenticate:true', function() { 
     // arrange 
     var next = { 
      name: 'main', 
      authenticate: true 
     }; 

     // act 
     handleStateChange({}, next); 

     // assert 
     // in case of authenticate: true, $state.transitionTo should 
     // have been called with the 'login' name 
     expect($state.transitionTo).toHaveBeenCalledWith('login'); 
    }); 

    it('should not transition to login state when authenticate:false', function() { 
     // arrange 
     var next = { 
      name: 'landing', 
      authenticate: false 
     }; 

     // act 
     handleStateChange({}, next); 

     // assert 
     expect($state.transitionTo).not.toHaveBeenCalledWith('login'); 
    }); 

});