testing/marionette/ChromeUtils.js

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

mercurial