在AngularJS单元测试嘲讽$模式 [英] Mocking $modal in AngularJS unit tests

查看:130
本文介绍了在AngularJS单元测试嘲讽$模式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在写一个控制器单元测试触发了一个 $模式并使用承诺返回执行一些逻辑。我可以测试触发模式$家长控制,但我不能为我的生活弄清楚如何嘲笑一个成功的承诺。

我已经尝试了多种方法,包括使用 $ Q $范围。$适用()给力的承诺的分辨率。不过,我已经得到的最接近的是类似的东西放在一起的最后答案<一个href=\"http://stackoverflow.com/questions/15490150/angular-ui-bootstrap-testing-a-controller-that-uses-a-dialog\">this SO后;

我已经看到了这个问了几次与旧 $对话模式。
我找不到太多关于如何与新 $对话做模式。

有些指针将特雷斯AP preciated。

要说明我使用的UI引导文档中提供的例如,一些小修改。

控制器(主要和莫代尔)

 使用严格的;angular.module('angularUiModalApp')
    .controller('MainCtrl',函数($范围,$模式,$日志){
        $ scope.items = ['ITEM1','ITEM2','ITEM3'];        $ scope.open =功能(){            $ scope.modalInstance = $ modal.open({
                templateUrl:myModalContent.html',
                控制器:'ModalInstanceCtrl',
                解析:{
                    项目:功能(){
                        返回$ scope.items;
                    }
                }
            });            $ scope.modalInstance.result.then(功能(将selectedItem){
                $ scope.selected = selectedItem属性;
            },函数(){
                $ log.info('模态在驳回:+新的Date());
            });
        };
    })
    .controller('ModalInstanceCtrl',函数($范围,$ modalInstance,物品){
        $ scope.items =物品;
        $ scope.selected = {
            项目:$ scope.items [0]
        };        $ scope.ok =功能(){
            $ modalInstance.close($ scope.selected.item);
        };        $ scope.cancel =功能(){
            $ modalInstance.dismiss('取消');
        };
    });

视图(main.html中)

 &LT; D​​IV NG控制器=MainCtrl&GT;
    &LT;脚本类型=文/ NG-模板ID =myModalContent.html&GT;
        &LT; D​​IV CLASS =模头&GT;
            &LT; H3 I标记是一个模式&LT;!/ H3 GT&;
        &LT; / DIV&GT;
        &LT; D​​IV CLASS =模体&GT;
            &LT; UL&GT;
                &LT;李NG重复=中的项项&GT;
                    &LT;一个NG点击=selected.item =项目&GT; {{}项}&LT; / A&GT;
                &LT; /李&GT;
            &LT; / UL&GT;
            选择:其中,B&GT; {{selected.item}}&LT; / B&GT;
        &LT; / DIV&GT;
        &LT; D​​IV CLASS =模式躯&GT;
            &LT;按钮类=BTN BTN-主要NG点击=OK()&GT;确定&LT; /按钮&GT;
            &LT;按钮类=BTN BTN-警告NG点击=取消()&GT;取消&LT; /按钮&GT;
        &LT; / DIV&GT;
    &LT; / SCRIPT&GT;    &LT;按钮类=BTN BTN-默认的NG点击=open()的&GT;打开ME&LT;!/按钮&GT;
    &LT; D​​IV NG秀=选择&GT;从模式选择:{{}选择}&LT; / DIV&GT;
&LT; / DIV&GT;

测试

 使用严格的;描述(控制器:MainCtrl',函数(){    //加载控制器模块
    beforeEach(模块('angularUiModalApp'));    VAR MainCtrl,
        范围;    VAR fakeModal = {
        打开:功能(){
            返回{
                结果:{
                    则:函数(回调){
                        回调(ITEM1);
                    }
                }
            };
        }
    };    beforeEach(注(函数($模态){
        spyOn($模式,开放)andReturn(fakeModal)。
    }));
    //初始化控制器和模拟范围
    beforeEach(注(函数($控制器,$ rootScope,_ $ modal_){
        范围= $ rootScope $新的()。
        MainCtrl = $控制器('MainCtrl',{
            $适用范围:适用范围,
            $模式:_ $ modal_
        });
    }));    它('应显示成功模式时,返回登录成功响应',函数(){
        期待(scope.items).toEqual(['ITEM1','ITEM2','项目3']);        //模拟出的模式结束,与所选择的项目解决,比如说1
        scope.open(); //打开模态
        scope.modalInstance.close('ITEM1');
        期待(scope.selected).toEqual('ITEM1');
        //没有骰子(scope.selected)未按照规定茉莉花。
    });
});


在窥视在beforeEach的$ modal.open功能,

  spyOn($模式,开放)andReturn(fakeModal)。要么spyOn($模式,开放)and.returnValue(fakeModal)。 //茉莉花2.0+

您需要返回什么$ modal.open正常返回,而不是$模式,为您制定了不包括打开函数的一个模拟的模拟在你的 fakeModal 模拟。假模态必须有一个结果包含然后函数来存储回调对象(被称为OK时或取消按钮被点击)。它还需要一个关闭功能(模拟的模式的确定按钮点击)和关闭功能(模拟取消在模式按钮点击)。在关闭关闭函数调用所需的回调函数调用时。

更改 fakeModal 以下和单元测试将传递:

  VAR fakeModal = {
    结果:{
        那么:功能(confirmCallback,cancelCallback){
            //存储供以后的回调时,在对话框的确定​​或取消按钮,用户点击
            this.confirmCallBack = confirmCallback;
            this.cancelCallback = cancelCallback;
        }
    },
    关闭:函数(项目){
        //用户点击了模态对话框OK,调用与所选项目的存储确认回调
        this.result.confirmCallBack(项目);
    },
    解雇:函数(类型){
        //用户点击模态对话框取消,调用存储取消回调
        this.result.cancelCallback(类型);
    }
};

此外,您可以通过添加一个属性的取消处理程序进行测试,在这种情况下测试取消对话框的情况下 $ scope.canceled

  $ scope.modalInstance.result.then(功能(将selectedItem){
    $ scope.selected = selectedItem属性;
},函数(){
    $ scope.canceled = TRUE; //标记为取消模态
    $ log.info('模态在驳回:+新的Date());
});

一旦取消标志被设置,单元测试会是这个样子:

 它(应该取消对话框解雇时被调用,$ scope.canceled应该是真实的,函数(){
    期待(scope.canceled).toBeUndefined();    scope.open(); //打开模态
    scope.modalInstance.dismiss(取消); //调用解雇(模拟点击模式的取消按钮)
    期待(scope.canceled).toBe(真);
});

I'm writing a unit test for a controller that fires up a $modal and uses the promise returned to execute some logic. I can test the parent controller that fires the $modal, but I can't for the life of me figure out how to mock a successful promise.

I've tried a number of ways, including using $q and $scope.$apply() to force the resolution of the promise. However, the closest I've gotten is putting together something similar to the last answer in this SO post;

I've seen this asked a few times with the "old" $dialog modal. I can't find much on how to do it with the "new" $dialog modal.

Some pointers would be tres appreciated.

To illustrate the problem I'm using the example provided in the UI Bootstrap docs, with some minor edits.

Controllers (Main and Modal)

'use strict';

angular.module('angularUiModalApp')
    .controller('MainCtrl', function($scope, $modal, $log) {
        $scope.items = ['item1', 'item2', 'item3'];

        $scope.open = function() {

            $scope.modalInstance = $modal.open({
                templateUrl: 'myModalContent.html',
                controller: 'ModalInstanceCtrl',
                resolve: {
                    items: function() {
                        return $scope.items;
                    }
                }
            });

            $scope.modalInstance.result.then(function(selectedItem) {
                $scope.selected = selectedItem;
            }, function() {
                $log.info('Modal dismissed at: ' + new Date());
            });
        };
    })
    .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');
        };
    });

The view (main.html)

<div ng-controller="MainCtrl">
    <script type="text/ng-template" id="myModalContent.html">
        <div class="modal-header">
            <h3>I is a modal!</h3>
        </div>
        <div class="modal-body">
            <ul>
                <li ng-repeat="item in items">
                    <a ng-click="selected.item = item">{{ item }}</a>
                </li>
            </ul>
            Selected: <b>{{ selected.item }}</b>
        </div>
        <div class="modal-footer">
            <button class="btn btn-primary" ng-click="ok()">OK</button>
            <button class="btn btn-warning" ng-click="cancel()">Cancel</button>
        </div>
    </script>

    <button class="btn btn-default" ng-click="open()">Open me!</button>
    <div ng-show="selected">Selection from a modal: {{ selected }}</div>
</div>

The test

'use strict';

describe('Controller: MainCtrl', function() {

    // load the controller's module
    beforeEach(module('angularUiModalApp'));

    var MainCtrl,
        scope;

    var fakeModal = {
        open: function() {
            return {
                result: {
                    then: function(callback) {
                        callback("item1");
                    }
                }
            };
        }
    };

    beforeEach(inject(function($modal) {
        spyOn($modal, 'open').andReturn(fakeModal);
    }));


    // Initialize the controller and a mock scope
    beforeEach(inject(function($controller, $rootScope, _$modal_) {
        scope = $rootScope.$new();
        MainCtrl = $controller('MainCtrl', {
            $scope: scope,
            $modal: _$modal_
        });
    }));

    it('should show success when modal login returns success response', function() {
        expect(scope.items).toEqual(['item1', 'item2', 'item3']);

        // Mock out the modal closing, resolving with a selected item, say 1
        scope.open(); // Open the modal
        scope.modalInstance.close('item1');
        expect(scope.selected).toEqual('item1'); 
        // No dice (scope.selected) is not defined according to Jasmine.
    });
});

解决方案

When you spy on the $modal.open function in the beforeEach,

spyOn($modal, 'open').andReturn(fakeModal);

or 

spyOn($modal, 'open').and.returnValue(fakeModal); //For Jasmine 2.0+

you need to return a mock of what $modal.open normally returns, not a mock of $modal, which doesn’t include an open function as you laid out in your fakeModal mock. The fake modal must have a result object that contains a then function to store the callbacks (to be called when the OK or Cancel buttons are clicked on). It also needs a close function (simulating an OK button click on the modal) and a dismiss function (simulating a Cancel button click on the modal). The close and dismiss functions call the necessary call back functions when called.

Change the fakeModal to the following and the unit test will pass:

var fakeModal = {
    result: {
        then: function(confirmCallback, cancelCallback) {
            //Store the callbacks for later when the user clicks on the OK or Cancel button of the dialog
            this.confirmCallBack = confirmCallback;
            this.cancelCallback = cancelCallback;
        }
    },
    close: function( item ) {
        //The user clicked OK on the modal dialog, call the stored confirm callback with the selected item
        this.result.confirmCallBack( item );
    },
    dismiss: function( type ) {
        //The user clicked cancel on the modal dialog, call the stored cancel callback
        this.result.cancelCallback( type );
    }
};

Additionally, you can test the cancel dialog case by adding a property to test in the cancel handler, in this case $scope.canceled:

$scope.modalInstance.result.then(function (selectedItem) {
    $scope.selected = selectedItem;
}, function () {
    $scope.canceled = true; //Mark the modal as canceled
    $log.info('Modal dismissed at: ' + new Date());
});

Once the cancel flag is set, the unit test will look something like this:

it("should cancel the dialog when dismiss is called, and $scope.canceled should be true", function () {
    expect( scope.canceled ).toBeUndefined();

    scope.open(); // Open the modal
    scope.modalInstance.dismiss( "cancel" ); //Call dismiss (simulating clicking the cancel button on the modal)
    expect( scope.canceled ).toBe( true );
});

这篇关于在AngularJS单元测试嘲讽$模式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆