|
1 /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* vim:set ts=2 sw=2 sts=2 et: */ |
|
3 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
4 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
6 |
|
7 /** |
|
8 * Tests the sanitize dialog (a.k.a. the clear recent history dialog). |
|
9 * See bug 480169. |
|
10 * |
|
11 * The purpose of this test is not to fully flex the sanitize timespan code; |
|
12 * browser/base/content/test/general/browser_sanitize-timespans.js does that. This |
|
13 * test checks the UI of the dialog and makes sure it's correctly connected to |
|
14 * the sanitize timespan code. |
|
15 * |
|
16 * Some of this code, especially the history creation parts, was taken from |
|
17 * browser/base/content/test/general/browser_sanitize-timespans.js. |
|
18 */ |
|
19 |
|
20 Cc["@mozilla.org/moz/jssubscript-loader;1"]. |
|
21 getService(Ci.mozIJSSubScriptLoader). |
|
22 loadSubScript("chrome://browser/content/sanitize.js"); |
|
23 |
|
24 const dm = Cc["@mozilla.org/download-manager;1"]. |
|
25 getService(Ci.nsIDownloadManager); |
|
26 const formhist = Cc["@mozilla.org/satchel/form-history;1"]. |
|
27 getService(Ci.nsIFormHistory2); |
|
28 |
|
29 // Add tests here. Each is a function that's called by doNextTest(). |
|
30 var gAllTests = [ |
|
31 |
|
32 /** |
|
33 * Moves the grippy around, makes sure it works OK. |
|
34 */ |
|
35 function () { |
|
36 // Add history (within the past hour) to get some rows in the tree. |
|
37 let uris = []; |
|
38 let places = []; |
|
39 let pURI; |
|
40 for (let i = 0; i < 30; i++) { |
|
41 pURI = makeURI("http://" + i + "-minutes-ago.com/"); |
|
42 places.push({uri: pURI, visitDate: visitTimeForMinutesAgo(i)}); |
|
43 uris.push(pURI); |
|
44 } |
|
45 |
|
46 addVisits(places, function() { |
|
47 // Open the dialog and do our tests. |
|
48 openWindow(function (aWin) { |
|
49 let wh = new WindowHelper(aWin); |
|
50 wh.selectDuration(Sanitizer.TIMESPAN_HOUR); |
|
51 wh.checkGrippy("Grippy should be at last row after selecting HOUR " + |
|
52 "duration", |
|
53 wh.getRowCount() - 1); |
|
54 |
|
55 // Move the grippy around. |
|
56 let row = wh.getGrippyRow(); |
|
57 while (row !== 0) { |
|
58 row--; |
|
59 wh.moveGrippyBy(-1); |
|
60 wh.checkGrippy("Grippy should be moved up one row", row); |
|
61 } |
|
62 wh.moveGrippyBy(-1); |
|
63 wh.checkGrippy("Grippy should remain at first row after trying to move " + |
|
64 "it up", |
|
65 0); |
|
66 while (row !== wh.getRowCount() - 1) { |
|
67 row++; |
|
68 wh.moveGrippyBy(1); |
|
69 wh.checkGrippy("Grippy should be moved down one row", row); |
|
70 } |
|
71 wh.moveGrippyBy(1); |
|
72 wh.checkGrippy("Grippy should remain at last row after trying to move " + |
|
73 "it down", |
|
74 wh.getRowCount() - 1); |
|
75 |
|
76 // Cancel the dialog, make sure history visits are not cleared. |
|
77 wh.checkPrefCheckbox("history", false); |
|
78 |
|
79 wh.cancelDialog(); |
|
80 yield promiseHistoryClearedState(uris, false); |
|
81 |
|
82 // OK, done, cleanup after ourselves. |
|
83 blankSlate(); |
|
84 yield promiseHistoryClearedState(uris, true); |
|
85 }); |
|
86 }); |
|
87 }, |
|
88 |
|
89 /** |
|
90 * Ensures that the combined history-downloads checkbox clears both history |
|
91 * visits and downloads when checked; the dialog respects simple timespan. |
|
92 */ |
|
93 function () { |
|
94 // Add history (within the past hour). |
|
95 let uris = []; |
|
96 let places = []; |
|
97 let pURI; |
|
98 for (let i = 0; i < 30; i++) { |
|
99 pURI = makeURI("http://" + i + "-minutes-ago.com/"); |
|
100 places.push({uri: pURI, visitDate: visitTimeForMinutesAgo(i)}); |
|
101 uris.push(pURI); |
|
102 } |
|
103 // Add history (over an hour ago). |
|
104 let olderURIs = []; |
|
105 for (let i = 0; i < 5; i++) { |
|
106 pURI = makeURI("http://" + (60 + i) + "-minutes-ago.com/"); |
|
107 places.push({uri: pURI, visitDate: visitTimeForMinutesAgo(60 + i)}); |
|
108 olderURIs.push(pURI); |
|
109 } |
|
110 |
|
111 addVisits(places, function() { |
|
112 // Add downloads (within the past hour). |
|
113 let downloadIDs = []; |
|
114 for (let i = 0; i < 5; i++) { |
|
115 downloadIDs.push(addDownloadWithMinutesAgo(i)); |
|
116 } |
|
117 // Add downloads (over an hour ago). |
|
118 let olderDownloadIDs = []; |
|
119 for (let i = 0; i < 5; i++) { |
|
120 olderDownloadIDs.push(addDownloadWithMinutesAgo(61 + i)); |
|
121 } |
|
122 let totalHistoryVisits = uris.length + olderURIs.length; |
|
123 |
|
124 // Open the dialog and do our tests. |
|
125 openWindow(function (aWin) { |
|
126 let wh = new WindowHelper(aWin); |
|
127 wh.selectDuration(Sanitizer.TIMESPAN_HOUR); |
|
128 wh.checkGrippy("Grippy should be at proper row after selecting HOUR " + |
|
129 "duration", |
|
130 uris.length); |
|
131 |
|
132 // Accept the dialog, make sure history visits and downloads within one |
|
133 // hour are cleared. |
|
134 wh.checkPrefCheckbox("history", true); |
|
135 wh.acceptDialog(); |
|
136 yield promiseHistoryClearedState(uris, true); |
|
137 ensureDownloadsClearedState(downloadIDs, true); |
|
138 |
|
139 // Make sure visits and downloads > 1 hour still exist. |
|
140 yield promiseHistoryClearedState(olderURIs, false); |
|
141 ensureDownloadsClearedState(olderDownloadIDs, false); |
|
142 |
|
143 // OK, done, cleanup after ourselves. |
|
144 blankSlate(); |
|
145 yield promiseHistoryClearedState(olderURIs, true); |
|
146 ensureDownloadsClearedState(olderDownloadIDs, true); |
|
147 }); |
|
148 }); |
|
149 }, |
|
150 |
|
151 /** |
|
152 * Ensures that the combined history-downloads checkbox removes neither |
|
153 * history visits nor downloads when not checked. |
|
154 */ |
|
155 function () { |
|
156 // Add history, downloads, form entries (within the past hour). |
|
157 let uris = []; |
|
158 let places = []; |
|
159 let pURI; |
|
160 for (let i = 0; i < 5; i++) { |
|
161 pURI = makeURI("http://" + i + "-minutes-ago.com/"); |
|
162 places.push({uri: pURI, visitDate: visitTimeForMinutesAgo(i)}); |
|
163 uris.push(pURI); |
|
164 } |
|
165 |
|
166 addVisits(places, function() { |
|
167 let downloadIDs = []; |
|
168 for (let i = 0; i < 5; i++) { |
|
169 downloadIDs.push(addDownloadWithMinutesAgo(i)); |
|
170 } |
|
171 let formEntries = []; |
|
172 for (let i = 0; i < 5; i++) { |
|
173 formEntries.push(addFormEntryWithMinutesAgo(i)); |
|
174 } |
|
175 |
|
176 // Open the dialog and do our tests. |
|
177 openWindow(function (aWin) { |
|
178 let wh = new WindowHelper(aWin); |
|
179 wh.selectDuration(Sanitizer.TIMESPAN_HOUR); |
|
180 wh.checkGrippy("Grippy should be at last row after selecting HOUR " + |
|
181 "duration", |
|
182 wh.getRowCount() - 1); |
|
183 |
|
184 // Remove only form entries, leave history (including downloads). |
|
185 wh.checkPrefCheckbox("history", false); |
|
186 wh.checkPrefCheckbox("formdata", true); |
|
187 wh.acceptDialog(); |
|
188 |
|
189 // Of the three only form entries should be cleared. |
|
190 yield promiseHistoryClearedState(uris, false); |
|
191 ensureDownloadsClearedState(downloadIDs, false); |
|
192 ensureFormEntriesClearedState(formEntries, true); |
|
193 |
|
194 // OK, done, cleanup after ourselves. |
|
195 blankSlate(); |
|
196 yield promiseHistoryClearedState(uris, true); |
|
197 ensureDownloadsClearedState(downloadIDs, true); |
|
198 }); |
|
199 }); |
|
200 }, |
|
201 |
|
202 /** |
|
203 * Ensures that the "Everything" duration option works. |
|
204 */ |
|
205 function () { |
|
206 // Add history. |
|
207 let uris = []; |
|
208 let places = []; |
|
209 let pURI; |
|
210 // within past hour, within past two hours, within past four hours and |
|
211 // outside past four hours |
|
212 [10, 70, 130, 250].forEach(function(aValue) { |
|
213 pURI = makeURI("http://" + aValue + "-minutes-ago.com/"); |
|
214 places.push({uri: pURI, visitDate: visitTimeForMinutesAgo(aValue)}); |
|
215 uris.push(pURI); |
|
216 }); |
|
217 addVisits(places, function() { |
|
218 |
|
219 // Open the dialog and do our tests. |
|
220 openWindow(function (aWin) { |
|
221 let wh = new WindowHelper(aWin); |
|
222 wh.selectDuration(Sanitizer.TIMESPAN_EVERYTHING); |
|
223 wh.checkPrefCheckbox("history", true); |
|
224 wh.acceptDialog(); |
|
225 yield promiseHistoryClearedState(uris, true); |
|
226 }); |
|
227 }); |
|
228 } |
|
229 ]; |
|
230 |
|
231 // Used as the download database ID for a new download. Incremented for each |
|
232 // new download. See addDownloadWithMinutesAgo(). |
|
233 var gDownloadId = 5555551; |
|
234 |
|
235 // Index in gAllTests of the test currently being run. Incremented for each |
|
236 // test run. See doNextTest(). |
|
237 var gCurrTest = 0; |
|
238 |
|
239 var now_uSec = Date.now() * 1000; |
|
240 |
|
241 /////////////////////////////////////////////////////////////////////////////// |
|
242 |
|
243 /** |
|
244 * This wraps the dialog and provides some convenience methods for interacting |
|
245 * with it. |
|
246 * |
|
247 * A warning: Before you call any function that uses the tree (or any function |
|
248 * that calls a function that uses the tree), you must set a non-everything |
|
249 * duration by calling selectDuration(). The dialog does not initialize the |
|
250 * tree if it does not yet need to be shown. |
|
251 * |
|
252 * @param aWin |
|
253 * The dialog's nsIDOMWindow |
|
254 */ |
|
255 function WindowHelper(aWin) { |
|
256 this.win = aWin; |
|
257 } |
|
258 |
|
259 WindowHelper.prototype = { |
|
260 /** |
|
261 * "Presses" the dialog's OK button. |
|
262 */ |
|
263 acceptDialog: function () { |
|
264 is(this.win.document.documentElement.getButton("accept").disabled, false, |
|
265 "Dialog's OK button should not be disabled"); |
|
266 this.win.document.documentElement.acceptDialog(); |
|
267 }, |
|
268 |
|
269 /** |
|
270 * "Presses" the dialog's Cancel button. |
|
271 */ |
|
272 cancelDialog: function () { |
|
273 this.win.document.documentElement.cancelDialog(); |
|
274 }, |
|
275 |
|
276 /** |
|
277 * Ensures that the grippy row is in the right place, tree selection is OK, |
|
278 * and that the grippy's visible. |
|
279 * |
|
280 * @param aMsg |
|
281 * Passed to is() when checking grippy location |
|
282 * @param aExpectedRow |
|
283 * The row that the grippy should be at |
|
284 */ |
|
285 checkGrippy: function (aMsg, aExpectedRow) { |
|
286 is(this.getGrippyRow(), aExpectedRow, aMsg); |
|
287 this.checkTreeSelection(); |
|
288 this.ensureGrippyIsVisible(); |
|
289 }, |
|
290 |
|
291 /** |
|
292 * (Un)checks a history scope checkbox (browser & download history, |
|
293 * form history, etc.). |
|
294 * |
|
295 * @param aPrefName |
|
296 * The final portion of the checkbox's privacy.cpd.* preference name |
|
297 * @param aCheckState |
|
298 * True if the checkbox should be checked, false otherwise |
|
299 */ |
|
300 checkPrefCheckbox: function (aPrefName, aCheckState) { |
|
301 var pref = "privacy.cpd." + aPrefName; |
|
302 var cb = this.win.document.querySelectorAll( |
|
303 "#itemList > [preference='" + pref + "']"); |
|
304 is(cb.length, 1, "found checkbox for " + pref + " preference"); |
|
305 if (cb[0].checked != aCheckState) |
|
306 cb[0].click(); |
|
307 }, |
|
308 |
|
309 /** |
|
310 * Ensures that the tree selection is appropriate to the grippy row. (A |
|
311 * single, contiguous selection should exist from the first row all the way |
|
312 * to the grippy.) |
|
313 */ |
|
314 checkTreeSelection: function () { |
|
315 let grippyRow = this.getGrippyRow(); |
|
316 let sel = this.getTree().view.selection; |
|
317 if (grippyRow === 0) { |
|
318 is(sel.getRangeCount(), 0, |
|
319 "Grippy row is 0, so no tree selection should exist"); |
|
320 } |
|
321 else { |
|
322 is(sel.getRangeCount(), 1, |
|
323 "Grippy row > 0, so only one tree selection range should exist"); |
|
324 let min = {}; |
|
325 let max = {}; |
|
326 sel.getRangeAt(0, min, max); |
|
327 is(min.value, 0, "Tree selection should start at first row"); |
|
328 is(max.value, grippyRow - 1, |
|
329 "Tree selection should end at row before grippy"); |
|
330 } |
|
331 }, |
|
332 |
|
333 /** |
|
334 * The grippy should always be visible when it's moved directly. This method |
|
335 * ensures that. |
|
336 */ |
|
337 ensureGrippyIsVisible: function () { |
|
338 let tbo = this.getTree().treeBoxObject; |
|
339 let firstVis = tbo.getFirstVisibleRow(); |
|
340 let lastVis = tbo.getLastVisibleRow(); |
|
341 let grippyRow = this.getGrippyRow(); |
|
342 ok(firstVis <= grippyRow && grippyRow <= lastVis, |
|
343 "Grippy row should be visible; this inequality should be true: " + |
|
344 firstVis + " <= " + grippyRow + " <= " + lastVis); |
|
345 }, |
|
346 |
|
347 /** |
|
348 * @return The dialog's duration dropdown |
|
349 */ |
|
350 getDurationDropdown: function () { |
|
351 return this.win.document.getElementById("sanitizeDurationChoice"); |
|
352 }, |
|
353 |
|
354 /** |
|
355 * @return The grippy row index |
|
356 */ |
|
357 getGrippyRow: function () { |
|
358 return this.win.gContiguousSelectionTreeHelper.getGrippyRow(); |
|
359 }, |
|
360 |
|
361 /** |
|
362 * @return The tree's row count (includes the grippy row) |
|
363 */ |
|
364 getRowCount: function () { |
|
365 return this.getTree().view.rowCount; |
|
366 }, |
|
367 |
|
368 /** |
|
369 * @return The tree |
|
370 */ |
|
371 getTree: function () { |
|
372 return this.win.gContiguousSelectionTreeHelper.tree; |
|
373 }, |
|
374 |
|
375 /** |
|
376 * @return True if the "Everything" warning panel is visible (as opposed to |
|
377 * the tree) |
|
378 */ |
|
379 isWarningPanelVisible: function () { |
|
380 return this.win.document.getElementById("durationDeck").selectedIndex == 1; |
|
381 }, |
|
382 |
|
383 /** |
|
384 * @return True if the tree is visible (as opposed to the warning panel) |
|
385 */ |
|
386 isTreeVisible: function () { |
|
387 return this.win.document.getElementById("durationDeck").selectedIndex == 0; |
|
388 }, |
|
389 |
|
390 /** |
|
391 * Moves the grippy one row at a time in the direction and magnitude specified. |
|
392 * If aDelta < 0, moves the grippy up; if aDelta > 0, moves it down. |
|
393 * |
|
394 * @param aDelta |
|
395 * The amount and direction to move |
|
396 */ |
|
397 moveGrippyBy: function (aDelta) { |
|
398 if (aDelta === 0) |
|
399 return; |
|
400 let key = aDelta < 0 ? "UP" : "DOWN"; |
|
401 let abs = Math.abs(aDelta); |
|
402 let treechildren = this.getTree().treeBoxObject.treeBody; |
|
403 treechildren.focus(); |
|
404 for (let i = 0; i < abs; i++) { |
|
405 EventUtils.sendKey(key); |
|
406 } |
|
407 }, |
|
408 |
|
409 /** |
|
410 * Selects a duration in the duration dropdown. |
|
411 * |
|
412 * @param aDurVal |
|
413 * One of the Sanitizer.TIMESPAN_* values |
|
414 */ |
|
415 selectDuration: function (aDurVal) { |
|
416 this.getDurationDropdown().value = aDurVal; |
|
417 if (aDurVal === Sanitizer.TIMESPAN_EVERYTHING) { |
|
418 is(this.isTreeVisible(), false, |
|
419 "Tree should not be visible for TIMESPAN_EVERYTHING"); |
|
420 is(this.isWarningPanelVisible(), true, |
|
421 "Warning panel should be visible for TIMESPAN_EVERYTHING"); |
|
422 } |
|
423 else { |
|
424 is(this.isTreeVisible(), true, |
|
425 "Tree should be visible for non-TIMESPAN_EVERYTHING"); |
|
426 is(this.isWarningPanelVisible(), false, |
|
427 "Warning panel should not be visible for non-TIMESPAN_EVERYTHING"); |
|
428 } |
|
429 } |
|
430 }; |
|
431 |
|
432 /** |
|
433 * Adds a download to history. |
|
434 * |
|
435 * @param aMinutesAgo |
|
436 * The download will be downloaded this many minutes ago |
|
437 */ |
|
438 function addDownloadWithMinutesAgo(aMinutesAgo) { |
|
439 let name = "fakefile-" + aMinutesAgo + "-minutes-ago"; |
|
440 let data = { |
|
441 id: gDownloadId, |
|
442 name: name, |
|
443 source: "https://bugzilla.mozilla.org/show_bug.cgi?id=480169", |
|
444 target: name, |
|
445 startTime: now_uSec - (aMinutesAgo * 60 * 1000000), |
|
446 endTime: now_uSec - ((aMinutesAgo + 1) *60 * 1000000), |
|
447 state: Ci.nsIDownloadManager.DOWNLOAD_FINISHED, |
|
448 currBytes: 0, maxBytes: -1, preferredAction: 0, autoResume: 0, |
|
449 guid: "a1bcD23eF4g5" |
|
450 }; |
|
451 |
|
452 let db = dm.DBConnection; |
|
453 let stmt = db.createStatement( |
|
454 "INSERT INTO moz_downloads (id, name, source, target, startTime, endTime, " + |
|
455 "state, currBytes, maxBytes, preferredAction, autoResume, guid) " + |
|
456 "VALUES (:id, :name, :source, :target, :startTime, :endTime, :state, " + |
|
457 ":currBytes, :maxBytes, :preferredAction, :autoResume, :guid)"); |
|
458 try { |
|
459 for (let prop in data) { |
|
460 stmt.params[prop] = data[prop]; |
|
461 } |
|
462 stmt.execute(); |
|
463 } |
|
464 finally { |
|
465 stmt.reset(); |
|
466 } |
|
467 |
|
468 is(downloadExists(gDownloadId), true, |
|
469 "Sanity check: download " + gDownloadId + |
|
470 " should exist after creating it"); |
|
471 |
|
472 return gDownloadId++; |
|
473 } |
|
474 |
|
475 /** |
|
476 * Adds a form entry to history. |
|
477 * |
|
478 * @param aMinutesAgo |
|
479 * The entry will be added this many minutes ago |
|
480 */ |
|
481 function addFormEntryWithMinutesAgo(aMinutesAgo) { |
|
482 let name = aMinutesAgo + "-minutes-ago"; |
|
483 formhist.addEntry(name, "dummy"); |
|
484 |
|
485 // Artifically age the entry to the proper vintage. |
|
486 let db = formhist.DBConnection; |
|
487 let timestamp = now_uSec - (aMinutesAgo * 60 * 1000000); |
|
488 db.executeSimpleSQL("UPDATE moz_formhistory SET firstUsed = " + |
|
489 timestamp + " WHERE fieldname = '" + name + "'"); |
|
490 |
|
491 is(formhist.nameExists(name), true, |
|
492 "Sanity check: form entry " + name + " should exist after creating it"); |
|
493 return name; |
|
494 } |
|
495 |
|
496 /** |
|
497 * Removes all history visits, downloads, and form entries. |
|
498 */ |
|
499 function blankSlate() { |
|
500 PlacesUtils.bhistory.removeAllPages(); |
|
501 dm.cleanUp(); |
|
502 formhist.removeAllEntries(); |
|
503 } |
|
504 |
|
505 /** |
|
506 * Checks to see if the download with the specified ID exists. |
|
507 * |
|
508 * @param aID |
|
509 * The ID of the download to check |
|
510 * @return True if the download exists, false otherwise |
|
511 */ |
|
512 function downloadExists(aID) |
|
513 { |
|
514 let db = dm.DBConnection; |
|
515 let stmt = db.createStatement( |
|
516 "SELECT * " + |
|
517 "FROM moz_downloads " + |
|
518 "WHERE id = :id" |
|
519 ); |
|
520 stmt.params.id = aID; |
|
521 let rows = stmt.executeStep(); |
|
522 stmt.finalize(); |
|
523 return !!rows; |
|
524 } |
|
525 |
|
526 /** |
|
527 * Runs the next test in the gAllTests array. If all tests have been run, |
|
528 * finishes the entire suite. |
|
529 */ |
|
530 function doNextTest() { |
|
531 if (gAllTests.length <= gCurrTest) { |
|
532 blankSlate(); |
|
533 waitForAsyncUpdates(finish); |
|
534 } |
|
535 else { |
|
536 let ct = gCurrTest; |
|
537 gCurrTest++; |
|
538 gAllTests[ct](); |
|
539 } |
|
540 } |
|
541 |
|
542 /** |
|
543 * Ensures that the specified downloads are either cleared or not. |
|
544 * |
|
545 * @param aDownloadIDs |
|
546 * Array of download database IDs |
|
547 * @param aShouldBeCleared |
|
548 * True if each download should be cleared, false otherwise |
|
549 */ |
|
550 function ensureDownloadsClearedState(aDownloadIDs, aShouldBeCleared) { |
|
551 let niceStr = aShouldBeCleared ? "no longer" : "still"; |
|
552 aDownloadIDs.forEach(function (id) { |
|
553 is(downloadExists(id), !aShouldBeCleared, |
|
554 "download " + id + " should " + niceStr + " exist"); |
|
555 }); |
|
556 } |
|
557 |
|
558 /** |
|
559 * Ensures that the specified form entries are either cleared or not. |
|
560 * |
|
561 * @param aFormEntries |
|
562 * Array of form entry names |
|
563 * @param aShouldBeCleared |
|
564 * True if each form entry should be cleared, false otherwise |
|
565 */ |
|
566 function ensureFormEntriesClearedState(aFormEntries, aShouldBeCleared) { |
|
567 let niceStr = aShouldBeCleared ? "no longer" : "still"; |
|
568 aFormEntries.forEach(function (entry) { |
|
569 is(formhist.nameExists(entry), !aShouldBeCleared, |
|
570 "form entry " + entry + " should " + niceStr + " exist"); |
|
571 }); |
|
572 } |
|
573 |
|
574 /** |
|
575 * Opens the sanitize dialog and runs a callback once it's finished loading. |
|
576 * |
|
577 * @param aOnloadCallback |
|
578 * A function that will be called once the dialog has loaded |
|
579 */ |
|
580 function openWindow(aOnloadCallback) { |
|
581 function windowObserver(aSubject, aTopic, aData) { |
|
582 if (aTopic != "domwindowopened") |
|
583 return; |
|
584 |
|
585 Services.ww.unregisterNotification(windowObserver); |
|
586 let win = aSubject.QueryInterface(Ci.nsIDOMWindow); |
|
587 win.addEventListener("load", function onload(event) { |
|
588 win.removeEventListener("load", onload, false); |
|
589 executeSoon(function () { |
|
590 // Some exceptions that reach here don't reach the test harness, but |
|
591 // ok()/is() do... |
|
592 try { |
|
593 Task.spawn(function() { |
|
594 aOnloadCallback(win); |
|
595 }).then(function() { |
|
596 waitForAsyncUpdates(doNextTest); |
|
597 }); |
|
598 } |
|
599 catch (exc) { |
|
600 win.close(); |
|
601 ok(false, "Unexpected exception: " + exc + "\n" + exc.stack); |
|
602 finish(); |
|
603 } |
|
604 }); |
|
605 }, false); |
|
606 } |
|
607 Services.ww.registerNotification(windowObserver); |
|
608 Services.ww.openWindow(null, |
|
609 "chrome://browser/content/sanitize.xul", |
|
610 "Sanitize", |
|
611 "chrome,titlebar,dialog,centerscreen,modal", |
|
612 null); |
|
613 } |
|
614 |
|
615 /** |
|
616 * Creates a visit time. |
|
617 * |
|
618 * @param aMinutesAgo |
|
619 * The visit will be visited this many minutes ago |
|
620 */ |
|
621 function visitTimeForMinutesAgo(aMinutesAgo) { |
|
622 return now_uSec - (aMinutesAgo * 60 * 1000000); |
|
623 } |
|
624 |
|
625 /////////////////////////////////////////////////////////////////////////////// |
|
626 |
|
627 function test() { |
|
628 blankSlate(); |
|
629 waitForExplicitFinish(); |
|
630 // Kick off all the tests in the gAllTests array. |
|
631 waitForAsyncUpdates(doNextTest); |
|
632 } |