Bug 1501761 - Fix EventUtils.synthesizePlainDragAndDrop to enable simulating tab detaching. r=florian
authorFelipe Gomes <felipc@gmail.com>
Wed, 24 Oct 2018 17:59:54 -0300
changeset 491140 0a2a9b94714f0f16a3af50a444e7555ddf6a4e38
parent 491139 eff78d899e015488e1e384c24b249c2daadc990a
child 491141 bcc643fef1568b22e72e51501608ac4498c6d0be
push id247
push userfmarier@mozilla.com
push dateSat, 27 Oct 2018 01:06:44 +0000
reviewersflorian
bugs1501761
milestone65.0a1
Bug 1501761 - Fix EventUtils.synthesizePlainDragAndDrop to enable simulating tab detaching. r=florian This fixes several problems with this function: - the parameters destX and destY were advertised but were actually unused - added support for dropping on an invalid drop target (by passing destElement = null) - implements the dragend event - stale documentation mentioned mouseup event
testing/mochitest/tests/SimpleTest/EventUtils.js
--- a/testing/mochitest/tests/SimpleTest/EventUtils.js
+++ b/testing/mochitest/tests/SimpleTest/EventUtils.js
@@ -2381,47 +2381,48 @@ function synthesizeDrop(aSrcElement, aDe
                                        aDestWindow, aDragEvent);
   } finally {
     ds.endDragSession(true, _parseModifiers(aDragEvent));
   }
 }
 
 /**
  * Emulate a drag and drop by emulating a dragstart by mousedown and mousemove,
- * and firing events dragenter, dragover, drop, and mouseup.
+ * and firing events dragenter, dragover, drop, and dragend.
  * This does not modify dataTransfer and tries to emulate the plain drag and
  * drop as much as possible, compared to synthesizeDrop.
  *
  * @param aParams
  *        {
  *          srcElement:   The element to start dragging
- *          destElement:  The element to drop on
+ *          destElement:  The element to drop on. Pass null to emulate
+ *                        a drop on an invalid target.
  *          srcX:         The initial x coordinate inside srcElement
  *          srcY:         The initial y coordinate inside srcElement
  *          stepX:        The x-axis step for mousemove inside srcElement
  *          stepY:        The y-axis step for mousemove inside srcElement
- *          destX:        The x coordinate inside destElement
- *          destY:        The x coordinate inside destElement
+ *          finalX:       The final x coordinate inside srcElement
+ *          finalY:       The final x coordinate inside srcElement
  *          srcWindow:    The window for dispatching event on srcElement,
  *                        defaults to the current window object
  *          destWindow:   The window for dispatching event on destElement,
  *                        defaults to the current window object
  *        }
  */
 async function synthesizePlainDragAndDrop(aParams)
 {
   let {
     srcElement,
     destElement,
     srcX = 2,
     srcY = 2,
     stepX = 9,
     stepY = 9,
-    destX = 2,
-    destY = 2,
+    finalX = srcX + stepX * 2,
+    finalY = srcY + stepY * 2,
     srcWindow = window,
     destWindow = window,
   } = aParams;
 
   const ds = _EU_Cc["@mozilla.org/widget/dragservice;1"]
         .getService(_EU_Ci.nsIDragService);
   ds.startDragSession();
 
@@ -2446,25 +2447,36 @@ async function synthesizePlainDragAndDro
     synthesizeMouse(srcElement, srcX, srcY, { type: "mousemove" }, srcWindow);
 
     await new Promise(r => setTimeout(r, 0));
 
     srcElement.removeEventListener("dragstart", trapDrag, true);
 
     await new Promise(r => setTimeout(r, 0));
 
-    let event = createDragEventObject("dragover", destElement, destWindow,
-                                      dataTransfer, {});
-    sendDragEvent(event, destElement, destWindow);
+    let event;
+    if (destElement) {
+      // dragover and drop are only fired to a valid drop target. If the
+      // destElement parameter is null, this function is being used to
+      // simulate a drag'n'drop over an invalid drop target.
+      event = createDragEventObject("dragover", destElement, destWindow,
+                                        dataTransfer, {});
+      sendDragEvent(event, destElement, destWindow);
 
-    await new Promise(r => setTimeout(r, 0));
+      await new Promise(r => setTimeout(r, 0));
 
-    event = createDragEventObject("drop", destElement, destWindow,
-                                  dataTransfer, {});
-    sendDragEvent(event, destElement, destWindow);
+      event = createDragEventObject("drop", destElement, destWindow,
+                                    dataTransfer, {});
+      sendDragEvent(event, destElement, destWindow);
+    }
+
+    // dragend is fired, by definition, on the srcElement
+    event = createDragEventObject("dragend", srcElement, srcWindow,
+                                  dataTransfer, {clientX: finalX, clientY: finalY});
+    sendDragEvent(event, srcElement, srcWindow);
 
     await new Promise(r => setTimeout(r, 0));
 
   } finally {
     ds.endDragSession(true, 0);
   }
 }