xeditable uib tpls ngx bootstrap javascript angularjs unit-testing angular-ui

javascript - tpls - uib-pagination angularjs



Prueba del controlador de instancia modal AngularUI Bootstrap (4)

Alternativamente, si está usando jazmín, puede $uibModalInstance el $uibModalInstance utilizando el método createSpy :

beforeEach(inject(function ($controller, $rootScope) { $scope = $rootScope.$new(); $uibModalInstance = jasmine.createSpyObj(''$uibModalInstance'', [''close'', ''dismiss'']); ModalCtrl = $controller(''ModalCtrl'', { $scope: $scope, $uibModalInstance: $uibModalInstance, }); }));

Y spyOn sin tener que llamar a spyOn en cada método, digamos que tiene 2 métodos de alcance, cancel() y confirm() :

it(''should let the user dismiss the modal'', function () { expect($scope.cancel).toBeDefined(); $scope.cancel(); expect($uibModalInstance.dismiss).toHaveBeenCalled(); }); it(''should let the user confirm the modal'', function () { expect($scope.confirm).toBeDefined(); $scope.confirm(); expect($uibModalInstance.close).toHaveBeenCalled(); });

Esta es una especie de pregunta de seguimiento a esta: Mocking $ modal en pruebas de unidad AngularJS

El SO mencionado es una pregunta excelente con una respuesta muy útil. Sin embargo, la pregunta que me queda después de esto es esta: ¿cómo pruebo la unidad del controlador de instancia modal? En el SO al que se hace referencia, se prueba el controlador de invocación, pero el controlador de instancia modal se burla. Podría decirse que este último también debería ser probado, pero esto ha demostrado ser muy complicado. Este es el por qué:

Copiaré el mismo ejemplo del SO aquí mencionado:

.controller(''ModalInstanceCtrl'', function($scope, $modalInstance, items){ $scope.items = items; $scope.selected = { item: $scope.items[0] }; $scope.ok = function () { $modalInstance.close($scope.selected.item); }; $scope.cancel = function () { $modalInstance.dismiss(''cancel''); }; });

Así que mi primer pensamiento fue que simplemente crearía una instancia del controlador directamente en una prueba, como cualquier otro controlador bajo prueba:

beforeEach(inject(function($rootScope) { scope = $rootScope.$new(); ctrl = $controller(''ModalInstanceCtrl'', {$scope: scope}); });

Esto no funciona porque en este contexto, angular no tiene un proveedor para inyectar $ modalInstance, ya que eso es proporcionado por el modo UI.

Luego, me dirijo al plan B: use $ modal.open para crear una instancia del controlador. Esto funcionará como se espera:

beforeEach(inject(function($rootScope, $modal) { scope = $rootScope.$new(); modalInstance = $modal.open({ template: ''<html></html>'', controller: ''ModalInstanceCtrl'', scope: scope }); });

(Tenga en cuenta que la plantilla no puede ser una cadena vacía o fallará crípticamente).

El problema ahora es que no tengo visibilidad del alcance, que es la forma habitual de recopilar recursos de pruebas unitarias, etc. En mi código real, el controlador llama a un servicio de recursos para rellenar una lista de opciones; mi intento de probar esto establece un expectgetOf de satisfacer el servicio que mi controlador está utilizando, y quiero validar que el controlador está poniendo el resultado en su alcance. Pero el modal está creando un nuevo ámbito para el controlador de instancia modal (utilizando el ámbito que paso como un prototipo), y no puedo entender cómo puedo obtener un hueco de ese alcance. El objeto modalInstance no tiene una ventana en el controlador.

¿Alguna sugerencia sobre la forma "correcta" de probar esto?

(NB: el comportamiento de crear un alcance derivado para el controlador de instancia modal no es inesperado, es un comportamiento documentado. Mi pregunta de cómo probarlo sigue siendo válida independientemente).


El mismo problema es con $ uidModalInstance y puede resolverlo de manera similar:

var uidModalInstance = { close: function() {}, dismiss: function() {} }; $ctrl = $controller(''ModalInstanceCtrl'', { $scope: $scope, $uibModalInstance: uidModalInstance });

o como dijo @yvesmancera, puedes usar el método jasmine.createSpy, como:

var uidModalInstance = jasmine.createSpyObj(''$uibModalInstance'', [''close'', ''dismiss'']); $ctrl = $controller(''ModalInstanceCtrl'', { $scope: $scope, $uibModalInstance: uidModalInstance });


Probé los controladores utilizados en los cuadros de diálogo modales instanciando el controlador directamente (de la misma manera en que inicialmente pensaste hacerlo más arriba).

Como no hay una versión burlada de $modalInstance , simplemente creo un objeto simulado y lo paso al controlador.

var modalInstance = { close: function() {}, dismiss: function() {} }; var items = []; // whatever... beforeEach(inject(function($rootScope) { scope = $rootScope.$new(); ctrl = $controller(''ModalInstanceCtrl'', { $scope: scope, $modalInstance: modalInstance, items: items }); }));

Ahora las dependencias para el controlador están satisfechas y puede probar este controlador como cualquier otro controlador.

Por ejemplo, puedo hacer spyOn(modalInstance, ''close'') y luego afirmar que mi controlador está cerrando el diálogo en el momento apropiado.


Siga los pasos dados a continuación:

  • Definir stub para ModalInstance como dar a continuación

    uibModalInstanceStub = { close: sinon.stub(), dismiss: sinon.stub() };

  • Pasar el apéndice de instancia modal al crear el controlador

    function createController() { return $controller( ppcConfirmGapModalComponentFullName, { $scope: scopeStub, $uibModalInstance: uibModalInstanceStub }); } });

  • Los métodos stub close (), dismiss () se llamarán como parte de las pruebas

    it (''confirmar modal - verificar acción de confirmación, en ok () llamar a modalInstance cerrar () función'', función () {acción = ''Ok''; scopeStub.item = testItem; createController (); scopeStub.ok ();} );