【问题标题】:D3.js - generating a drag event in Jasmine programmaticallyD3.js - 以编程方式在 Jasmine 中生成拖动事件
【发布时间】:2014-08-08 22:25:42
【问题描述】:

我有一个使用 D3 和 Angular 编写的折线图组件。它具有用于更改 x 轴比例的可拖动条。现在我正在尝试使用 Karma/Jasmine 测试组件。我在单元测试中触发拖动事件时遇到问题。
其他事件,如鼠标悬停和单击都可以很好地触发。我认为这是 d3 中“拖动”事件的综合实现导致了问题。 这是我用来触发拖动的代码(此类代码会在测试 html 页面上触发正确的 d3 拖动事件,但在单元测试中失败)。

    var leftBar = element.find(".left-bar")[0];
    var evObjStart = document.createEvent("MouseEvents");
    evObjStart.initMouseEvent("mousedown", true, true, window, 1, 12, 320, 12, 320, false, false, false, false, 0, null);
    var evObj = document.createEvent("MouseEvents");
    evObj.initMouseEvent("mousemove", true, true, window, 1, 100, 320, 100, 320, false, false, false, false, 0, null);
    var evObjEnd = document.createEvent("MouseEvents");
    evObjEnd.initMouseEvent("mouseup", true, true, window, 1, 200, 320, 200, 320, false, false, false, false, 0, null);

    leftBar.dispatchEvent(evObjStart);
    leftBar.dispatchEvent(evObj);
    leftBar.dispatchEvent(evObjEnd);

我发现只有第一个事件被正确分派(leftBar.dispatchEvent(evObjStart))。 其他两个事件根本没有调度。 leftBar 变量 100% 正确。我完全不知道在哪里搜索错误。
附言我尝试生成“dragstart”、“drag”和“dragend”事件,但是浏览器中的 d3 没有正确处理它们(在控制台的基本测试示例中不起作用)。 Mousedown/mousemove/mouseup 序列在浏览器中正常工作,但在单元测试中仅调度 mousedown。将非常感谢任何帮助或想法。

【问题讨论】:

  • 我认为,如果您直接使用模拟参数调用处理程序并相信浏览器供应商正确实施了事件处理,那么您的生活会大大简化。
  • 谢谢,本!我的用例有点复杂。实际上,我的代码位于 angular 指令中,因此无法从外部访问处理程序。使它们可访问实际上会破坏将此指令用作单独插件的概念(这并不意味着影响外部 html 或变量)。我想编写一个“仅测试”指令版本,处理程序从外部可见,但如果我有一个用于分发的组件和另一个用于测试的组件,这与单元测试的想法有些冲突。希望我的解释有道理)
  • 您可以通过执行各种操作使处理程序从外部访问。例如,将它们作为成员或静态属性添加到指令的控制器中。如果已正确注册,则可以使用 $controller 检索。
  • 我想我会通过创建指令来执行 d3 鼠标事件绑定来解决这个问题,然后在更像是模板/控制器构造的指令中使用这些指令。您所做的一个指令可能会尝试做太多事情,这使得测试变得困难。
  • 谢谢!现在会研究那个。你是对的,目前我将所有代码都放在一个指令中。 Angular 用于传递/更新数据,所有处理都在 d3 内部完成。我会尝试重新定义架构,谢谢你的想法!

标签: javascript angularjs unit-testing d3.js jasmine


【解决方案1】:

虽然这不是答案,但我希望这会有所帮助。

这是一种可以将处理程序分解为可测试的方法。

将它们添加为控制器的成员,如下所示:

app.controller('MyDirectiveCtrl', function($scope) {
  this.dragHandler = function() {
    // do stuff
  };
});

app.directive('MyDirective', function(){
  return {
   controller: 'MyDirectiveCtrl',
   link: function(scope, elem, attrs, ctrl) {
      var drag = d3.behavior.drag();
      drag.on('drag', ctrl.dragHandler);
      d3.select(elem[0]).call(drag);
   }
  }
});

然后进行测试:

<!-- language: lang-js -->

    // create the controller
    var ctrl = $controller('MyDirectiveCtrl', {
       $scope: mockScope
    });

    // call the handler
    ctrl.dragHandler(mock, args, here);

    // assert some difference
    expect(mock).toBe(differentSomehow

);

【讨论】:

  • 本,非常感谢您快速高效的回复。您的想法加深了我对 Angular 的理解,谢谢!我的主管希望我将内容保留在指令中以实现灵活性和独立性,因此我将寻找一种方法以不同方式对其进行更改。 PS我希望你不介意我仍然保留这个问题,也许有人碰巧触发了d3的拖动事件。
  • 我完全不介意你让问题悬而未决。
  • 告诉你的主管“Ben Lesh 说你疯了”:P 哈哈。如果某些东西很难测试,那是因为它的构造很差。您将不得不以一种或另一种方式公开这些处理程序并对其进行测试。直接测试 DOM 非常困难,而且非常脆弱。如果您必须走这条路,请考虑创建 Protractor 测试,尽管我不确定它在拖放中的效果如何。
  • 谢谢,本!我的主管是一个很棒的人,我认为他也有一个好点(很可能是我没有做对)。我将继续重新考虑架构。感谢您为这个问题付出的努力,我非常感谢!肯定会考虑量角器。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多