Angular -ui / bootstrap: testing a controller using a dialog

I have a controller that uses the dialog from angular -ui / bootstrap:

function ClientFeatureController($dialog, $scope, ClientFeature, Country, FeatureService) { //Get list of client features for selected client (that is set in ClientController) $scope.clientFeatures = ClientFeature.query({clientId: $scope.selected.client.id}, function () { console.log('getting clientfeatures for clientid: ' + $scope.selected.client.id); console.log($scope.clientFeatures); }); //Selected ClientFeature $scope.selectedClientFeature = {}; /** * Edit selected clientFeature. * @param clientFeature */ $scope.editClientFeature = function (clientFeature) { //set selectedClientFeature for data binding $scope.selectedClientFeature = clientFeature; var dialogOpts = { templateUrl: 'partials/clients/dialogs/clientfeature-edit.html', controller: 'EditClientFeatureController', resolve: {selectedClientFeature: function () { return clientFeature; } } }; //open dialog box $dialog.dialog(dialogOpts).open().then(function (result) { if (result) { $scope.selectedClientFeature = result; $scope.selectedClientFeature.$save({clientId: $scope.selectedClientFeature.client.id}, function (data, headers) { console.log('saved.'); }, null); } }); }; }); 

I am almost completely new to testing and realized that maybe I need to check two things:

  • A dialog will open when $ scope.editClientFeature () is called
  • This $ save is called successfully after closing the dialog box and returns the result

My really confusing test now looks like this:

 describe('ClientFeatureController', function () { var scope, $dialog, provider; beforeEach(function () { inject(function ($controller, $httpBackend, $rootScope, _$dialog_) { scope = $rootScope; $dialog = _$dialog_; //mock client scope.selected = {}; scope.selected.client = { id: 23805 }; $httpBackend.whenGET('http://localhost:3001/client/' + scope.selected.client.id + '/clientfeatures').respond(mockClientFeatures); $controller('ClientFeatureController', {$scope: scope}); $httpBackend.flush(); }); }); it('should inject dialog service from angular-ui-bootstrap module', function () { expect($dialog).toBeDefined(); console.log($dialog); //{} }); var dialog; var createDialog = function (opts) { dialog = $dialog.dialog(opts); }; describe('when editing a clientfeature', function () { createDialog({}); console.log(dialog); //undefined // var res; // var d; // beforeEach(function () { // var dialogOpts = { // template: '<div>dummy template</div>' // }; // console.log(dialog); // d = $dialog.dialog(dialogOpts); // d.open(); // }); // // it('should open a dialog when editing a client feature', function () { // expect(d.isOpen()).toBe(true); // }); }); }); 

The immediate problem is that I cannot create / open a dialog. I get the following error:

 Chrome 25.0 (Mac) ClientFeatureController when editing a clientfeature encountered a declaration exception FAILED TypeError: Cannot call method 'dialog' of undefined 

It would be great if someone had already written a test for a similar use case and could provide me with an example, since I'm pretty lost.

Thanks, Shaun

+2
javascript angularjs testing jasmine angular-ui
Mar 19 '13 at 1:47
source share
4 answers

Personally, I'm trying to make fun of all the services. If the ui-bootstrap project does not provide a $ dialog layout, you must open the big code there and request it. However, creating it is just as easy.

The mock service should have fake methods that do nothing but return promises. It should also provide you with a method for cleaning all asynchronous methods in order to simplify synchronous testing.

+2
Mar 19 '13 at 2:59
source share

I struggled with the same problem until right now, after trolling the github repository, I found dialogue tests and used this as a starting point:

 var $dialog,$scope,$httpBackend; beforeEach(module('ui.bootstrap.dialog')); beforeEach(function(){ inject(function (_$dialog_, _$httpBackend_, $controller){ $dialog = _$dialog_; $httpBackend = _$httpBackend_; $httpBackend.expectGET('/appServer/list') .respond([{ id:1, name:'test1' }, { id:2, name:'test2' }, { id:3, name:'test3' }]); //setup controller scope scope = {}; ServerCtrl = $controller('ServerCtrl', { $scope: scope, $dialog:$dialog }); }); }); 
+6
Apr 25 '13 at 16:44
source share

I also prefer the right layout. When it is unavailable, I fix the service

To check this:

 $dialog.messageBox(title, msg, btns) .open() .then(function (result) { if (result == 'ok') { // block executed if user click OK } }); 

You can set $ dialog like this:

 $dialog.messageBox = function (title, msg, btns) { return { open: function () { return { then: function (callback) { callback('ok'); // 'ok' will be set to param result } } } } }; 
+3
Apr 14 '13 at 10:06
source share

It seems clearer to write my own dialogue layout. Here is an example of extracting a dialog to simulate a yes choice.

Verified Code

 .controller('AdminListingCtrl', function AdminListingController($scope, $dialog, houseRepository) { $scope.houses = houseRepository.query(); $scope.remove = function (house) { var dlg = $dialog.messageBox('Delete house', 'Are you sure?', [ {label: 'Yep', result: 'yes'}, {label: 'Nope', result: 'no'} ]); dlg.open().then(function (result) { if (result == 'yes') { houseRepository.remove(house.id); $scope.houses = houseRepository.query(); } }); }; } 

Test

  describe('when deleting a house', function () { var fakeDialog = { open: function() { return { then: function(callback) { callback("yes"); } }; } }; beforeEach(inject(function($dialog) { spyOn($dialog, 'messageBox').andReturn(fakeDialog); })); it('should call the remove method on the houseRepository', function () { scope.remove({id: 99}); expect(houseRepository.remove).toHaveBeenCalledWith(99); }); // etc }); 
+2
Jul 16 '13 at 14:08
source share



All Articles