2014-10-27 27 views
6

Ich habe eine Angular App mit einem Controller, der während eines Funktionsaufrufs ein Angular-Strap modales Fenster anzeigt. Es funktioniert korrekt in Chrome, aber ich bin nicht in der Lage, einen gültigen Komponententest zu erhalten.

App-Modul und das FooController:

var app = angular.module("app", ["mgcrea.ngStrap"]); 

app.controller("FooController", function($scope, $modal) { 
    var fooModal = $modal({ 
     title: 'Foo', 
     content:'Bar', 
     show: false, 
     html: true, 
     backdrop: 'static', 
     placement: 'center'}); 

    angular.extend($scope, { 
     makeItFoo: function() { 
      fooModal.show(); 
     } 
    }); 
}); 

Controller-Spezifikation:

describe('FooController', function() { 
    var scope, controller, modal; 

    beforeEach(module('app', function ($provide) { 
     // Stub out $modal service 
     $provide.value('$modal', function() { 
      return { 
       hide: function() { }, 
       show: function() { } 
      }; 
     }); 
    })); 

    beforeEach(inject(function ($rootScope, $controller, $injector) { 
     //set up a new scope and the controller for the test 
     scope = $rootScope.$new(); 
     controller = $controller('FooController', {$scope: scope}); 
     modal = $injector.get('$modal'); 
    })); 

    it('should show the modal', function() { 
     var modalSpy = spyOn(modal(), 'show'); 

     scope.makeItFoo(); 

     expect(modalSpy).toHaveBeenCalled(); 
    }); 
}); 

Here's a fiddle as well.

ich meinen Ruf zu makeItFoo() erwarten, dass die modal angezeigt werden, aber Jasmin versagt der Test mit dem Fehler Expected spy show to have been called. Ich habe auch versucht, die show Eigenschaft des modalen zu true einzustellen und nicht show() getrennt zu nennen, und ich habe andere Varianten versucht, den $ modalen Dienst zu stubben und es direkt in den Prüfer einspritzt, aber es endet mit dem gleichen Fehler.

Ich benutze AngularJS 1.2.14, Angular-Strap 2.0.0 und Jasmine 1.3.1.

Antwort

7

Anstatt diese zu tun. Erstellen Sie ein Mock-Objekt für $modal mit Methoden zum Ein- und Ausblenden und legen Sie Ihre Erwartungen fest.

describe('FooController', function() { 
    var scope, controller, modal; 

    beforeEach(module('app')); 

    beforeEach(inject(function ($rootScope, $controller) { 
     //set up a new scope and the controller for the test 
     scope = $rootScope.$new(); 
     //Create spy object 
     modal = jasmine.createSpyObj('modal', ['show', 'hide']); 
     //provide modal as dependency to the controller. 
     controller = $controller('FooController', {$scope: scope, $modal:modal}); 

    })); 

    it('should show the modal', function() { 

     scope.makeItFoo(); 

     expect(modal.show).toHaveBeenCalled(); 
    }); 
}); 
+1

Ich war mitten in meiner Antwort, als Sie es gepostet haben, Sie haben es genagelt;) – maurycy

+0

@maurycy haha ​​es passiert manchmal auch mir .. :) – PSL

+0

@PSL, danke! Ich habe versucht, den richtigen Weg zu verstehen, $ modal nachzuahmen, und das scheint es zu sein. Nachdem ich jedoch meine Geige wie beschrieben aktualisiert habe, ist der Test immer noch nicht erfolgreich. Der Fehler lautet jetzt: Argument 'FooController' ist keine Funktion, wurde undefiniert '; aktualisierte Geige [hier] (http://jsfiddle.net/dimmreaper/jwom7ns2/3/). –

1

Die Modal Show ist asynchron. Ich habe deine Geige um http://jsfiddle.net/jwom7ns2/1/ aktualisiert.

Ändern Sie den folgenden Abschnitt:

it('should show the modal', function (done) { 
    var modalSpy = spyOn(modal(), 'show'); 

    scope.makeItFoo(); 

    setTimeout(function() { 
     expect(modalSpy).toHaveBeenCalled(); 
     done(); 
    }); 

}); 

Die Timeout-Wrapper wartet auf den Digest passieren, wenn die modale Show auftritt.

+0

Ich war im Begriff zu kommentieren, bevor Sie Ihre Antwort auf, warum 'scope. $ Apply '?. Aber ich denke, das ist wahrscheinlich auch ein Overkill IMHO, weil OP bereits einen Mock Obj erstellt und dann einen Spion eingerichtet hat. Stattdessen kann alles auf einmal getan werden, indem ein Mock-Objekt mit Jasmin erstellt wird. Außerdem müssen Sie nicht '$ injector.get ('$ modal')' statt $ modal 'direkt einfügen. – PSL

+1

Danke, das scheint definitiv eine praktikable Lösung. Ich werde zuerst auf die @ PSL-Methode des Spotting von $ modal eingehen, da ich es vorziehen würde, nicht explizit mit Timing umzugehen. Wenn ich Probleme habe, behalte ich Ihre Lösung im Hinterkopf. Vielen Dank! –