Andrew Luhring
Andrew Luhring

Reputation: 1894

Testing angular mousedown, mousemove, mouseup

In the directives section of the angular docs

They provide roughly this example of how to make a drag thing.

My question is how would you test THEIR EXAMPLE/implementation:

  var startX = 0, startY = 0;
  scope.x = 0;
  scope.y = 0;
  element.css({
    top: scope.y, 
    left: scope.x
  });

  element.on('mousedown', function(event) {
    // Prevent default dragging of selected content
    event.preventDefault();
    startX = event.pageX - scope.x;
    startY = event.pageY - scope.y;
    $document.on('mousemove', mousemove);
    $document.on('mouseup', mouseup);
  });

  function mousemove(event) {
    scope.y = event.pageY - startY;
    scope.x = event.pageX - startX;
    element.css({
      top: scope.y + 'px',
      left: scope.x + 'px'
    });
  }

  function mouseup() {
    $document.off('mousemove', mousemove);
    $document.off('mouseup', mouseup);
  }
}

but that only works for a single event.

Angular's example uses the mousedown to add the mousemove and mouseup event listeners, and this stackoverflow answer uses triggerHandler-- which prevents bubbling/propagation.

right now i have (roughly):

describe('on mousedown it', function(){
  it('moves a thing', function(){
    expect(scope.x).toBe(0);
    element.triggerHandler({type: 'mousedown', pageX: 0, pageY:0});
    element.triggerHandler({type: 'mousemove', pageX:10, pageY:10);
    expect(scope.x).toBe(10);
  });
});

test is failing. scope.x is logging as 0. what do?

Upvotes: 7

Views: 3695

Answers (2)

adiinstack
adiinstack

Reputation: 96

You can test/assert for scope.x also , but do consider above answer by Chanthu - the way to compile directive with a scope.

Besides that ,the reason why your test fails is all events except mousedown are triggered on document unlike your test case depicts.

Try following snippet:

                       describe('on mousedown it', function(){
                        it('moves a thing', function(){
                         expect(scope.x).toBe(0);
                         element.triggerHandler({type: 'mousedown',           
                         pageX: 0, pageY:0});
                         document.triggerHandler({type: 'mousemove', 
                         pageX:10, pageY:10);
                         expect(scope.x).toBe(10);
                        });
                      });

Upvotes: 2

Chanthu
Chanthu

Reputation: 1794

Ok the way I look at this, in the example, the dragging code is in a directive. So, when looking at testing, because the directive is manipulating the position of the element that the directive is attached to, I would assert the changes in element position rather than asserting values of internal scope variables.

Given we have the directive called myDraggable which is applied like so <span my-draggable="">Drag Me</span>, when testing:

  1. Lets compile the directive.

    var scope = $rootScope.$new(); var elem = $compile('<span my-draggable="">Drag Me</span>')(scope);

  2. Then send mouse down event to compiled element

    elem.triggerHandler({type: 'mousedown', pageX: 0, pageY:0});

  3. After that, because the mouse move event is attached to the $document, lets send mouse mouse move event to $document

    $document.triggerHandler({type: 'mousemove', pageX: 10, pageY:20});

  4. And finally, let's assert the final position of the compiled element

    expect(elem.css('top')).toBe('20px') expect(elem.css('left')).toBe('10px')

And when we put it all together,

describe('on mousedown it', function(){
  beforeEach(module('dragModule'));

  it('moves a thing', inject(function($compile, $rootScope, $document){
    var scope = $rootScope.$new();
    var elem = $compile('<span my-draggable="">Drag Me</span>')(scope);
    $rootScope.$digest();

    elem.triggerHandler({type: 'mousedown', pageX: 0, pageY:0});
    $document.triggerHandler({type: 'mousemove', pageX: 10, pageY:20});

    expect(elem.css('top')).toBe('20px');
    expect(elem.css('left')).toBe('10px');
  }));
});

Here's official angular documentation on recommended way of testing a directive: https://docs.angularjs.org/guide/unit-testing#testing-directives

Here's the plunker that implements everything I just talked about: https://plnkr.co/edit/QgWiVlbNOKkhn6wkGxUK?p=preview

Upvotes: 4

Related Questions