angularjs - test - Unidad de prueba de un controlador modalInstance con Karma/Jasmine
unit test angular 4 (3)
EDITAR: solución rápida y sucia al final de este post
Estoy usando una ventana modal de AngularUI-Bootstrap de la misma manera que se explica en el sitio web, excepto que dividí los archivos. Por eso tengo:
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;
});
y cuando pruebo este código con Karma (con el archivo ui-bootstrap-tpls.min.js cargado en el archivo de configuración de karma), aparece el siguiente error: Error: [$ injector: unpr] [ http://errors.angularjs.org/1.2.15-build.2389+sha.c5f2f58/ $ injector / unpr? p0 =% 24modalInstanceProvider% 20% 3C-% 20% 24modalInstance] 1 en Error (nativo) , lo que significa que el jazmín no se las arregla para encuentra el proveedor para $ modalInstance.
Ni siquiera he probado cosas en este controlador, todavía no, pero aquí está mi archivo de prueba de jazmín:
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 () {
});
});
});
¿Tienes alguna pista sobre este problema? No es el primer módulo "externo" que uso (y pruebo), e hice lo mismo que para los demás, excepto que esta vez no funciona y no tengo idea de por qué.
==========================================
EDITAR: Solución rápida y probablemente sucia:
De acuerdo, basándome en el método de simulación de alcance en la instanciación del controlador de Jasmine, descubrí cómo podría "resolver" mi problema, pero es probable que esté bastante sucio, así que no dude en comentarlo si encuentra una mejor manera de hacer lo que pretendo. .
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 () {
});
});
});
De esta manera, Jasmine ya no busca proveedores, porque ya ha inyectado los elementos que se supone que necesitan esos proveedores. Funciona, pero creo que podría hacerse de una mejor manera ...
+1 para la respuesta de fiznool. Es correcto y debe ser elegido ..
Me gustaría señalar una cosa, sin embargo, no se puede mantener de la forma en que se presenta aquí.
Ya que esto es angular, sugiero usarlo ..
angular.module(''...'').service(''$modalInstance'', function(){
... define spies and such
})
Haría tu código mucho más modular y genérico. simplemente agregue un archivo bajo spec
algún lugar con el contenido anterior y asegúrese de incluirlo en su karma.conf
Si desea asegurarse de que se cargue solo en pruebas específicas, simplemente dele un nombre de módulo único y agréguelo a la invocación del module
de beforeEach
En lugar de:
modalInstance = { // Create a mock object using spies
close: jasmine.createSpy(''modalInstance.close''),
dismiss: jasmine.createSpy(''modalInstance.dismiss''),
result: {
then: jasmine.createSpy(''modalInstance.result.then'')
}
};
Esto se puede escribir como:
modalInstance = jasmine.createSpyObj(''modalInstance'', [''close'', ''dismiss'', ''result.then'']);
Además, no hay $ modalInstance, ahora es $ uibModalInstance, por lo que cada "modalInstance" anterior debe reemplazarse por "uibModalInstance"
Estoy resolviendo esto simplemente creando objetos modal
y modalInstance
y verificando que han sido llamados por mi código de controlador. Ya que modal
y modalInstance
son parte de una biblioteca de terceros, no es nuestra responsabilidad probar que funcionan correctamente, sino que es nuestra responsabilidad probar que nuestro código que llama a la biblioteca funciona bien.
Usando tu ejemplo:
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);
});
});
});
De esta manera, realmente no necesitamos ninguna dependencia de los objetos de Angular-UI y nuestras pruebas de unidad son agradables y aisladas.