browser/components/sessionstore/test/head.js

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 const TAB_STATE_NEEDS_RESTORE = 1;
michael@0 6 const TAB_STATE_RESTORING = 2;
michael@0 7
michael@0 8 const ROOT = getRootDirectory(gTestPath);
michael@0 9 const FRAME_SCRIPTS = [
michael@0 10 ROOT + "content.js",
michael@0 11 ROOT + "content-forms.js"
michael@0 12 ];
michael@0 13
michael@0 14 let mm = Cc["@mozilla.org/globalmessagemanager;1"]
michael@0 15 .getService(Ci.nsIMessageListenerManager);
michael@0 16
michael@0 17 for (let script of FRAME_SCRIPTS) {
michael@0 18 mm.loadFrameScript(script, true);
michael@0 19 }
michael@0 20
michael@0 21 mm.addMessageListener("SessionStore:setupSyncHandler", onSetupSyncHandler);
michael@0 22
michael@0 23 /**
michael@0 24 * This keeps track of all SyncHandlers passed to chrome from frame scripts.
michael@0 25 * We need this to let tests communicate with frame scripts and cause (a)sync
michael@0 26 * flushes.
michael@0 27 */
michael@0 28 let SyncHandlers = new WeakMap();
michael@0 29 function onSetupSyncHandler(msg) {
michael@0 30 SyncHandlers.set(msg.target, msg.objects.handler);
michael@0 31 }
michael@0 32
michael@0 33 registerCleanupFunction(() => {
michael@0 34 for (let script of FRAME_SCRIPTS) {
michael@0 35 mm.removeDelayedFrameScript(script, true);
michael@0 36 }
michael@0 37 mm.removeMessageListener("SessionStore:setupSyncHandler", onSetupSyncHandler);
michael@0 38 });
michael@0 39
michael@0 40 let tmp = {};
michael@0 41 Cu.import("resource://gre/modules/Promise.jsm", tmp);
michael@0 42 Cu.import("resource:///modules/sessionstore/SessionStore.jsm", tmp);
michael@0 43 Cu.import("resource:///modules/sessionstore/SessionSaver.jsm", tmp);
michael@0 44 let {Promise, SessionStore, SessionSaver} = tmp;
michael@0 45
michael@0 46 let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
michael@0 47
michael@0 48 // Some tests here assume that all restored tabs are loaded without waiting for
michael@0 49 // the user to bring them to the foreground. We ensure this by resetting the
michael@0 50 // related preference (see the "firefox.js" defaults file for details).
michael@0 51 Services.prefs.setBoolPref("browser.sessionstore.restore_on_demand", false);
michael@0 52 registerCleanupFunction(function () {
michael@0 53 Services.prefs.clearUserPref("browser.sessionstore.restore_on_demand");
michael@0 54 });
michael@0 55
michael@0 56 // Obtain access to internals
michael@0 57 Services.prefs.setBoolPref("browser.sessionstore.debug", true);
michael@0 58 registerCleanupFunction(function () {
michael@0 59 Services.prefs.clearUserPref("browser.sessionstore.debug");
michael@0 60 });
michael@0 61
michael@0 62
michael@0 63 // This kicks off the search service used on about:home and allows the
michael@0 64 // session restore tests to be run standalone without triggering errors.
michael@0 65 Cc["@mozilla.org/browser/clh;1"].getService(Ci.nsIBrowserHandler).defaultArgs;
michael@0 66
michael@0 67 function provideWindow(aCallback, aURL, aFeatures) {
michael@0 68 function callbackSoon(aWindow) {
michael@0 69 executeSoon(function executeCallbackSoon() {
michael@0 70 aCallback(aWindow);
michael@0 71 });
michael@0 72 }
michael@0 73
michael@0 74 let win = openDialog(getBrowserURL(), "", aFeatures || "chrome,all,dialog=no", aURL);
michael@0 75 whenWindowLoaded(win, function onWindowLoaded(aWin) {
michael@0 76 if (!aURL) {
michael@0 77 info("Loaded a blank window.");
michael@0 78 callbackSoon(aWin);
michael@0 79 return;
michael@0 80 }
michael@0 81
michael@0 82 aWin.gBrowser.selectedBrowser.addEventListener("load", function selectedBrowserLoadListener() {
michael@0 83 aWin.gBrowser.selectedBrowser.removeEventListener("load", selectedBrowserLoadListener, true);
michael@0 84 callbackSoon(aWin);
michael@0 85 }, true);
michael@0 86 });
michael@0 87 }
michael@0 88
michael@0 89 // This assumes that tests will at least have some state/entries
michael@0 90 function waitForBrowserState(aState, aSetStateCallback) {
michael@0 91 let windows = [window];
michael@0 92 let tabsRestored = 0;
michael@0 93 let expectedTabsRestored = 0;
michael@0 94 let expectedWindows = aState.windows.length;
michael@0 95 let windowsOpen = 1;
michael@0 96 let listening = false;
michael@0 97 let windowObserving = false;
michael@0 98 let restoreHiddenTabs = Services.prefs.getBoolPref(
michael@0 99 "browser.sessionstore.restore_hidden_tabs");
michael@0 100
michael@0 101 aState.windows.forEach(function (winState) {
michael@0 102 winState.tabs.forEach(function (tabState) {
michael@0 103 if (restoreHiddenTabs || !tabState.hidden)
michael@0 104 expectedTabsRestored++;
michael@0 105 });
michael@0 106 });
michael@0 107
michael@0 108 // There must be only hidden tabs and restoreHiddenTabs = false. We still
michael@0 109 // expect one of them to be restored because it gets shown automatically.
michael@0 110 if (!expectedTabsRestored)
michael@0 111 expectedTabsRestored = 1;
michael@0 112
michael@0 113 function onSSTabRestored(aEvent) {
michael@0 114 if (++tabsRestored == expectedTabsRestored) {
michael@0 115 // Remove the event listener from each window
michael@0 116 windows.forEach(function(win) {
michael@0 117 win.gBrowser.tabContainer.removeEventListener("SSTabRestored", onSSTabRestored, true);
michael@0 118 });
michael@0 119 listening = false;
michael@0 120 info("running " + aSetStateCallback.name);
michael@0 121 executeSoon(aSetStateCallback);
michael@0 122 }
michael@0 123 }
michael@0 124
michael@0 125 // Used to add our listener to further windows so we can catch SSTabRestored
michael@0 126 // coming from them when creating a multi-window state.
michael@0 127 function windowObserver(aSubject, aTopic, aData) {
michael@0 128 if (aTopic == "domwindowopened") {
michael@0 129 let newWindow = aSubject.QueryInterface(Ci.nsIDOMWindow);
michael@0 130 newWindow.addEventListener("load", function() {
michael@0 131 newWindow.removeEventListener("load", arguments.callee, false);
michael@0 132
michael@0 133 if (++windowsOpen == expectedWindows) {
michael@0 134 Services.ww.unregisterNotification(windowObserver);
michael@0 135 windowObserving = false;
michael@0 136 }
michael@0 137
michael@0 138 // Track this window so we can remove the progress listener later
michael@0 139 windows.push(newWindow);
michael@0 140 // Add the progress listener
michael@0 141 newWindow.gBrowser.tabContainer.addEventListener("SSTabRestored", onSSTabRestored, true);
michael@0 142 }, false);
michael@0 143 }
michael@0 144 }
michael@0 145
michael@0 146 // We only want to register the notification if we expect more than 1 window
michael@0 147 if (expectedWindows > 1) {
michael@0 148 registerCleanupFunction(function() {
michael@0 149 if (windowObserving) {
michael@0 150 Services.ww.unregisterNotification(windowObserver);
michael@0 151 }
michael@0 152 });
michael@0 153 windowObserving = true;
michael@0 154 Services.ww.registerNotification(windowObserver);
michael@0 155 }
michael@0 156
michael@0 157 registerCleanupFunction(function() {
michael@0 158 if (listening) {
michael@0 159 windows.forEach(function(win) {
michael@0 160 win.gBrowser.tabContainer.removeEventListener("SSTabRestored", onSSTabRestored, true);
michael@0 161 });
michael@0 162 }
michael@0 163 });
michael@0 164 // Add the event listener for this window as well.
michael@0 165 listening = true;
michael@0 166 gBrowser.tabContainer.addEventListener("SSTabRestored", onSSTabRestored, true);
michael@0 167
michael@0 168 // Ensure setBrowserState() doesn't remove the initial tab.
michael@0 169 gBrowser.selectedTab = gBrowser.tabs[0];
michael@0 170
michael@0 171 // Finally, call setBrowserState
michael@0 172 ss.setBrowserState(JSON.stringify(aState));
michael@0 173 }
michael@0 174
michael@0 175 // Doesn't assume that the tab needs to be closed in a cleanup function.
michael@0 176 // If that's the case, the test author should handle that in the test.
michael@0 177 function waitForTabState(aTab, aState, aCallback) {
michael@0 178 let listening = true;
michael@0 179
michael@0 180 function onSSTabRestored() {
michael@0 181 aTab.removeEventListener("SSTabRestored", onSSTabRestored, false);
michael@0 182 listening = false;
michael@0 183 aCallback();
michael@0 184 }
michael@0 185
michael@0 186 aTab.addEventListener("SSTabRestored", onSSTabRestored, false);
michael@0 187
michael@0 188 registerCleanupFunction(function() {
michael@0 189 if (listening) {
michael@0 190 aTab.removeEventListener("SSTabRestored", onSSTabRestored, false);
michael@0 191 }
michael@0 192 });
michael@0 193 ss.setTabState(aTab, JSON.stringify(aState));
michael@0 194 }
michael@0 195
michael@0 196 /**
michael@0 197 * Wait for a content -> chrome message.
michael@0 198 */
michael@0 199 function promiseContentMessage(browser, name) {
michael@0 200 let deferred = Promise.defer();
michael@0 201 let mm = browser.messageManager;
michael@0 202
michael@0 203 function removeListener() {
michael@0 204 mm.removeMessageListener(name, listener);
michael@0 205 }
michael@0 206
michael@0 207 function listener(msg) {
michael@0 208 removeListener();
michael@0 209 deferred.resolve(msg.data);
michael@0 210 }
michael@0 211
michael@0 212 mm.addMessageListener(name, listener);
michael@0 213 registerCleanupFunction(removeListener);
michael@0 214 return deferred.promise;
michael@0 215 }
michael@0 216
michael@0 217 function waitForTopic(aTopic, aTimeout, aCallback) {
michael@0 218 let observing = false;
michael@0 219 function removeObserver() {
michael@0 220 if (!observing)
michael@0 221 return;
michael@0 222 Services.obs.removeObserver(observer, aTopic);
michael@0 223 observing = false;
michael@0 224 }
michael@0 225
michael@0 226 let timeout = setTimeout(function () {
michael@0 227 removeObserver();
michael@0 228 aCallback(false);
michael@0 229 }, aTimeout);
michael@0 230
michael@0 231 function observer(aSubject, aTopic, aData) {
michael@0 232 removeObserver();
michael@0 233 timeout = clearTimeout(timeout);
michael@0 234 executeSoon(() => aCallback(true));
michael@0 235 }
michael@0 236
michael@0 237 registerCleanupFunction(function() {
michael@0 238 removeObserver();
michael@0 239 if (timeout) {
michael@0 240 clearTimeout(timeout);
michael@0 241 }
michael@0 242 });
michael@0 243
michael@0 244 observing = true;
michael@0 245 Services.obs.addObserver(observer, aTopic, false);
michael@0 246 }
michael@0 247
michael@0 248 /**
michael@0 249 * Wait until session restore has finished collecting its data and is
michael@0 250 * has written that data ("sessionstore-state-write-complete").
michael@0 251 *
michael@0 252 * @param {function} aCallback If sessionstore-state-write is sent
michael@0 253 * within buffering interval + 100 ms, the callback is passed |true|,
michael@0 254 * otherwise, it is passed |false|.
michael@0 255 */
michael@0 256 function waitForSaveState(aCallback) {
michael@0 257 let timeout = 100 +
michael@0 258 Services.prefs.getIntPref("browser.sessionstore.interval");
michael@0 259 return waitForTopic("sessionstore-state-write-complete", timeout, aCallback);
michael@0 260 }
michael@0 261 function promiseSaveState() {
michael@0 262 let deferred = Promise.defer();
michael@0 263 waitForSaveState(isSuccessful => {
michael@0 264 if (isSuccessful) {
michael@0 265 deferred.resolve();
michael@0 266 } else {
michael@0 267 deferred.reject(new Error("timeout"));
michael@0 268 }});
michael@0 269 return deferred.promise;
michael@0 270 }
michael@0 271 function forceSaveState() {
michael@0 272 return SessionSaver.run();
michael@0 273 }
michael@0 274
michael@0 275 function promiseSaveFileContents() {
michael@0 276 let promise = forceSaveState();
michael@0 277 return promise.then(function() {
michael@0 278 return OS.File.read(OS.Path.join(OS.Constants.Path.profileDir, "sessionstore.js"), { encoding: "utf-8" });
michael@0 279 });
michael@0 280 }
michael@0 281
michael@0 282 function whenBrowserLoaded(aBrowser, aCallback = next, ignoreSubFrames = true) {
michael@0 283 aBrowser.addEventListener("load", function onLoad(event) {
michael@0 284 if (!ignoreSubFrames || event.target == aBrowser.contentDocument) {
michael@0 285 aBrowser.removeEventListener("load", onLoad, true);
michael@0 286 executeSoon(aCallback);
michael@0 287 }
michael@0 288 }, true);
michael@0 289 }
michael@0 290 function promiseBrowserLoaded(aBrowser, ignoreSubFrames = true) {
michael@0 291 let deferred = Promise.defer();
michael@0 292 whenBrowserLoaded(aBrowser, deferred.resolve, ignoreSubFrames);
michael@0 293 return deferred.promise;
michael@0 294 }
michael@0 295 function whenBrowserUnloaded(aBrowser, aContainer, aCallback = next) {
michael@0 296 aBrowser.addEventListener("unload", function onUnload() {
michael@0 297 aBrowser.removeEventListener("unload", onUnload, true);
michael@0 298 executeSoon(aCallback);
michael@0 299 }, true);
michael@0 300 }
michael@0 301 function promiseBrowserUnloaded(aBrowser, aContainer) {
michael@0 302 let deferred = Promise.defer();
michael@0 303 whenBrowserUnloaded(aBrowser, aContainer, deferred.resolve);
michael@0 304 return deferred.promise;
michael@0 305 }
michael@0 306
michael@0 307 function whenWindowLoaded(aWindow, aCallback = next) {
michael@0 308 aWindow.addEventListener("load", function windowLoadListener() {
michael@0 309 aWindow.removeEventListener("load", windowLoadListener, false);
michael@0 310 executeSoon(function executeWhenWindowLoaded() {
michael@0 311 aCallback(aWindow);
michael@0 312 });
michael@0 313 }, false);
michael@0 314 }
michael@0 315 function promiseWindowLoaded(aWindow) {
michael@0 316 let deferred = Promise.defer();
michael@0 317 whenWindowLoaded(aWindow, deferred.resolve);
michael@0 318 return deferred.promise;
michael@0 319 }
michael@0 320
michael@0 321 function whenTabRestored(aTab, aCallback = next) {
michael@0 322 aTab.addEventListener("SSTabRestored", function onRestored(aEvent) {
michael@0 323 aTab.removeEventListener("SSTabRestored", onRestored, true);
michael@0 324 executeSoon(function executeWhenTabRestored() {
michael@0 325 aCallback();
michael@0 326 });
michael@0 327 }, true);
michael@0 328 }
michael@0 329
michael@0 330 var gUniqueCounter = 0;
michael@0 331 function r() {
michael@0 332 return Date.now() + "-" + (++gUniqueCounter);
michael@0 333 }
michael@0 334
michael@0 335 function BrowserWindowIterator() {
michael@0 336 let windowsEnum = Services.wm.getEnumerator("navigator:browser");
michael@0 337 while (windowsEnum.hasMoreElements()) {
michael@0 338 let currentWindow = windowsEnum.getNext();
michael@0 339 if (!currentWindow.closed) {
michael@0 340 yield currentWindow;
michael@0 341 }
michael@0 342 }
michael@0 343 }
michael@0 344
michael@0 345 let gWebProgressListener = {
michael@0 346 _callback: null,
michael@0 347
michael@0 348 setCallback: function (aCallback) {
michael@0 349 if (!this._callback) {
michael@0 350 window.gBrowser.addTabsProgressListener(this);
michael@0 351 }
michael@0 352 this._callback = aCallback;
michael@0 353 },
michael@0 354
michael@0 355 unsetCallback: function () {
michael@0 356 if (this._callback) {
michael@0 357 this._callback = null;
michael@0 358 window.gBrowser.removeTabsProgressListener(this);
michael@0 359 }
michael@0 360 },
michael@0 361
michael@0 362 onStateChange: function (aBrowser, aWebProgress, aRequest,
michael@0 363 aStateFlags, aStatus) {
michael@0 364 if (aStateFlags & Ci.nsIWebProgressListener.STATE_STOP &&
michael@0 365 aStateFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK &&
michael@0 366 aStateFlags & Ci.nsIWebProgressListener.STATE_IS_WINDOW) {
michael@0 367 this._callback(aBrowser);
michael@0 368 }
michael@0 369 }
michael@0 370 };
michael@0 371
michael@0 372 registerCleanupFunction(function () {
michael@0 373 gWebProgressListener.unsetCallback();
michael@0 374 });
michael@0 375
michael@0 376 let gProgressListener = {
michael@0 377 _callback: null,
michael@0 378
michael@0 379 setCallback: function (callback) {
michael@0 380 Services.obs.addObserver(this, "sessionstore-debug-tab-restored", false);
michael@0 381 this._callback = callback;
michael@0 382 },
michael@0 383
michael@0 384 unsetCallback: function () {
michael@0 385 if (this._callback) {
michael@0 386 this._callback = null;
michael@0 387 Services.obs.removeObserver(this, "sessionstore-debug-tab-restored");
michael@0 388 }
michael@0 389 },
michael@0 390
michael@0 391 observe: function (browser, topic, data) {
michael@0 392 gProgressListener.onRestored(browser);
michael@0 393 },
michael@0 394
michael@0 395 onRestored: function (browser) {
michael@0 396 if (browser.__SS_restoreState == TAB_STATE_RESTORING) {
michael@0 397 let args = [browser].concat(gProgressListener._countTabs());
michael@0 398 gProgressListener._callback.apply(gProgressListener, args);
michael@0 399 }
michael@0 400 },
michael@0 401
michael@0 402 _countTabs: function () {
michael@0 403 let needsRestore = 0, isRestoring = 0, wasRestored = 0;
michael@0 404
michael@0 405 for (let win in BrowserWindowIterator()) {
michael@0 406 for (let i = 0; i < win.gBrowser.tabs.length; i++) {
michael@0 407 let browser = win.gBrowser.tabs[i].linkedBrowser;
michael@0 408 if (!browser.__SS_restoreState)
michael@0 409 wasRestored++;
michael@0 410 else if (browser.__SS_restoreState == TAB_STATE_RESTORING)
michael@0 411 isRestoring++;
michael@0 412 else if (browser.__SS_restoreState == TAB_STATE_NEEDS_RESTORE)
michael@0 413 needsRestore++;
michael@0 414 }
michael@0 415 }
michael@0 416 return [needsRestore, isRestoring, wasRestored];
michael@0 417 }
michael@0 418 };
michael@0 419
michael@0 420 registerCleanupFunction(function () {
michael@0 421 gProgressListener.unsetCallback();
michael@0 422 });
michael@0 423
michael@0 424 // Close everything but our primary window. We can't use waitForFocus()
michael@0 425 // because apparently it's buggy. See bug 599253.
michael@0 426 function closeAllButPrimaryWindow() {
michael@0 427 for (let win in BrowserWindowIterator()) {
michael@0 428 if (win != window) {
michael@0 429 win.close();
michael@0 430 }
michael@0 431 }
michael@0 432 }
michael@0 433
michael@0 434 /**
michael@0 435 * When opening a new window it is not sufficient to wait for its load event.
michael@0 436 * We need to use whenDelayedStartupFinshed() here as the browser window's
michael@0 437 * delayedStartup() routine is executed one tick after the window's load event
michael@0 438 * has been dispatched. browser-delayed-startup-finished might be deferred even
michael@0 439 * further if parts of the window's initialization process take more time than
michael@0 440 * expected (e.g. reading a big session state from disk).
michael@0 441 */
michael@0 442 function whenNewWindowLoaded(aOptions, aCallback) {
michael@0 443 let win = OpenBrowserWindow(aOptions);
michael@0 444 whenDelayedStartupFinished(win, () => aCallback(win));
michael@0 445 return win;
michael@0 446 }
michael@0 447 function promiseNewWindowLoaded(aOptions) {
michael@0 448 let deferred = Promise.defer();
michael@0 449 whenNewWindowLoaded(aOptions, deferred.resolve);
michael@0 450 return deferred.promise;
michael@0 451 }
michael@0 452
michael@0 453 /**
michael@0 454 * Chrome windows aren't closed synchronously. Provide a helper method to close
michael@0 455 * a window and wait until we received the "domwindowclosed" notification for it.
michael@0 456 */
michael@0 457 function promiseWindowClosed(win) {
michael@0 458 let deferred = Promise.defer();
michael@0 459
michael@0 460 Services.obs.addObserver(function obs(subject, topic) {
michael@0 461 if (subject == win) {
michael@0 462 Services.obs.removeObserver(obs, topic);
michael@0 463 deferred.resolve();
michael@0 464 }
michael@0 465 }, "domwindowclosed", false);
michael@0 466
michael@0 467 win.close();
michael@0 468 return deferred.promise;
michael@0 469 }
michael@0 470
michael@0 471 /**
michael@0 472 * This waits for the browser-delayed-startup-finished notification of a given
michael@0 473 * window. It indicates that the windows has loaded completely and is ready to
michael@0 474 * be used for testing.
michael@0 475 */
michael@0 476 function whenDelayedStartupFinished(aWindow, aCallback) {
michael@0 477 Services.obs.addObserver(function observer(aSubject, aTopic) {
michael@0 478 if (aWindow == aSubject) {
michael@0 479 Services.obs.removeObserver(observer, aTopic);
michael@0 480 executeSoon(aCallback);
michael@0 481 }
michael@0 482 }, "browser-delayed-startup-finished", false);
michael@0 483 }
michael@0 484
michael@0 485 /**
michael@0 486 * The test runner that controls the execution flow of our tests.
michael@0 487 */
michael@0 488 let TestRunner = {
michael@0 489 _iter: null,
michael@0 490
michael@0 491 /**
michael@0 492 * Holds the browser state from before we started so
michael@0 493 * that we can restore it after all tests ran.
michael@0 494 */
michael@0 495 backupState: {},
michael@0 496
michael@0 497 /**
michael@0 498 * Starts the test runner.
michael@0 499 */
michael@0 500 run: function () {
michael@0 501 waitForExplicitFinish();
michael@0 502
michael@0 503 SessionStore.promiseInitialized.then(() => {
michael@0 504 this.backupState = JSON.parse(ss.getBrowserState());
michael@0 505 this._iter = runTests();
michael@0 506 this.next();
michael@0 507 });
michael@0 508 },
michael@0 509
michael@0 510 /**
michael@0 511 * Runs the next available test or finishes if there's no test left.
michael@0 512 */
michael@0 513 next: function () {
michael@0 514 try {
michael@0 515 TestRunner._iter.next();
michael@0 516 } catch (e if e instanceof StopIteration) {
michael@0 517 TestRunner.finish();
michael@0 518 }
michael@0 519 },
michael@0 520
michael@0 521 /**
michael@0 522 * Finishes all tests and cleans up.
michael@0 523 */
michael@0 524 finish: function () {
michael@0 525 closeAllButPrimaryWindow();
michael@0 526 gBrowser.selectedTab = gBrowser.tabs[0];
michael@0 527 waitForBrowserState(this.backupState, finish);
michael@0 528 }
michael@0 529 };
michael@0 530
michael@0 531 function next() {
michael@0 532 TestRunner.next();
michael@0 533 }
michael@0 534
michael@0 535 function promiseTabRestored(tab) {
michael@0 536 let deferred = Promise.defer();
michael@0 537
michael@0 538 tab.addEventListener("SSTabRestored", function onRestored() {
michael@0 539 tab.removeEventListener("SSTabRestored", onRestored);
michael@0 540 deferred.resolve();
michael@0 541 });
michael@0 542
michael@0 543 return deferred.promise;
michael@0 544 }
michael@0 545
michael@0 546 function sendMessage(browser, name, data = {}) {
michael@0 547 browser.messageManager.sendAsyncMessage(name, data);
michael@0 548 return promiseContentMessage(browser, name);
michael@0 549 }
michael@0 550
michael@0 551 // This creates list of functions that we will map to their corresponding
michael@0 552 // ss-test:* messages names. Those will be sent to the frame script and
michael@0 553 // be used to read and modify form data.
michael@0 554 const FORM_HELPERS = [
michael@0 555 "getTextContent",
michael@0 556 "getInputValue", "setInputValue",
michael@0 557 "getInputChecked", "setInputChecked",
michael@0 558 "getSelectedIndex", "setSelectedIndex",
michael@0 559 "getMultipleSelected", "setMultipleSelected",
michael@0 560 "getFileNameArray", "setFileNameArray",
michael@0 561 ];
michael@0 562
michael@0 563 for (let name of FORM_HELPERS) {
michael@0 564 let msg = "ss-test:" + name;
michael@0 565 this[name] = (browser, data) => sendMessage(browser, msg, data);
michael@0 566 }

mercurial