1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/testing/mochitest/tests/SimpleTest/ChromeUtils.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,272 @@ 1.4 +/** 1.5 + * ChromeUtils.js is a set of mochitest utilities that are used to 1.6 + * synthesize events in the browser. These are only used by 1.7 + * mochitest-chrome and browser-chrome tests. Originally these functions were in 1.8 + * EventUtils.js, but when porting to specialPowers, we didn't want 1.9 + * to move unnecessary functions. 1.10 + * 1.11 + */ 1.12 + 1.13 +const EventUtils = {}; 1.14 +const scriptLoader = Components.classes["@mozilla.org/moz/jssubscript-loader;1"]. 1.15 + getService(Components.interfaces.mozIJSSubScriptLoader); 1.16 +scriptLoader.loadSubScript("chrome://mochikit/content/tests/SimpleTest/EventUtils.js", EventUtils); 1.17 + 1.18 +/** 1.19 + * Synthesize a query text content event. 1.20 + * 1.21 + * @param aOffset The character offset. 0 means the first character in the 1.22 + * selection root. 1.23 + * @param aLength The length of getting text. If the length is too long, 1.24 + * the extra length is ignored. 1.25 + * @param aWindow Optional (If null, current |window| will be used) 1.26 + * @return An nsIQueryContentEventResult object. If this failed, 1.27 + * the result might be null. 1.28 + */ 1.29 +function synthesizeQueryTextContent(aOffset, aLength, aWindow) 1.30 +{ 1.31 + var utils = _getDOMWindowUtils(aWindow); 1.32 + if (!utils) { 1.33 + return nullptr; 1.34 + } 1.35 + return utils.sendQueryContentEvent(utils.QUERY_TEXT_CONTENT, 1.36 + aOffset, aLength, 0, 0, 1.37 + QUERY_CONTENT_FLAG_USE_NATIVE_LINE_BREAK); 1.38 +} 1.39 + 1.40 +/** 1.41 + * Synthesize a query text rect event. 1.42 + * 1.43 + * @param aOffset The character offset. 0 means the first character in the 1.44 + * selection root. 1.45 + * @param aLength The length of the text. If the length is too long, 1.46 + * the extra length is ignored. 1.47 + * @param aWindow Optional (If null, current |window| will be used) 1.48 + * @return An nsIQueryContentEventResult object. If this failed, 1.49 + * the result might be null. 1.50 + */ 1.51 +function synthesizeQueryTextRect(aOffset, aLength, aWindow) 1.52 +{ 1.53 + var utils = _getDOMWindowUtils(aWindow); 1.54 + if (!utils) { 1.55 + return nullptr; 1.56 + } 1.57 + return utils.sendQueryContentEvent(utils.QUERY_TEXT_RECT, 1.58 + aOffset, aLength, 0, 0, 1.59 + QUERY_CONTENT_FLAG_USE_NATIVE_LINE_BREAK); 1.60 +} 1.61 + 1.62 +/** 1.63 + * Synthesize a query editor rect event. 1.64 + * 1.65 + * @param aWindow Optional (If null, current |window| will be used) 1.66 + * @return An nsIQueryContentEventResult object. If this failed, 1.67 + * the result might be null. 1.68 + */ 1.69 +function synthesizeQueryEditorRect(aWindow) 1.70 +{ 1.71 + var utils = _getDOMWindowUtils(aWindow); 1.72 + if (!utils) { 1.73 + return nullptr; 1.74 + } 1.75 + return utils.sendQueryContentEvent(utils.QUERY_EDITOR_RECT, 0, 0, 0, 0, 1.76 + QUERY_CONTENT_FLAG_USE_NATIVE_LINE_BREAK); 1.77 +} 1.78 + 1.79 +/** 1.80 + * Synthesize a character at point event. 1.81 + * 1.82 + * @param aX, aY The offset in the client area of the DOM window. 1.83 + * @param aWindow Optional (If null, current |window| will be used) 1.84 + * @return An nsIQueryContentEventResult object. If this failed, 1.85 + * the result might be null. 1.86 + */ 1.87 +function synthesizeCharAtPoint(aX, aY, aWindow) 1.88 +{ 1.89 + var utils = _getDOMWindowUtils(aWindow); 1.90 + if (!utils) { 1.91 + return nullptr; 1.92 + } 1.93 + return utils.sendQueryContentEvent(utils.QUERY_CHARACTER_AT_POINT, 1.94 + 0, 0, aX, aY, 1.95 + QUERY_CONTENT_FLAG_USE_NATIVE_LINE_BREAK); 1.96 +} 1.97 + 1.98 +/** 1.99 + * Emulate a dragstart event. 1.100 + * element - element to fire the dragstart event on 1.101 + * expectedDragData - the data you expect the data transfer to contain afterwards 1.102 + * This data is in the format: 1.103 + * [ [ {type: value, data: value, test: function}, ... ], ... ] 1.104 + * can be null 1.105 + * aWindow - optional; defaults to the current window object. 1.106 + * x - optional; initial x coordinate 1.107 + * y - optional; initial y coordinate 1.108 + * Returns null if data matches. 1.109 + * Returns the event.dataTransfer if data does not match 1.110 + * 1.111 + * eqTest is an optional function if comparison can't be done with x == y; 1.112 + * function (actualData, expectedData) {return boolean} 1.113 + * @param actualData from dataTransfer 1.114 + * @param expectedData from expectedDragData 1.115 + * see bug 462172 for example of use 1.116 + * 1.117 + */ 1.118 +function synthesizeDragStart(element, expectedDragData, aWindow, x, y) 1.119 +{ 1.120 + if (!aWindow) 1.121 + aWindow = window; 1.122 + x = x || 2; 1.123 + y = y || 2; 1.124 + const step = 9; 1.125 + 1.126 + var result = "trapDrag was not called"; 1.127 + var trapDrag = function(event) { 1.128 + try { 1.129 + var dataTransfer = event.dataTransfer; 1.130 + result = null; 1.131 + if (!dataTransfer) 1.132 + throw "no dataTransfer"; 1.133 + if (expectedDragData == null || 1.134 + dataTransfer.mozItemCount != expectedDragData.length) 1.135 + throw dataTransfer; 1.136 + for (var i = 0; i < dataTransfer.mozItemCount; i++) { 1.137 + var dtTypes = dataTransfer.mozTypesAt(i); 1.138 + if (dtTypes.length != expectedDragData[i].length) 1.139 + throw dataTransfer; 1.140 + for (var j = 0; j < dtTypes.length; j++) { 1.141 + if (dtTypes[j] != expectedDragData[i][j].type) 1.142 + throw dataTransfer; 1.143 + var dtData = dataTransfer.mozGetDataAt(dtTypes[j],i); 1.144 + if (expectedDragData[i][j].eqTest) { 1.145 + if (!expectedDragData[i][j].eqTest(dtData, expectedDragData[i][j].data)) 1.146 + throw dataTransfer; 1.147 + } 1.148 + else if (expectedDragData[i][j].data != dtData) 1.149 + throw dataTransfer; 1.150 + } 1.151 + } 1.152 + } catch(ex) { 1.153 + result = ex; 1.154 + } 1.155 + event.preventDefault(); 1.156 + event.stopPropagation(); 1.157 + } 1.158 + aWindow.addEventListener("dragstart", trapDrag, false); 1.159 + EventUtils.synthesizeMouse(element, x, y, { type: "mousedown" }, aWindow); 1.160 + x += step; y += step; 1.161 + EventUtils.synthesizeMouse(element, x, y, { type: "mousemove" }, aWindow); 1.162 + x += step; y += step; 1.163 + EventUtils.synthesizeMouse(element, x, y, { type: "mousemove" }, aWindow); 1.164 + aWindow.removeEventListener("dragstart", trapDrag, false); 1.165 + EventUtils.synthesizeMouse(element, x, y, { type: "mouseup" }, aWindow); 1.166 + return result; 1.167 +} 1.168 + 1.169 +/** 1.170 + * Emulate a drop by emulating a dragstart and firing events dragenter, dragover, and drop. 1.171 + * srcElement - the element to use to start the drag, usually the same as destElement 1.172 + * but if destElement isn't suitable to start a drag on pass a suitable 1.173 + * element for srcElement 1.174 + * destElement - the element to fire the dragover, dragleave and drop events 1.175 + * dragData - the data to supply for the data transfer 1.176 + * This data is in the format: 1.177 + * [ [ {type: value, data: value}, ...], ... ] 1.178 + * dropEffect - the drop effect to set during the dragstart event, or 'move' if null 1.179 + * aWindow - optional; defaults to the current window object. 1.180 + * aDestWindow - optional; defaults to aWindow. 1.181 + * Used when destElement is in a different window than srcElement. 1.182 + * 1.183 + * Returns the drop effect that was desired. 1.184 + */ 1.185 +function synthesizeDrop(srcElement, destElement, dragData, dropEffect, aWindow, aDestWindow) 1.186 +{ 1.187 + if (!aWindow) 1.188 + aWindow = window; 1.189 + if (!aDestWindow) 1.190 + aDestWindow = aWindow; 1.191 + 1.192 + var gWindowUtils = aDestWindow.QueryInterface(Components.interfaces.nsIInterfaceRequestor). 1.193 + getInterface(Components.interfaces.nsIDOMWindowUtils); 1.194 + var ds = Components.classes["@mozilla.org/widget/dragservice;1"]. 1.195 + getService(Components.interfaces.nsIDragService); 1.196 + 1.197 + var dataTransfer; 1.198 + var trapDrag = function(event) { 1.199 + dataTransfer = event.dataTransfer; 1.200 + for (var i = 0; i < dragData.length; i++) { 1.201 + var item = dragData[i]; 1.202 + for (var j = 0; j < item.length; j++) { 1.203 + dataTransfer.mozSetDataAt(item[j].type, item[j].data, i); 1.204 + } 1.205 + } 1.206 + dataTransfer.dropEffect = dropEffect || "move"; 1.207 + event.preventDefault(); 1.208 + event.stopPropagation(); 1.209 + } 1.210 + 1.211 + ds.startDragSession(); 1.212 + 1.213 + try { 1.214 + // need to use real mouse action 1.215 + aWindow.addEventListener("dragstart", trapDrag, true); 1.216 + EventUtils.synthesizeMouseAtCenter(srcElement, { type: "mousedown" }, aWindow); 1.217 + 1.218 + var rect = srcElement.getBoundingClientRect(); 1.219 + var x = rect.width / 2; 1.220 + var y = rect.height / 2; 1.221 + EventUtils.synthesizeMouse(srcElement, x, y, { type: "mousemove" }, aWindow); 1.222 + EventUtils.synthesizeMouse(srcElement, x+10, y+10, { type: "mousemove" }, aWindow); 1.223 + aWindow.removeEventListener("dragstart", trapDrag, true); 1.224 + 1.225 + event = aDestWindow.document.createEvent("DragEvents"); 1.226 + event.initDragEvent("dragenter", true, true, aDestWindow, 0, 0, 0, 0, 0, false, false, false, false, 0, null, dataTransfer); 1.227 + gWindowUtils.dispatchDOMEventViaPresShell(destElement, event, true); 1.228 + var event = aDestWindow.document.createEvent("DragEvents"); 1.229 + event.initDragEvent("dragover", true, true, aDestWindow, 0, 0, 0, 0, 0, false, false, false, false, 0, null, dataTransfer); 1.230 + if (gWindowUtils.dispatchDOMEventViaPresShell(destElement, event, true)) { 1.231 + EventUtils.synthesizeMouseAtCenter(destElement, { type: "mouseup" }, aDestWindow); 1.232 + return "none"; 1.233 + } 1.234 + 1.235 + if (dataTransfer.dropEffect != "none") { 1.236 + event = aDestWindow.document.createEvent("DragEvents"); 1.237 + event.initDragEvent("drop", true, true, aDestWindow, 0, 0, 0, 0, 0, false, false, false, false, 0, null, dataTransfer); 1.238 + gWindowUtils.dispatchDOMEventViaPresShell(destElement, event, true); 1.239 + } 1.240 + 1.241 + EventUtils.synthesizeMouseAtCenter(destElement, { type: "mouseup" }, aDestWindow); 1.242 + 1.243 + return dataTransfer.dropEffect; 1.244 + } finally { 1.245 + ds.endDragSession(true); 1.246 + } 1.247 +}; 1.248 + 1.249 +var PluginUtils = 1.250 +{ 1.251 + withTestPlugin : function(callback) 1.252 + { 1.253 + if (typeof Components == "undefined") 1.254 + { 1.255 + todo(false, "Not a Mozilla-based browser"); 1.256 + return false; 1.257 + } 1.258 + 1.259 + var ph = Components.classes["@mozilla.org/plugin/host;1"] 1.260 + .getService(Components.interfaces.nsIPluginHost); 1.261 + var tags = ph.getPluginTags(); 1.262 + 1.263 + // Find the test plugin 1.264 + for (var i = 0; i < tags.length; i++) 1.265 + { 1.266 + if (tags[i].name == "Test Plug-in") 1.267 + { 1.268 + callback(tags[i]); 1.269 + return true; 1.270 + } 1.271 + } 1.272 + todo(false, "Need a test plugin on this platform"); 1.273 + return false; 1.274 + } 1.275 +};