6

Als Erstes versuche ich, den Controller zu testen, der an eine Angular Material Dialog Instanz übergeben wird.Testen des Controllers an eine Angular Material Dialog-Instanz übergeben

Als allgemeine Frage, ist es sinnvoller, einen solchen Controller separat zu testen zu machen, oder durch tatsächliches $mdDialog.show() Aufruf?

ich die erste Methode versucht bin, aber ich bin in einige Probleme laufen, vor allem damit zusammen, wie scharfkantiges Material bindet die „Einheimischen“ an die Steuerung.

Hier ist der Code, den ich den Dialog in meinem Quellcode aufzurufen bin mit, die wie erwartet funktioniert:

$mdDialog.show({ 
    controller: 'DeviceDetailController', 
    controllerAs: 'vm', 
    locals: {deviceId: "123"}, 
    bindToController: true, 
    templateUrl: 'admin/views/deviceDetail.html', 
    parent: angular.element(document.body), 
    targetEvent: event 
}); 

Ich glaube nicht, das docs aktualisiert wurden, aber ab der Version 0.9. 0 oder so, die Locals stehen dem Controller zum Zeitpunkt des Aufrufs der Konstruktorfunktion zur Verfügung (siehe this issue on Github). Hier ist eine abgespeckte Version des Controllers Konstruktorfunktion unter Test, so können Sie sehen, warum ich die Variablen müssen übergeben und zur Verfügung werden, wenn der Regler „instanziiert“:

function DeviceDetailController(devicesService) { 
    var vm = this; 

    vm.device = {}; 
// vm.deviceId = null;   //this field is injected when the dialog is created, if there is one. For some reason I can't pre-assign it to null. 

    activate(); 

    ////////// 
    function activate() { 
     if (vm.deviceId != null) { 
      loadDevice(); 
     } 
    } 

    function loadDevice() { 
     devicesService.getDeviceById(vm.deviceId) 
      .then(function(data) { 
       vm.device = data.collection; 
      }; 
    } 
} 

Ich versuche zu testen dass das Gerät vm.device zugewiesen wird, wenn eine DeviceId an die Konstruktorfunktion übergeben wird, bevor sie aufgerufen wird.

Der Test (Jasmin und Sinon, von Karma laufen):

describe('DeviceDetailController', function() { 
    var $controllerConstructor, scope, mockDevicesService; 

    beforeEach(module("admin")); 

    beforeEach(inject(function ($controller, $rootScope) { 
     mockDevicesService = sinon.stub({ 
      getDeviceById: function() {} 
     }); 
     $controllerConstructor = $controller; 
     scope = $rootScope.$new(); 
    })); 

    it('should get a device from devicesService if passed a deviceId', function() { 
     var mockDeviceId = 3; 
     var mockDevice = {onlyIWouldHaveThis: true}; 
     var mockDeviceResponse = {collection: [mockDevice]}; 
     var mockDevicePromise = { 
      then: function (cb) { 
       cb(mockDeviceResponse); 
      } 
     }; 

     var mockLocals = {deviceId: mockDeviceId, $scope: scope}; 

     mockDevicesService.getDeviceById.returns(mockDevicePromise); 

     var ctrlConstructor = $controllerConstructor('DeviceDetailController as vm', mockLocals, true); 
     angular.extend(ctrlConstructor.instance, mockLocals); 
     ctrlConstructor(); 

     expect(scope.vm.deviceId).toBe(mockDeviceId); 
     expect(scope.vm.device).toEqual(mockDevice); 
    }); 
}); 

Als ich das laufen, die erste Behauptung geht und die zweite ausfällt ("Expected Objekt ({}) gleich Object ({ onlyIWouldHaveThis: true}). "), was mir zeigt, dass deviceId in den Bereich des Controllers injiziert wird, aber anscheinend nicht rechtzeitig für die if-Klausel in der activate() -Methode, um sie zu sehen.

Sie werden feststellen, dass ich die grundlegende Verfahren zu imitieren versuche, die Angular Material verwendet von $ Controller() aufrufen, mit dem dritten Argument auf ‚true‘, die $controller() bewirkt, dass der Controller Konstruktor Funktion zurückzukehren, im Gegensatz zu der sich ergebenden Regler. Ich sollte dann in der Lage sein, den Konstruktor mit meinen lokalen Variablen zu erweitern (genau wie es Angular Material in dem oben verlinkten Code tut) und dann die Konstruktorfunktion aufzurufen, um den Controller zu instanziieren.

Ich habe eine Reihe von Dingen versucht, einschließlich der Übergabe eines isolieren Bereichs an den Controller durch Aufruf $rootScope.$new(true), ohne Wirkung (Ich kann nicht wirklich sagen, ich verstehe isolieren Bereich, aber $ mdDialog verwendet es standardmäßig).

Jede Hilfe wird geschätzt!

Antwort

0

Die erste Sache, die ich versuchen würde, würde sein, das 'als vm' von Ihrem Anruf zu $ ​​Controller zu verlieren. Sie können den Rückgabewert nur für Ihren Expect-Test verwenden, statt den Testbereich zu testen.

Versuchen Sie folgendes:

var ctrlConstructor = $controllerConstructor('DeviceDetailController', mockLocals, true); 
    angular.extend(ctrlConstructor.instance, mockLocals); 
    var vm = ctrlConstructor(); 

    expect(vm.deviceId).toBe(mockDeviceId); 
    expect(vm.device).toEqual(mockDevice);