angular-ui / bootstrap: Тестирование контроллера, использующего диалог

У меня есть контроллер, который использует диалог из 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);
                }
            });
        };
    });

Я почти новичок в тестировании и подумал, что, возможно, мне нужно протестировать две вещи:

  1. Это диалоговое окно открывается при вызове $ scope.editClientFeature ()
  2. Это $ save успешно вызывается после закрытия диалогового окна и возвращает 'результат'

Мой действительно испорченный тест теперь выглядит так:

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

});

Непосредственная проблема сейчас в том, что я не могу создать / открыть диалог. Я получаю следующую ошибку:

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

Было бы здорово, если бы кто-то уже написал тест для аналогичного варианта использования и мог бы предоставить мне пример, поскольку я довольно потерян.

Спасибо, Шон


person shaunlim    schedule 19.03.2013    source источник


Ответы (4)


Лично я стараюсь издеваться над всеми сервисами. Если проект ui-bootstrap не предоставляет макета диалога $, вам следует открыть там сообщение об ошибке и попросить его предоставить его. Однако создать его так же просто.

У макетной службы должны быть поддельные методы, которые ничего не делают, кроме как возвращать обещания. Он также должен дать вам способ сбросить все асинхронные методы, чтобы упростить синхронное тестирование.

person ProLoser    schedule 19.03.2013

Я боролся с той же проблемой до сих пор, после троллинга репозитория github я нашел тесты диалога и использовал их в качестве отправной точки:

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
      });
    });
  });
person fistoftheheavns    schedule 25.04.2013
comment
Из вашего сообщения я понял, что забыл включить модуль для ui.bootstrap в beforeEach. Спасибо! - person BrightIntelDusk; 20.03.2014

Я также предпочитаю настоящий макет. Когда он недоступен, я исправляю сервис

Чтобы проверить это:

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

Вы можете исправить $ dialog следующим образом:

$dialog.messageBox = function (title, msg, btns) {
    return {
        open: function () {
            return {
                 then: function (callback) {
                      callback('ok'); // 'ok' will be set to param result
                 }
             }
        }
    }
 };
person ozan.turksever    schedule 14.04.2013

Я считаю наиболее очевидным написать свой собственный макет диалога. Вот пример имитации диалога для имитации выбора «да».

Тестируемый код

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

Тесты

    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
    });
person Jonathan Moffatt    schedule 16.07.2013