testing/mochitest/tests/SimpleTest/ChromeUtils.js

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:be1c63a75e1b
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 */
9
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);
14
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 }
36
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 }
58
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 }
75
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 }
94
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;
122
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 }
165
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;
188
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);
193
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 }
207
208 ds.startDragSession();
209
210 try {
211 // need to use real mouse action
212 aWindow.addEventListener("dragstart", trapDrag, true);
213 EventUtils.synthesizeMouseAtCenter(srcElement, { type: "mousedown" }, aWindow);
214
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);
221
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 }
231
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 }
237
238 EventUtils.synthesizeMouseAtCenter(destElement, { type: "mouseup" }, aDestWindow);
239
240 return dataTransfer.dropEffect;
241 } finally {
242 ds.endDragSession(true);
243 }
244 };
245
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 }
255
256 var ph = Components.classes["@mozilla.org/plugin/host;1"]
257 .getService(Components.interfaces.nsIPluginHost);
258 var tags = ph.getPluginTags();
259
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