11

我正在尝试对需要父组件和来自另一个模块的控制器的 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。我一直无法找到如何真正做到这一点。我找到了一些类似的子父指令解决方案并尝试了这些解决方案,例如通过假 HTML 元素注入父控制器,如本子父指令示例中所述,并且基本上相同的stackoverflow 解决方案没有结果。我的问题至少不同之处在于子控制器和父控制器位于不同的模块中。而且我认为范围技巧不是 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 方面的经验有限,我没有想法。

4

3 回答 3

4

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

beforeEach(inject(function(_$componentController_) {
  controller = _$componentController_('child');
  parentCtrl = _$componentController_('parent');
  controller.parentCtrl = parentCtrl;
}))
于 2016-08-10T15:46:22.527 回答
1

1.解决方案

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

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

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

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

AngularJS 文档中的示例:

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 文档 - 测试控制器

AngularJS 文档 - $componentController

使用 $componentController 对 Angular 组件进行单元测试

于 2017-03-07T04:35:20.983 回答
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');

  });
});
于 2017-03-07T05:19:02.177 回答