michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: let {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}); michael@0: let TargetFactory = devtools.TargetFactory; michael@0: let {console} = Cu.import("resource://gre/modules/devtools/Console.jsm", {}); michael@0: michael@0: gDevTools.testing = true; michael@0: SimpleTest.registerCleanupFunction(() => { michael@0: gDevTools.testing = false; michael@0: }); michael@0: michael@0: /** michael@0: * Open a new tab at a URL and call a callback on load michael@0: */ michael@0: function addTab(aURL, aCallback) michael@0: { michael@0: waitForExplicitFinish(); michael@0: michael@0: gBrowser.selectedTab = gBrowser.addTab(); michael@0: content.location = aURL; michael@0: michael@0: let tab = gBrowser.selectedTab; michael@0: let browser = gBrowser.getBrowserForTab(tab); michael@0: michael@0: function onTabLoad() { michael@0: browser.removeEventListener("load", onTabLoad, true); michael@0: aCallback(browser, tab, browser.contentDocument); michael@0: } michael@0: michael@0: browser.addEventListener("load", onTabLoad, true); michael@0: } michael@0: michael@0: registerCleanupFunction(function tearDown() { michael@0: while (gBrowser.tabs.length > 1) { michael@0: gBrowser.removeCurrentTab(); michael@0: } michael@0: michael@0: console = undefined; michael@0: }); michael@0: michael@0: function catchFail(func) { michael@0: return function() { michael@0: try { michael@0: return func.apply(null, arguments); michael@0: } michael@0: catch (ex) { michael@0: ok(false, ex); michael@0: console.error(ex); michael@0: finish(); michael@0: throw ex; michael@0: } michael@0: }; michael@0: } michael@0: michael@0: /** michael@0: * Polls a given function waiting for the given value. michael@0: * michael@0: * @param object aOptions michael@0: * Options object with the following properties: michael@0: * - validator michael@0: * A validator function that should return the expected value. This is michael@0: * called every few milliseconds to check if the result is the expected michael@0: * one. When the returned result is the expected one, then the |success| michael@0: * function is called and polling stops. If |validator| never returns michael@0: * the expected value, then polling timeouts after several tries and michael@0: * a failure is recorded - the given |failure| function is invoked. michael@0: * - success michael@0: * A function called when the validator function returns the expected michael@0: * value. michael@0: * - failure michael@0: * A function called if the validator function timeouts - fails to return michael@0: * the expected value in the given time. michael@0: * - name michael@0: * Name of test. This is used to generate the success and failure michael@0: * messages. michael@0: * - timeout michael@0: * Timeout for validator function, in milliseconds. Default is 5000 ms. michael@0: * - value michael@0: * The expected value. If this option is omitted then the |validator| michael@0: * function must return a trueish value. michael@0: * Each of the provided callback functions will receive two arguments: michael@0: * the |aOptions| object and the last value returned by |validator|. michael@0: */ michael@0: function waitForValue(aOptions) michael@0: { michael@0: let start = Date.now(); michael@0: let timeout = aOptions.timeout || 5000; michael@0: let lastValue; michael@0: michael@0: function wait(validatorFn, successFn, failureFn) michael@0: { michael@0: if ((Date.now() - start) > timeout) { michael@0: // Log the failure. michael@0: ok(false, "Timed out while waiting for: " + aOptions.name); michael@0: let expected = "value" in aOptions ? michael@0: "'" + aOptions.value + "'" : michael@0: "a trueish value"; michael@0: info("timeout info :: got '" + lastValue + "', expected " + expected); michael@0: failureFn(aOptions, lastValue); michael@0: return; michael@0: } michael@0: michael@0: lastValue = validatorFn(aOptions, lastValue); michael@0: let successful = "value" in aOptions ? michael@0: lastValue == aOptions.value : michael@0: lastValue; michael@0: if (successful) { michael@0: ok(true, aOptions.name); michael@0: successFn(aOptions, lastValue); michael@0: } michael@0: else { michael@0: setTimeout(function() wait(validatorFn, successFn, failureFn), 100); michael@0: } michael@0: } michael@0: michael@0: wait(aOptions.validator, aOptions.success, aOptions.failure); michael@0: } michael@0: michael@0: function oneTimeObserve(name, callback) { michael@0: var func = function() { michael@0: Services.obs.removeObserver(func, name); michael@0: callback(); michael@0: }; michael@0: Services.obs.addObserver(func, name, false); michael@0: }