Bug 1357590 - Test drag and drop with mouse actions; r?ato draft
authorMaja Frydrychowicz <mjzffr@gmail.com>
Tue, 18 Apr 2017 19:07:04 -0400
changeset 565073 2d29c276f578bf844c4015ed75b78134b2ac1cb5
parent 565072 6acc59f9c74f8aa4fc781652ff9b193955727bdc
child 624915 896bf9ca4fddcf6ad3d3866bd496d16c61392391
push id54785
push userbmo:mjzffr@gmail.com
push dateWed, 19 Apr 2017 13:55:52 +0000
reviewersato
bugs1357590
milestone55.0a1
Bug 1357590 - Test drag and drop with mouse actions; r?ato MozReview-Commit-ID: 6vRHj7pRGdh
testing/web-platform/meta/MANIFEST.json
testing/web-platform/tests/webdriver/actions/mouse.py
testing/web-platform/tests/webdriver/actions/support/test_actions_wdspec.html
--- a/testing/web-platform/meta/MANIFEST.json
+++ b/testing/web-platform/meta/MANIFEST.json
@@ -181336,17 +181336,17 @@
    "ace7008a593a32ca016685aaa85bda9b4c4bd8c8",
    "testharness"
   ],
   "html/webappapis/idle-callbacks/callback-invoked.html": [
    "e7cf5a399d92f1fcb98f6ebb1ed3283d60d2bfe2",
    "testharness"
   ],
   "html/webappapis/idle-callbacks/callback-multiple-calls.html": [
-   "6375309c43a1e7c9fafdc95f01fcccb4c92f8afc",
+   "af6e6a65fda2486ac8669340988b1d57a178e77a",
    "testharness"
   ],
   "html/webappapis/idle-callbacks/callback-removed-frame.html": [
    "ff034276659407d2dea91d2b0ed0e5919b875904",
    "testharness"
   ],
   "html/webappapis/idle-callbacks/callback-suspended.html": [
    "f3f9eeda9e2d47825c77eaf278be6e976a8e1715",
@@ -208156,17 +208156,17 @@
    "78b6434a88021b7f56e5a7bf3e858fc9558a7c19",
    "wdspec"
   ],
   "webdriver/actions/key.py": [
    "918bcadf034657dfcb679fd92c8a11efe34bfedf",
    "wdspec"
   ],
   "webdriver/actions/mouse.py": [
-   "86b27e994042b37b4889175a10a02c30a24d3c7e",
+   "823e2b1e5ba200487d0598eecbb051f73b5ea69f",
    "wdspec"
   ],
   "webdriver/actions/sequence.py": [
    "d80f382863e52ff223db735a2a551197e570774f",
    "wdspec"
   ],
   "webdriver/actions/special_keys.py": [
    "b2d6c2fa8852c6299b6bd214f67007efebe3029a",
@@ -208180,17 +208180,17 @@
    "636991372c21e52b623ed4ada9dfb675dd7f7e14",
    "support"
   ],
   "webdriver/actions/support/refine.py": [
    "0d244bffe67ef57be68aad99f1cbc7440ff80e27",
    "support"
   ],
   "webdriver/actions/support/test_actions_wdspec.html": [
-   "ccd55308840f1b7ab6e9c56b7123b9ac370f0d25",
+   "c56cc117512bf9a5b6378dcead8e2640493d23a4",
    "support"
   ],
   "webdriver/conftest.py": [
    "39ba7649c437b50bb97d766561e4bd5a110f6459",
    "wdspec"
   ],
   "webdriver/contexts.py": [
    "302a1a0cb246aef74f2c1d961a210d9de7e366c5",
--- a/testing/web-platform/tests/webdriver/actions/mouse.py
+++ b/testing/web-platform/tests/webdriver/actions/mouse.py
@@ -1,23 +1,36 @@
+import pytest
 import urllib
 
 from support.refine import get_events, filter_dict
 
 
 # TODO use support.inline module once available from upstream
 def inline(doc):
     return "data:text/html;charset=utf-8,%s" % urllib.quote(doc)
 
 
 def link_doc(dest):
     content = "<a href=\"{}\" id=\"link\">destination</a>".format(dest)
     return inline(content)
 
 
+def get_center(rect):
+    return {
+        "x": rect["width"] / 2 + rect["x"],
+        "y": rect["height"] / 2 + rect["y"],
+    }
+
+
+# TODO use pytest.approx once we upgrade to pytest > 3.0
+def approx(n, m, tolerance=1):
+    return abs(n - m) < tolerance
+
+
 def test_click_at_coordinates(session, test_actions_page, mouse_chain):
     div_point = {
         "x": 82,
         "y": 187,
     }
     mouse_chain \
         .pointer_move(div_point["x"], div_point["y"], duration=1000) \
         .click() \
@@ -38,29 +51,26 @@ def test_click_at_coordinates(session, t
         {"type": "click", "buttons": 0},
     ]
     filtered_events = [filter_dict(e, expected[0]) for e in events]
     assert expected == filtered_events[1:]
 
 
 def test_click_element_center(session, test_actions_page, mouse_chain):
     outer = session.find.css("#outer", all=False)
-    outer_rect = outer.rect
-    center_x = outer_rect["width"] / 2 + outer_rect["x"]
-    center_y = outer_rect["height"] / 2 + outer_rect["y"]
+    center = get_center(outer.rect)
     mouse_chain.click(element=outer).perform()
     events = get_events(session)
     assert len(events) == 4
     event_types = [e["type"] for e in events]
     assert ["mousemove", "mousedown", "mouseup", "click"] == event_types
     for e in events:
         if e["type"] != "mousemove":
-            # TODO use pytest.approx once we upgrade to pytest > 3.0
-            assert abs(e["pageX"] - center_x) < 1
-            assert abs(e["pageY"] - center_y) < 1
+            assert approx(e["pageX"], center["x"])
+            assert approx(e["pageY"], center["y"])
             assert e["target"] == "outer"
 
 
 def test_click_navigation(session, url):
     destination = url("/webdriver/actions/support/test_actions_wdspec.html")
     start = link_doc(destination)
 
     def click(link):
@@ -70,8 +80,34 @@ def test_click_navigation(session, url):
 
     session.url = start
     click(session.find.css("#link", all=False))
     assert session.url == destination
     # repeat steps to check behaviour after document unload
     session.url = start
     click(session.find.css("#link", all=False))
     assert session.url == destination
+
+
+@pytest.mark.parametrize("drag_duration", [0, 300, 800])
+@pytest.mark.parametrize("dx, dy", [(20, 0), (0, 15), (10, 15)])
+def test_drag_and_drop(session, test_actions_page, mouse_chain, dx, dy, drag_duration):
+    drag_target = session.find.css("#dragTarget", all=False)
+    initial_rect = drag_target.rect
+    initial_center = get_center(initial_rect)
+    # Conclude chain with extra move to allow time for last queued
+    # coordinate-update of drag_target and to test that drag_target is "dropped".
+    mouse_chain \
+        .pointer_move(0, 0, origin=drag_target) \
+        .pointer_down() \
+        .pointer_move(dx, dy, duration=drag_duration, origin="pointer") \
+        .pointer_up() \
+        .pointer_move(80, 50, duration=100, origin="pointer") \
+        .perform()
+    # mouseup that ends the drag is at the expected destination
+    e = get_events(session)[1]
+    assert e["type"] == "mouseup"
+    assert approx(e["pageX"], initial_center["x"] + dx)
+    assert approx(e["pageY"], initial_center["y"] + dy)
+    # check resulting location of the dragged element
+    final_rect = drag_target.rect
+    assert initial_rect["x"] + dx == final_rect["x"]
+    assert initial_rect["y"] + dy == final_rect["y"]
--- a/testing/web-platform/tests/webdriver/actions/support/test_actions_wdspec.html
+++ b/testing/web-platform/tests/webdriver/actions/support/test_actions_wdspec.html
@@ -1,23 +1,24 @@
 <!doctype html>
 <meta charset=utf-8>
 <head>
     <title>Test Actions</title>
     <style>
       div { padding:0px; margin: 0px; }
+      #trackPointer { position: fixed; }
       #resultContainer { width: 600px; height: 60px; }
-      #outer { width: 100px; height: 50px; background-color: #ccc; }
-      #trackPointer {
-        width: 5px;
-        height: 5px;
-        border: solid 1px red;
-        position: fixed; }
+      .area { width: 100px; height: 50px; background-color: #ccc; }
+      .block { width: 5px; height: 5px; border: solid 1px red; }
+      #dragArea { position: relative; }
+      #dragTarget { position: absolute; top:22px; left:47px;}
     </style>
     <script>
+        "use strict";
+        var els = {};
         var allEvents = {events: []};
         function displayMessage(message) {
             document.getElementById("events").innerHTML = "<p>" + message + "</p>";
         }
 
         function appendMessage(message) {
             document.getElementById("events").innerHTML += "<p>" + message + "</p>";
         }
@@ -85,48 +86,85 @@
           window.removeEventListener("mousemove", recordFirstPointerMove);
         }
 
         function resetEvents() {
             allEvents.events.length = 0;
             displayMessage("");
         }
 
+        function drop(moveHandler) {
+          return function (event) {
+            els.dragArea.removeEventListener("mousemove", moveHandler);
+            els.dragTarget.style.backgroundColor = "yellow";
+            els.dragTarget.addEventListener("mousedown", grab);
+            recordPointerEvent(event);
+          };
+        }
+
+        function move(el, offsetX, offsetY, timeout) {
+          return (event) => {
+            setTimeout(() => {
+              el.style.top = event.clientY + offsetY + "px";
+              el.style.left = event.clientX + offsetX + "px";
+            }, timeout);
+          };
+        }
+
+        function grab(event) {
+          event.target.style.backgroundColor = "red";
+          let boxRect = event.target.getBoundingClientRect();
+          let areaRect = event.target.parentElement.getBoundingClientRect();
+          let moveHandler = move(
+              event.target,
+              // coordinates of dragTarget must be relative to dragArea such that
+              // dragTarget remains under the pointer
+              -(areaRect.left + (event.clientX - boxRect.left)),
+              -(areaRect.top + (event.clientY - boxRect.top)),
+              20);
+          els.dragArea.addEventListener("mousemove", moveHandler);
+          els.dragArea.addEventListener("mouseup", drop(moveHandler), {once: true});
+        }
+
         document.addEventListener("DOMContentLoaded", () => {
           var keyReporter = document.getElementById("keys");
           ["keyup", "keypress", "keydown"].forEach((e) => {
             keyReporter.addEventListener(e, recordKeyboardEvent);
           });
           var outer = document.getElementById("outer");
           ["click", "dblclick", "mousedown",
               "mouseup", "contextmenu"].forEach((e) => {
             outer.addEventListener(e, recordPointerEvent);
           });
-          window.addEventListener("mousemove", recordFirstPointerMove);
+          window.addEventListener("mousemove", recordPointerEvent, {once: true});
           //visual cue for mousemove
           var pointer = document.getElementById("trackPointer");
-          window.addEventListener("mousemove", (e) => {
-            setTimeout(() => {
-              let offset = 15;
-              pointer.style.top = e.pageY + offset + "px";
-              pointer.style.left = e.pageX + offset + "px";
-            }, 30);
-          });
+          window.addEventListener("mousemove", move(pointer, 15, 15, 30));
+          // drag and drop
+          els.dragArea = document.getElementById("dragArea");
+          els.dragTarget = document.getElementById("dragTarget");
+          els.dragTarget.addEventListener("mousedown", grab, {once: true});
         });
     </script>
 </head>
 <body>
-  <div id="trackPointer"></div>
+  <div id="trackPointer" class="block"></div>
   <div>
     <h2>KeyReporter</h2>
     <input type="text" id="keys" size="80">
   </div>
   <div>
     <h2>ClickReporter</h2>
-    <div id="outer">
+    <div id="outer" class="area">
+    </div>
+  </div>
+  <div>
+    <h2>DragReporter</h2>
+    <div id="dragArea" class="area">
+      <div id="dragTarget" class="block"></div>
     </div>
   </div>
   <div id="resultContainer">
     <h2>Events</h2>
     <div id="events"></div>
   </div>
 </body>
 </html>