Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

D3.js - generating a drag event in Jasmine programmatically

I have a line chart component written using D3 and Angular. It has draggable bars used to change the scale of x axis. Now I am trying to test the component using Karma/Jasmine. I have a trouble triggering drag event in the unit test.
Other events like mouseover and click are triggered just fine. I think it's the synthetized implementation of "drag" event in d3 which causes issue. Here is the code I use to trigger dragging (such code fires a correct d3 drag event on a test html page, but fails inside a unit test).

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

I found out that only the first event is correctly dispatched (leftBar.dispatchEvent(evObjStart)). Other two events are not dispatched at all. leftBar variable is correct 100%. I am totally lost on where to search the error.
P.S. I tried generating "dragstart", "drag" and "dragend" events, but they are not handled properly by d3 in browser (did not work in a basic test example in console). Mousedown/mousemove/mouseup sequence works correctly in browser, but only mousedown is dispatched in the unit test. Will be very grateful for any help or ideas.

like image 447
Olga Gnatenko Avatar asked Jun 18 '14 14:06

Olga Gnatenko


1 Answers

While this isn't an answer, I hope this helps.

Here's a way you can break your handlers off into something testable.

Add them as members of your controller like so:

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

Then to test:

<!-- 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

);
like image 74
Ben Lesh Avatar answered Oct 13 '22 18:10

Ben Lesh