【问题标题】:Angular 1.5 unit test controller that requires parent component's controllerAngular 1.5 单元测试控制器,需要父组件的控制器
【发布时间】:2016-10-31 21:19:25
【问题描述】:

我正在尝试对需要父组件和来自另一个模块的控制器的 AngularJS 1.5(带有 Webpack)组件的(子)控制器进行单元测试。

子控制器结构:

function ChildController () {
  var vm = this;

  vm.searchText = '';

  vm.submit = function() {
    var data = {};
    data['srch'] = vm.searchText;
    vm.parentCtrl.submitTextSearch(data);
  };
}

module.exports = ChildController;

子组件:

var template = require('./child.html');
var controller = require('./child.controller');

var childComponent = {
  require: {
    parentCtrl: '^parent'
  },
  template: template,
  controller: controller,
  controllerAs: 'vm'
};

module.exports = childComponent;

所以我想做的是模拟出 childController 的 submit() 函数中所需的 parentCtrl。我一直无法找到如何真正做到这一点。我找到了一些类似的子父指令解决方案并尝试了这些,例如通过this child-parent directive example 中描述的假HTML 元素注入父控制器,基本相同stackoverflow solutions 没有结果。我的问题至少不同之处在于子控制器和父控制器位于不同的模块中。而且我认为范围技巧不是 Angular 1.5 风格的?

没有失败的模拟尝试的 Jasmine 测试框架:

describe('child component', function() {
  describe('child controller', function() {
    var controller;
    beforeEach(angular.mock.module('child'));
    beforeEach(inject(function(_$componentController_) {
      controller = _$componentController_('child');
    }))
    it('should work', function() {
      controller.searchText = "test";
      controller.submit();
    })
  })
})

这导致TypeError: Cannot read property 'submitTextSearch' of undefined。我应该怎么做才能模拟父控制器?由于我在 Angular 方面的经验有限,我没有想法。

【问题讨论】:

    标签: angularjs unit-testing angularjs-components


    【解决方案1】:

    使用下面的代码将初始化它,请检查 Jasmine 单元测试Plunker

    var ctrP = $componentController('parentComp');
    var ctrl = $componentController('childComp', {}, {
      parentCtrl: ctrP
    });
    

    你的测试用例应该如下图所示:

    'use strict';
    
    describe('component: heroDetail', function() {
      var $componentController, $compile, $rootScope;
    
      beforeEach(module('plunker'));
      beforeEach(inject(function(_$componentController_) {
        $componentController = _$componentController_;
      }));
    
      it('should expose a `hero` object', function() {
        var ctrP = $componentController('parentComp');
        console.log(ctrP);
        var ctrl = $componentController('childComp', {}, {
          parentCtrl: ctrP
        });
        console.log(ctrl);
        ctrl.submit('some data');
        expect(ctrl.parentCtrl.searchText).toEqual('some data');
    
      });
    });
    

    【讨论】:

      【解决方案2】:

      1.解决方案

      在您的测试中,使用新范围实例化父控制器:

      mainScope = $rootScope.$new();
      $controller('ParentController', {$scope: mainScope});
      

      然后在您的子控制器中,使用之前实例化的作用域实例化一个新作用域:

      childScope = mainScope.$new();
      $controller('ChildController', {$scope: childScope});
      

      来自AngularJS documentation的示例:

      describe('state', function() {
      
        var mainScope, childScope, grandChildScope;
      
        beforeEach(module('myApp'));
      
        beforeEach(inject(function($rootScope, $controller) {
            mainScope = $rootScope.$new();
            $controller('MainController', {$scope: mainScope});
            childScope = mainScope.$new();
            $controller('ChildController', {$scope: childScope});
            grandChildScope = childScope.$new();
            $controller('GrandChildController', {$scope: grandChildScope});
        }));
      
        it('should work', function() {
            grandChildScope.searchText = "test";
            grandChildScope.submit();
        });
      });
      

      2.解决方案

      子控制器结构:

      function ChildController () {
        var vm = this;
      
        vm.searchText = '';
      
        vm.submit = function() {
          var data = {};
          data['srch'] = vm.searchText;
          vm.parentCtrl.submitTextSearch(data);
        };
      }
      
      module.exports = ChildController;
      

      子组件:

      var template = require('./child.html');
      var controller = require('./child.controller');
      
          var childComponent = {
            bindings: {
               searchText: 'test'
            },
            template: template,
            controller: controller,
            controllerAs: 'vm'
          };
      
      module.exports = childComponent;
      
      var ChildController = $componentController('childComponent', null, {...});
      ChildController.$onInit();
      expect(ChildController.searchText).to.equal('test');
      expect(ChildController.submit()).to.equal('*expected result value should come here*');
      

      参考:

      AngularJS documentation - Testing Controllers

      AngularJS documentation - $componentController

      Unit Testing Angular Components with $componentController

      【讨论】:

        【解决方案3】:

        在您的情况下,您将添加 parentCtrl 作为组件的依赖项,因此为了测试它,您还必须模拟父组件并将其分配给控制器。因此,您需要执行以下操作:

        beforeEach(inject(function(_$componentController_) {
          controller = _$componentController_('child');
          parentCtrl = _$componentController_('parent');
          controller.parentCtrl = parentCtrl;
        }))
        

        【讨论】:

        • 我已经尝试过了,但对我不起作用。仍然得到“无法找到指令''所需的控制器''!”。
        • 你确定你的业力配置吗?可能有些文件没有被加载。
        猜你喜欢
        • 2016-07-29
        • 1970-01-01
        • 2017-04-18
        • 2017-08-17
        • 1970-01-01
        • 2014-01-16
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多