6

Prima di tutto, sto provando a testare il controller che viene passato a un'istanza Angular Material Dialog.Test del controller passato a un'istanza di Dialogo materiale angolare

Come domanda generale, ha più senso testare un controller di questo tipo separatamente o invocando effettivamente $mdDialog.show()?

Sto tentando il primo metodo, ma sto riscontrando alcuni problemi, principalmente relativi a come il materiale angolare lega i "locals" al controller.

Ecco il codice che sto usando per richiamare la finestra nel mio codice sorgente, che funziona come previsto:

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

Io non credo che il docs sono stati aggiornati, ma a partire dalla versione 0.9. 0 o giù di lì, i locali sono disponibili per il controller nel momento in cui viene chiamata la funzione del costruttore (vedere this issue on Github). Ecco una versione ridotta della funzione di costruzione di controllo in prova, in modo da poter vedere perché ho bisogno della variabile da passare dentro e disponibile quando il controller è "istanziato":

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; 
      }; 
    } 
} 

sto cercando di testare che il dispositivo è assegnato a vm.device quando un deviceId viene passato alla funzione di costruzione prima di essere richiamato.

Il test (gelsomino e Sinon, gestito dal karma):

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); 
    }); 
}); 

Quando eseguo questo, la prima affermazione passa e il secondo fallisce ("Previsto oggetto ({}) alla parità di oggetto ({ onlyIWouldHaveThis: true}). "), che mi mostra che deviceId viene iniettato nello scope del controller, ma apparentemente non in tempo per la clausola if nel metodo activate() per vederlo.

Si noterà che sto cercando di imitare la procedura di base che Angular Material utilizza chiamando $ controllore() con il terzo argomento impostato su 'vero', che provoca $controller() per restituire la funzione di costruzione di controllo, in contrasto con la conseguente controller. Dovrei quindi essere in grado di estendere il costruttore con le mie variabili locali (proprio come fa Angular Material nel codice collegato sopra), e quindi invocare la funzione di costruzione per istanziare il controller.

Ho provato un certo numero di cose, incluso il passaggio di un ambito isolato al controller chiamando $rootScope.$new(true), senza alcun effetto (in realtà non posso dire di comprendere completamente l'ambito isolato, ma $ mdDialog lo utilizza per impostazione predefinita).

Qualsiasi aiuto è apprezzato!

risposta

0

La prima cosa che proverei sarebbe quella di perdere "come VM" dalla chiamata a $ controller. Puoi semplicemente utilizzare il valore di ritorno per le tue aspettative piuttosto che per verificare l'ambito.

Prova questo:

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

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