Implement support for <markup:children/> elements, from initial import to showing the imported contents to the user, to final export back to the data document.
1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
14 * The Original Code is Pending Events Test Harness.
16 * The Initial Developer of the Original Code is
17 * Alexander J. Vincent <ajvincent@gmail.com>.
18 * Portions created by the Initial Developer are Copyright (C) 2010
19 * the Initial Developer. All Rights Reserved.
23 * Alternatively, the contents of this file may be used under the terms of
24 * either the GNU General Public License Version 2 or later (the "GPL"), or
25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 * in which case the provisions of the GPL or the LGPL are applicable instead
27 * of those above. If you wish to allow use of your version of this file only
28 * under the terms of either the GPL or the LGPL, and not to allow others to
29 * use your version of this file under the terms of the MPL, indicate your
30 * decision by deleting the provisions above and replace them with the notice
31 * and other provisions required by the GPL or the LGPL. If you do not delete
32 * the provisions above, a recipient may use your version of this file under
33 * the terms of any one of the MPL, the GPL or the LGPL.
35 * ***** END LICENSE BLOCK ***** */
38 This object exists to manage tests which depend on asynchronous events firing
39 before the test completes. For example, if you wish to test properties of a XBL
40 binding on an element, but the element hasn't been inserted into a live user
41 document, you would want to pause the test and allow the binding to attach. You
42 would also want to specify a "resume ordinary testing" point.
44 This test harness accepts test parts as individual functions. Add a test
45 function by calling PendingEventsTest.addTest(yourFunction). At all exit points
46 for a test, you should call PendingEventsTest.asyncRun(). To start the test
47 sequence, call PendingEventsTest.run().
49 To block one test function from running because you're waiting for a DOM event,
50 call PendingEventsTest.addEventLock. Tests will not proceed until the right
51 DOM event arrives. If the right DOM event does not arrive in the time you
52 specify, the test will fail.
54 To transfer local variables from one test function to another, use the
55 setPayload(), getPayload() and clearPayload() methods.
57 You can add functions which execute after the overall test script finishes
58 (with failure or success) using the executeAfterRun() method.
60 Finally, to abort a test run with a failure (and prevent other asynchronous test
61 functions from running), use the abortFail() method. Once this method is called,
62 the test script is effectively done. The abortFail() method will also trigger
63 for exceptions not caught in the test script.
66 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
67 SimpleTest.waitForExplicitFinish();
69 const PendingEventsTest = {
74 _postRunCallbacks: [],
76 _endTests: function() {
77 for each (var callback in this._postRunCallbacks)
87 window.onerror = gOldOnError;
91 * Prevent the test from proceeding until an event has been received.
93 * @param node The DOM node expecting an event.
94 * @param eventName The name of the event.
95 * @param capturing True if the event should be in the capturing phase.
96 * @param timeLimit The number of milliseconds to wait for the event. If not
97 * received in that time, the test has failed.
98 * @param filter (optional) A JS function which filters events passed to
99 * the event listener. The function takes the event as its
100 * first argument. If the function returns false, the lock
102 * @param subtest (optional) A custom test to run in handleEvent. The
103 * function takes the event as its first argument.
105 addEventLock: function(node, eventName, capturing, timeLimit, filter, subtest)
107 if (!(node instanceof C_i.nsIDOMNode) ||
108 (typeof eventName != "string") ||
109 (typeof capturing != "boolean") ||
110 (typeof timeLimit != "number") ||
111 (filter && (typeof filter != "function")) ||
112 (subtest && (typeof subtest != "function")))
114 throw new Components.Exception("Event lock argument is invalid",
115 Components.results.NS_ERROR_ILLEGAL_VALUE);
117 if (isNaN(timeLimit) ||
119 (timeLimit == Infinity))
121 throw new Components.Exception("timeLimit is an invalid value",
122 Components.results.NS_ERROR_ILLEGAL_VALUE);
128 if (PendingEventsTest._aborted)
130 PendingEventsTest.abortFail("Expected " + eventName + " event, timed out");
133 // nsIDOMEventListener
134 handleEvent: function(event)
136 if (PendingEventsTest._aborted)
139 // Does the event apply to this lock?
141 if (filter && !filter(event))
145 PendingEventsTest.abortFail("exception caught in lock filter: " + e);
149 window.clearTimeout(this._timer);
150 event.currentTarget.removeEventListener(eventName, this, capturing);
159 PendingEventsTest.abortFail("exception caught in subtest: " + e);
160 if (typeof e.stack == "string")
162 dump(e.stack + "\n\n");
167 var index = PendingEventsTest._locks.indexOf(this);
168 PendingEventsTest._locks.splice(index, 1);
169 PendingEventsTest.run();
174 XPCOMUtils.generateQI(["nsIDOMEventListener"])
177 PendingEventsTest._locks.push(lock);
178 lock._timer = window.setTimeout(function() {
181 node.addEventListener(eventName, lock, capturing);
185 * Add a test to the execution sequence.
187 addTest: function(aTest)
189 this._tests.push(aTest);
193 * Abort the test run and log a failure.
195 * @param msg The failure message to log.
197 abortFail: function(msg) {
198 this._aborted = true;
204 * Get an object which a previous test stored, after checking its name.
206 * @param nameCheck The name to match against the previous payload store.
208 * @returns The object the user cached.
210 getPayload: function(nameCheck)
214 throw new Components.Exception(
216 Components.results.NS_ERROR_NOT_INITIALIZED
220 if (nameCheck != this._payload.name)
222 throw new Components.Exception(
223 "Payload name didn't match: " + this._payload.name,
224 Components.results.NS_ERROR_UNEXPECTED
228 return this._payload.data;
232 * Store an object for a later test to pick up.
234 * @param name A value to confirm the right parties get the right payload.
235 * @param data The object to store.
237 setPayload: function(name, data)
241 throw new Components.Exception(
242 "We already have a payload!",
243 Components.results.NS_ERROR_ALREADY_INITIALIZED
254 * Clear the stored object, after checking its name.
256 * @param nameCheck The name to match against the previous payload store.
258 clearPayload: function(nameCheck)
262 throw new Components.Exception(
264 Components.results.NS_ERROR_NOT_INITIALIZED
268 if (nameCheck != this._payload.name)
270 throw new Components.Exception(
271 "Payload name didn't match: " + this._payload.name,
272 Components.results.NS_ERROR_UNEXPECTED
276 this._payload = null;
280 * Run the next test, if there are no locks and we haven't aborted.
282 run: function PendingEventsTest_run()
284 if ((this._locks.length > 0) || (this._aborted))
289 if (this._tests.length > 0)
291 var test = this._tests.shift();
304 * Run the next test asynchronously, so as to allow currently executing
305 * functions to exit cleanly (and not show up on the stack).
307 asyncRun: function() {
308 var delay = (arguments.length > 0) ? arguments[0] : 0;
309 if (isNaN(delay) || (delay < 0) || (delay == Infinity))
311 throw new Components.Exception(
312 "PendingEventsTest.asyncRun called with bad delay",
313 Components.results.NS_ERROR_ILLEGAL_VALUE
316 window.setTimeout("PendingEventsTest.run()", delay);
320 * Execute a function after the test run finishes (successfully or not).
322 executeAfterRun: function(callback)
324 if (typeof callback != "function")
325 throw new Components.Exception("executeAfterRun expects a function",
326 Components.results.NS_ERROR_ILLEGAL_VALUE);
327 this._postRunCallbacks.push(callback);