testing/marionette/ChromeUtils.js

Wed, 31 Dec 2014 06:55:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:50 +0100
changeset 2
7e26c7da4463
permissions
-rw-r--r--

Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2

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

mercurial