Bug 1357590 - Test drag and drop with mouse actions; r=ato
authorMaja Frydrychowicz <mjzffr@gmail.com>
Tue, 18 Apr 2017 19:07:04 -0400
changeset 353850 8fd376fc906071d384783e5c9bd228ba640f7483
parent 353849 4750ab2b56f22fb0ead804b0b159585322590d72
child 353851 ccf614bcd29637ea73c3980a26862ddd8f0ce0ed
push id41080
push usermjzffr@gmail.com
push dateWed, 19 Apr 2017 13:57:49 +0000
treeherderautoland@8fd376fc9060 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersato
bugs1357590
milestone55.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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>