25

EDIT: Schnell & Schmutzige Lösung am Ende dieses EintragesEinheit einen modalInstance Controller mit Karma/Jasmin testet

Ich bin ein modales Fenster aus AngularUI-Bootstrap auf die gleiche Art und Weise mit, dass es auf dem erklärt wird Website, außer dass ich Dateien spaltete. Deshalb habe ich:

CallingController.js:

$scope.delete = function() { 
    if ($scope.selected.length > 0) { 
     // [...] 
     // preparing data 
     // [...] 
     var modalInstance = $modal.open({ 
      templateUrl: 'views/modalView.html', 
      controller: 'modalCtrl', 
      resolve: { 
       itemArray: function() { 
        return $scope.selected; 
       } 
      } 
     }); 
     modalInstance.result.then(function (confirm) { 
      if (confirm === true) { 
       // [...] 
       // treat 
       // [...] 
      } 
     }); 
    } 
}; 

modalController.js:

myAppControllers.controller('modalCtrl', 
    function ($scope, $modalInstance, itemArray) { 

     $scope.accept = function() { 
      $modalInstance.close(true); 
     }; 

     $scope.reject = function() { 
      $modalInstance.close(false); 
     }; 

     $scope.itemArray = itemArray; 

    }); 

und wenn ich testen diesen Code mit Karma (mit dem ui-Bootstrap -tpls.min.js Datei in der Karma-Konfigurationsdatei geladen), erhalte ich den folgenden Fehler: Fehler: [$ injector: unpr] [http://errors.angularjs.org/1.2.15-build.2389+sha.c5f2f58/ $ injector/unpr? P0 =% 24modalInstanceProvider% 20% 3C-% 20% 24modalInstance] 1 bei Fehler (nativ), was bedeutet, dass Jasmine es nicht schafft, den Anbieter zu finden für $ modalInstance.

Ich weiß nicht einmal Test Sachen auf diesem Controller, noch nicht, aber hier ist meine Jasmin Testdatei:

testModalController.js:

describe('Controller: modalCtrl', function() { 

    beforeEach(module('myApp')); 

    var Ctrl; 
    var scope; 

    // Initialize the controller and a mock scope 
    beforeEach(inject(
     function ($controller, $rootScope) { 
      scope = $rootScope.$new(); 

      Ctrl = $controller('modalCtrl', { $scope: scope }); 
     }) 
    ); 

    describe('Initial state', function() { 
     it('should instantiate the controller properly', function() { 
      expect(Ctrl).not.toBeUndefined(); 
     }); 

     it('should initialize its values properly', function() { 

     }); 
    }); 

}); 

Haben Sie zu diesem Problem keine Ahnung bekam ? Es ist nicht das erste "externe" Modul, das ich benutze (und teste), und ich habe das gleiche getan wie für die anderen, nur dass es dieses Mal nicht funktioniert und ich habe keine Ahnung warum.

==========================================

EDIT: Schnell & wahrscheinlich schmutzig Lösung:

okay, so basiert auf dem Umfang spöttischen Methode im Controller Instanziierung Jasmin, habe ich herausgefunden, wie ich „lösen“ mein Problem könnte, aber es ist wahrscheinlich ziemlich schmutzig, so fühlen Sie sich frei zu kommentieren, wenn Sie einen besseren Weg finden, um zu tun, was ich vorhabe.

testModalController.js:

describe('Controller: modalCtrl', function() { 

    beforeEach(module('myApp')); 

    var Ctrl; 
    var scope; 
    var modalInstance; 

    // Initialize the controller and a mock scope 
    beforeEach(inject(
     function ($controller, $rootScope, _$modal_) { 
      scope = $rootScope.$new(); 
      modalInstance = _$modal_.open({ 
       templateUrl: 'views/modalView.html' 
      }); 

      Ctrl = $controller('modalCtrl', { 
       $scope: scope, 
       $modalInstance: modalInstance, 
       itemArray: function() { return ['a', 'b', 'c']; } 
      }); 
     }) 
    ); 

    describe('Initial state', function() { 
     it('should instantiate the controller properly', function() { 
      expect(Ctrl).not.toBeUndefined(); 
     }); 

     it('should initialize its values properly', function() { 

     }); 
    }); 

}); 

Auf diese Weise Jasmin für die Anbieter suchen nicht mehr, weil Sie bereits die Elemente injiziert, die diese Anbieter benötigen werden sollen. Es funktioniert, aber ich glaube, es könnte auf eine bessere Art und Weise getan werden ...

+0

Sie ersetzt werden müssen Bootstrap-Modul laden ('ui.bootstrap') oder vielleicht ('ui.bootstrap.modal'). Versuche es und sag es mir. Auch ein Plünderer hilft immer. –

+0

Das Gleiche. Abhängigkeiten hinzugefügt, aber der gleiche Fehler wird im Konsolenfenster angezeigt. Irgendeine Lösungsmöglichkeit? Was löst es aus? Ich habe versucht [hier] (http://plnkr.co/edit/OuBIcvbe08FqPc6wjyBq?p=preview) und es funktioniert gut, aber ein Schritt nach links in meiner App und es sendet diesen höllischen Fehler in der Konsole. – Eugene

Antwort

63

Ich löse dies, indem ich einfach modal und modalInstance Objekte erstellen und überprüfen, dass sie von meinem Controller-Code aufgerufen wurden. Da modal und modalInstance Teil einer Third Party Library sind, liegt es nicht in unserer Verantwortung zu testen, ob sie ordnungsgemäß funktionieren - es liegt vielmehr in unserer Verantwortung zu testen, ob unser Code, der die Bibliothek aufruft, in Ordnung ist.

mit Ihrem Beispiel:

describe('Controller: modalCtrl', function() { 

    beforeEach(module('myApp')); 

    var Ctrl; 
    var scope; 
    var modalInstance; 

    // Initialize the controller and a mock scope 
    beforeEach(inject(
    function ($controller, $rootScope) {  // Don't bother injecting a 'real' modal 
     scope = $rootScope.$new(); 
     modalInstance = {     // Create a mock object using spies 
     close: jasmine.createSpy('modalInstance.close'), 
     dismiss: jasmine.createSpy('modalInstance.dismiss'), 
     result: { 
      then: jasmine.createSpy('modalInstance.result.then') 
     } 
     }; 
     Ctrl = $controller('modalCtrl', { 
     $scope: scope, 
     $modalInstance: modalInstance, 
     itemArray: function() { return ['a', 'b', 'c']; } 
     }); 
    }) 
); 

    describe('Initial state', function() { 
    it('should instantiate the controller properly', function() { 
     expect(Ctrl).not.toBeUndefined(); 
    }); 

    it('should close the modal with result "true" when accepted', function() { 
     scope.accept(); 
     expect(modalInstance.close).toHaveBeenCalledWith(true); 
    }); 

    it('should close the modal with result "false" when rejected', function() { 
     scope.reject(); 
     expect(modalInstance.close).toHaveBeenCalledWith(false); 
    }); 
    }); 
}); 

Auf diese Weise brauchen wir nicht wirklich keine Abhängigkeit von den Winkel-UI-Objekte und unsere Unit-Tests sind schön und isoliert.

+0

Danke für diese Antwort, ich liebe es. Ich kämpfe seit einiger Zeit und versuche nun, meine Modalitäten auf eine gute Art und Weise zu testen, und ich denke, das geht gut! –

+0

Das ist richtig. Es ist wichtig, nicht zu erwarten, dass $ modalInstance für den Injektor in eigenen Tests verfügbar ist, da dies von anderen Diensten des uiBootstrap-Moduls zu erwarten wäre, da $ modalInstance die Instanziierung eines neuen Modales mit dem $ modal-Dienst ist (welche * für den Injektor * verfügbar ist. –

+1

Brilliant, es funktioniert wie ein Charme. – codeepic

2

+1 für fiznools Antwort. Es ist korrekt und sollte gewählt werden.

Ich möchte jedoch eine Sache beachten, es ist nicht wartbar, wie es hier dargestellt wird.

Da dieser Winkel ist, schlage ich es verwenden ..

angular.module('...').service('$modalInstance', function(){ 
    ... define spies and such 
}) 

würde Ihren Code viel mehr modular und Generika machen. einfach eine Datei unter spec irgendwo mit dem obigen Inhalt hinzufügen und sicherstellen, dass es schließen in Ihrem karma.conf

, wenn Sie sicherstellen möchten, lädt es nur in bestimmten Tests, einfach geben ihm ein einzigartiges Modulnamen und fügen Sie es module Aufruf in beforeEach

6

Statt:

modalInstance = {     // Create a mock object using spies 
 
    close: jasmine.createSpy('modalInstance.close'), 
 
    dismiss: jasmine.createSpy('modalInstance.dismiss'), 
 
    result: { 
 
    then: jasmine.createSpy('modalInstance.result.then') 
 
    } 
 
};

Dies kann wie folgt geschrieben werden:

modalInstance = jasmine.createSpyObj('modalInstance', ['close', 'dismiss', 'result.then']);
es

Auch ist kein $ modalInstance es jetzt uibModalInstance $ ist so jeder "modalInstance" oben sollte mit "uibModalInstance"

+0

+1 für das Update über $ uibModalInstance. Anscheinend änderte sich dies Mitte Oktober 2015, als sie von 0.14.3 auf 1.0.0 wechselten. –