testing/mochitest/tests/SimpleTest/ChromeUtils.js

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /**
     2  * ChromeUtils.js is a set of mochitest utilities that are used to 
     3  * synthesize events in the browser.  These are only used by 
     4  * mochitest-chrome and browser-chrome tests.  Originally these functions were in 
     5  * EventUtils.js, but when porting to specialPowers, we didn't want
     6  * to move unnecessary functions.
     7  *
     8  */
    10 const EventUtils = {};
    11 const scriptLoader = Components.classes["@mozilla.org/moz/jssubscript-loader;1"].
    12                    getService(Components.interfaces.mozIJSSubScriptLoader);
    13 scriptLoader.loadSubScript("chrome://mochikit/content/tests/SimpleTest/EventUtils.js", EventUtils);
    15 /**
    16  * Synthesize a query text content event.
    17  *
    18  * @param aOffset  The character offset.  0 means the first character in the
    19  *                 selection root.
    20  * @param aLength  The length of getting text.  If the length is too long,
    21  *                 the extra length is ignored.
    22  * @param aWindow  Optional (If null, current |window| will be used)
    23  * @return         An nsIQueryContentEventResult object.  If this failed,
    24  *                 the result might be null.
    25  */
    26 function synthesizeQueryTextContent(aOffset, aLength, aWindow)
    27 {
    28   var utils = _getDOMWindowUtils(aWindow);
    29   if (!utils) {
    30     return nullptr;
    31   }
    32   return utils.sendQueryContentEvent(utils.QUERY_TEXT_CONTENT,
    33                                      aOffset, aLength, 0, 0,
    34                                      QUERY_CONTENT_FLAG_USE_NATIVE_LINE_BREAK);
    35 }
    37 /**
    38  * Synthesize a query text rect event.
    39  *
    40  * @param aOffset  The character offset.  0 means the first character in the
    41  *                 selection root.
    42  * @param aLength  The length of the text.  If the length is too long,
    43  *                 the extra length is ignored.
    44  * @param aWindow  Optional (If null, current |window| will be used)
    45  * @return         An nsIQueryContentEventResult object.  If this failed,
    46  *                 the result might be null.
    47  */
    48 function synthesizeQueryTextRect(aOffset, aLength, aWindow)
    49 {
    50   var utils = _getDOMWindowUtils(aWindow);
    51   if (!utils) {
    52     return nullptr;
    53   }
    54   return utils.sendQueryContentEvent(utils.QUERY_TEXT_RECT,
    55                                      aOffset, aLength, 0, 0,
    56                                      QUERY_CONTENT_FLAG_USE_NATIVE_LINE_BREAK);
    57 }
    59 /**
    60  * Synthesize a query editor rect event.
    61  *
    62  * @param aWindow  Optional (If null, current |window| will be used)
    63  * @return         An nsIQueryContentEventResult object.  If this failed,
    64  *                 the result might be null.
    65  */
    66 function synthesizeQueryEditorRect(aWindow)
    67 {
    68   var utils = _getDOMWindowUtils(aWindow);
    69   if (!utils) {
    70     return nullptr;
    71   }
    72   return utils.sendQueryContentEvent(utils.QUERY_EDITOR_RECT, 0, 0, 0, 0,
    73                                      QUERY_CONTENT_FLAG_USE_NATIVE_LINE_BREAK);
    74 }
    76 /**
    77  * Synthesize a character at point event.
    78  *
    79  * @param aX, aY   The offset in the client area of the DOM window.
    80  * @param aWindow  Optional (If null, current |window| will be used)
    81  * @return         An nsIQueryContentEventResult object.  If this failed,
    82  *                 the result might be null.
    83  */
    84 function synthesizeCharAtPoint(aX, aY, aWindow)
    85 {
    86   var utils = _getDOMWindowUtils(aWindow);
    87   if (!utils) {
    88     return nullptr;
    89   }
    90   return utils.sendQueryContentEvent(utils.QUERY_CHARACTER_AT_POINT,
    91                                      0, 0, aX, aY,
    92                                      QUERY_CONTENT_FLAG_USE_NATIVE_LINE_BREAK);
    93 }
    95 /**
    96  * Emulate a dragstart event.
    97  *  element - element to fire the dragstart event on
    98  *  expectedDragData - the data you expect the data transfer to contain afterwards
    99  *                      This data is in the format:
   100  *                         [ [ {type: value, data: value, test: function}, ... ], ... ]
   101  *                     can be null
   102  *  aWindow - optional; defaults to the current window object.
   103  *  x - optional; initial x coordinate
   104  *  y - optional; initial y coordinate
   105  * Returns null if data matches.
   106  * Returns the event.dataTransfer if data does not match
   107  *
   108  * eqTest is an optional function if comparison can't be done with x == y;
   109  *   function (actualData, expectedData) {return boolean}
   110  *   @param actualData from dataTransfer
   111  *   @param expectedData from expectedDragData
   112  * see bug 462172 for example of use
   113  *
   114  */
   115 function synthesizeDragStart(element, expectedDragData, aWindow, x, y)
   116 {
   117   if (!aWindow)
   118     aWindow = window;
   119   x = x || 2;
   120   y = y || 2;
   121   const step = 9;
   123   var result = "trapDrag was not called";
   124   var trapDrag = function(event) {
   125     try {
   126       var dataTransfer = event.dataTransfer;
   127       result = null;
   128       if (!dataTransfer)
   129         throw "no dataTransfer";
   130       if (expectedDragData == null ||
   131           dataTransfer.mozItemCount != expectedDragData.length)
   132         throw dataTransfer;
   133       for (var i = 0; i < dataTransfer.mozItemCount; i++) {
   134         var dtTypes = dataTransfer.mozTypesAt(i);
   135         if (dtTypes.length != expectedDragData[i].length)
   136           throw dataTransfer;
   137         for (var j = 0; j < dtTypes.length; j++) {
   138           if (dtTypes[j] != expectedDragData[i][j].type)
   139             throw dataTransfer;
   140           var dtData = dataTransfer.mozGetDataAt(dtTypes[j],i);
   141           if (expectedDragData[i][j].eqTest) {
   142             if (!expectedDragData[i][j].eqTest(dtData, expectedDragData[i][j].data))
   143               throw dataTransfer;
   144           }
   145           else if (expectedDragData[i][j].data != dtData)
   146             throw dataTransfer;
   147         }
   148       }
   149     } catch(ex) {
   150       result = ex;
   151     }
   152     event.preventDefault();
   153     event.stopPropagation();
   154   }
   155   aWindow.addEventListener("dragstart", trapDrag, false);
   156   EventUtils.synthesizeMouse(element, x, y, { type: "mousedown" }, aWindow);
   157   x += step; y += step;
   158   EventUtils.synthesizeMouse(element, x, y, { type: "mousemove" }, aWindow);
   159   x += step; y += step;
   160   EventUtils.synthesizeMouse(element, x, y, { type: "mousemove" }, aWindow);
   161   aWindow.removeEventListener("dragstart", trapDrag, false);
   162   EventUtils.synthesizeMouse(element, x, y, { type: "mouseup" }, aWindow);
   163   return result;
   164 }
   166 /**
   167  * Emulate a drop by emulating a dragstart and firing events dragenter, dragover, and drop.
   168  *  srcElement - the element to use to start the drag, usually the same as destElement
   169  *               but if destElement isn't suitable to start a drag on pass a suitable
   170  *               element for srcElement
   171  *  destElement - the element to fire the dragover, dragleave and drop events
   172  *  dragData - the data to supply for the data transfer
   173  *                     This data is in the format:
   174  *                       [ [ {type: value, data: value}, ...], ... ]
   175  *  dropEffect - the drop effect to set during the dragstart event, or 'move' if null
   176  *  aWindow - optional; defaults to the current window object.
   177  *  aDestWindow - optional; defaults to aWindow.
   178  *                Used when destElement is in a different window than srcElement.
   179  *
   180  * Returns the drop effect that was desired.
   181  */
   182 function synthesizeDrop(srcElement, destElement, dragData, dropEffect, aWindow, aDestWindow)
   183 {
   184   if (!aWindow)
   185     aWindow = window;
   186   if (!aDestWindow)
   187     aDestWindow = aWindow;
   189   var gWindowUtils = aDestWindow.QueryInterface(Components.interfaces.nsIInterfaceRequestor).
   190                                  getInterface(Components.interfaces.nsIDOMWindowUtils);
   191   var ds = Components.classes["@mozilla.org/widget/dragservice;1"].
   192            getService(Components.interfaces.nsIDragService);
   194   var dataTransfer;
   195   var trapDrag = function(event) {
   196     dataTransfer = event.dataTransfer;
   197     for (var i = 0; i < dragData.length; i++) {
   198       var item = dragData[i];
   199       for (var j = 0; j < item.length; j++) {
   200         dataTransfer.mozSetDataAt(item[j].type, item[j].data, i);
   201       }
   202     }
   203     dataTransfer.dropEffect = dropEffect || "move";
   204     event.preventDefault();
   205     event.stopPropagation();
   206   }
   208   ds.startDragSession();
   210   try {
   211     // need to use real mouse action
   212     aWindow.addEventListener("dragstart", trapDrag, true);
   213     EventUtils.synthesizeMouseAtCenter(srcElement, { type: "mousedown" }, aWindow);
   215     var rect = srcElement.getBoundingClientRect();
   216     var x = rect.width / 2;
   217     var y = rect.height / 2;
   218     EventUtils.synthesizeMouse(srcElement, x, y, { type: "mousemove" }, aWindow);
   219     EventUtils.synthesizeMouse(srcElement, x+10, y+10, { type: "mousemove" }, aWindow);
   220     aWindow.removeEventListener("dragstart", trapDrag, true);
   222     event = aDestWindow.document.createEvent("DragEvents");
   223     event.initDragEvent("dragenter", true, true, aDestWindow, 0, 0, 0, 0, 0, false, false, false, false, 0, null, dataTransfer);
   224     gWindowUtils.dispatchDOMEventViaPresShell(destElement, event, true);
   225     var event = aDestWindow.document.createEvent("DragEvents");
   226     event.initDragEvent("dragover", true, true, aDestWindow, 0, 0, 0, 0, 0, false, false, false, false, 0, null, dataTransfer);
   227     if (gWindowUtils.dispatchDOMEventViaPresShell(destElement, event, true)) {
   228       EventUtils.synthesizeMouseAtCenter(destElement, { type: "mouseup" }, aDestWindow);
   229       return "none";
   230     }
   232     if (dataTransfer.dropEffect != "none") {
   233       event = aDestWindow.document.createEvent("DragEvents");
   234       event.initDragEvent("drop", true, true, aDestWindow, 0, 0, 0, 0, 0, false, false, false, false, 0, null, dataTransfer);
   235       gWindowUtils.dispatchDOMEventViaPresShell(destElement, event, true);
   236     }
   238     EventUtils.synthesizeMouseAtCenter(destElement, { type: "mouseup" }, aDestWindow);
   240     return dataTransfer.dropEffect;
   241   } finally {
   242     ds.endDragSession(true);
   243   }
   244 };
   246 var PluginUtils =
   247 {
   248   withTestPlugin : function(callback)
   249   {
   250     if (typeof Components == "undefined")
   251     {
   252       todo(false, "Not a Mozilla-based browser");
   253       return false;
   254     }
   256     var ph = Components.classes["@mozilla.org/plugin/host;1"]
   257                        .getService(Components.interfaces.nsIPluginHost);
   258     var tags = ph.getPluginTags();
   260     // Find the test plugin
   261     for (var i = 0; i < tags.length; i++)
   262     {
   263       if (tags[i].name == "Test Plug-in")
   264       {
   265         callback(tags[i]);
   266         return true;
   267       }
   268     }
   269     todo(false, "Need a test plugin on this platform");
   270     return false;
   271   }
   272 };

mercurial