diff options
Diffstat (limited to 'devtools/client/canvasdebugger/test/head.js')
-rw-r--r-- | devtools/client/canvasdebugger/test/head.js | 305 |
1 files changed, 305 insertions, 0 deletions
diff --git a/devtools/client/canvasdebugger/test/head.js b/devtools/client/canvasdebugger/test/head.js new file mode 100644 index 000000000..a718551ce --- /dev/null +++ b/devtools/client/canvasdebugger/test/head.js @@ -0,0 +1,305 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ +"use strict"; + +var { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; + +var { generateUUID } = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator); +var { require } = Cu.import("resource://devtools/shared/Loader.jsm", {}); + +var Services = require("Services"); +var promise = require("promise"); +var { gDevTools } = require("devtools/client/framework/devtools"); +var { DebuggerClient } = require("devtools/shared/client/main"); +var { DebuggerServer } = require("devtools/server/main"); +var { CallWatcherFront } = require("devtools/shared/fronts/call-watcher"); +var { CanvasFront } = require("devtools/shared/fronts/canvas"); +var { setTimeout } = require("sdk/timers"); +var DevToolsUtils = require("devtools/shared/DevToolsUtils"); +var flags = require("devtools/shared/flags"); +var { TargetFactory } = require("devtools/client/framework/target"); +var { Toolbox } = require("devtools/client/framework/toolbox"); +var { isWebGLSupported } = require("devtools/client/shared/webgl-utils"); +var mm = null; + +const FRAME_SCRIPT_UTILS_URL = "chrome://devtools/content/shared/frame-script-utils.js"; +const EXAMPLE_URL = "http://example.com/browser/devtools/client/canvasdebugger/test/"; +const SET_TIMEOUT_URL = EXAMPLE_URL + "doc_settimeout.html"; +const NO_CANVAS_URL = EXAMPLE_URL + "doc_no-canvas.html"; +const RAF_NO_CANVAS_URL = EXAMPLE_URL + "doc_raf-no-canvas.html"; +const SIMPLE_CANVAS_URL = EXAMPLE_URL + "doc_simple-canvas.html"; +const SIMPLE_BITMASKS_URL = EXAMPLE_URL + "doc_simple-canvas-bitmasks.html"; +const SIMPLE_CANVAS_TRANSPARENT_URL = EXAMPLE_URL + "doc_simple-canvas-transparent.html"; +const SIMPLE_CANVAS_DEEP_STACK_URL = EXAMPLE_URL + "doc_simple-canvas-deep-stack.html"; +const WEBGL_ENUM_URL = EXAMPLE_URL + "doc_webgl-enum.html"; +const WEBGL_BINDINGS_URL = EXAMPLE_URL + "doc_webgl-bindings.html"; +const WEBGL_DRAW_ARRAYS = EXAMPLE_URL + "doc_webgl-drawArrays.html"; +const WEBGL_DRAW_ELEMENTS = EXAMPLE_URL + "doc_webgl-drawElements.html"; +const RAF_BEGIN_URL = EXAMPLE_URL + "doc_raf-begin.html"; + +// Disable logging for all the tests. Both the debugger server and frontend will +// be affected by this pref. +var gEnableLogging = Services.prefs.getBoolPref("devtools.debugger.log"); +Services.prefs.setBoolPref("devtools.debugger.log", false); + +// All tests are asynchronous. +waitForExplicitFinish(); + +var gToolEnabled = Services.prefs.getBoolPref("devtools.canvasdebugger.enabled"); + +flags.testing = true; + +registerCleanupFunction(() => { + info("finish() was called, cleaning up..."); + flags.testing = false; + Services.prefs.setBoolPref("devtools.debugger.log", gEnableLogging); + Services.prefs.setBoolPref("devtools.canvasdebugger.enabled", gToolEnabled); + + // Some of yhese tests use a lot of memory due to GL contexts, so force a GC + // to help fragmentation. + info("Forcing GC after canvas debugger test."); + Cu.forceGC(); +}); + +/** + * Call manually in tests that use frame script utils after initializing + * the shader editor. Call after init but before navigating to different pages. + */ +function loadFrameScripts() { + mm = gBrowser.selectedBrowser.messageManager; + mm.loadFrameScript(FRAME_SCRIPT_UTILS_URL, false); +} + +function addTab(aUrl, aWindow) { + info("Adding tab: " + aUrl); + + let deferred = promise.defer(); + let targetWindow = aWindow || window; + let targetBrowser = targetWindow.gBrowser; + + targetWindow.focus(); + let tab = targetBrowser.selectedTab = targetBrowser.addTab(aUrl); + let linkedBrowser = tab.linkedBrowser; + + BrowserTestUtils.browserLoaded(linkedBrowser) + .then(function () { + info("Tab added and finished loading: " + aUrl); + deferred.resolve(tab); + }); + + return deferred.promise; +} + +function removeTab(aTab, aWindow) { + info("Removing tab."); + + let deferred = promise.defer(); + let targetWindow = aWindow || window; + let targetBrowser = targetWindow.gBrowser; + let tabContainer = targetBrowser.tabContainer; + + tabContainer.addEventListener("TabClose", function onClose(aEvent) { + tabContainer.removeEventListener("TabClose", onClose, false); + info("Tab removed and finished closing."); + deferred.resolve(); + }, false); + + targetBrowser.removeTab(aTab); + return deferred.promise; +} + +function handleError(aError) { + ok(false, "Got an error: " + aError.message + "\n" + aError.stack); + finish(); +} + +var gRequiresWebGL = false; + +function ifTestingSupported() { + ok(false, "You need to define a 'ifTestingSupported' function."); + finish(); +} + +function ifTestingUnsupported() { + todo(false, "Skipping test because some required functionality isn't supported."); + finish(); +} + +function test() { + let generator = isTestingSupported() ? ifTestingSupported : ifTestingUnsupported; + Task.spawn(generator).then(null, handleError); +} + +function createCanvas() { + return document.createElementNS("http://www.w3.org/1999/xhtml", "canvas"); +} + +function isTestingSupported() { + if (!gRequiresWebGL) { + info("This test does not require WebGL support."); + return true; + } + + let supported = isWebGLSupported(document); + + info("This test requires WebGL support."); + info("Apparently, WebGL is" + (supported ? "" : " not") + " supported."); + return supported; +} + +function once(aTarget, aEventName, aUseCapture = false) { + info("Waiting for event: '" + aEventName + "' on " + aTarget + "."); + + let deferred = promise.defer(); + + for (let [add, remove] of [ + ["on", "off"], // Use event emitter before DOM events for consistency + ["addEventListener", "removeEventListener"], + ["addListener", "removeListener"] + ]) { + if ((add in aTarget) && (remove in aTarget)) { + aTarget[add](aEventName, function onEvent(...aArgs) { + info("Got event: '" + aEventName + "' on " + aTarget + "."); + aTarget[remove](aEventName, onEvent, aUseCapture); + deferred.resolve(...aArgs); + }, aUseCapture); + break; + } + } + + return deferred.promise; +} + +function waitForTick() { + let deferred = promise.defer(); + executeSoon(deferred.resolve); + return deferred.promise; +} + +function navigateInHistory(aTarget, aDirection, aWaitForTargetEvent = "navigate") { + executeSoon(() => content.history[aDirection]()); + return once(aTarget, aWaitForTargetEvent); +} + +function navigate(aTarget, aUrl, aWaitForTargetEvent = "navigate") { + executeSoon(() => aTarget.activeTab.navigateTo(aUrl)); + return once(aTarget, aWaitForTargetEvent); +} + +function reload(aTarget, aWaitForTargetEvent = "navigate") { + executeSoon(() => aTarget.activeTab.reload()); + return once(aTarget, aWaitForTargetEvent); +} + +function initServer() { + if (!DebuggerServer.initialized) { + DebuggerServer.init(); + DebuggerServer.addBrowserActors(); + } +} + +function initCallWatcherBackend(aUrl) { + info("Initializing a call watcher front."); + initServer(); + + return Task.spawn(function* () { + let tab = yield addTab(aUrl); + let target = TargetFactory.forTab(tab); + + yield target.makeRemote(); + + let front = new CallWatcherFront(target.client, target.form); + return { target, front }; + }); +} + +function initCanvasDebuggerBackend(aUrl) { + info("Initializing a canvas debugger front."); + initServer(); + + return Task.spawn(function* () { + let tab = yield addTab(aUrl); + let target = TargetFactory.forTab(tab); + + yield target.makeRemote(); + + let front = new CanvasFront(target.client, target.form); + return { target, front }; + }); +} + +function initCanvasDebuggerFrontend(aUrl) { + info("Initializing a canvas debugger pane."); + + return Task.spawn(function* () { + let tab = yield addTab(aUrl); + let target = TargetFactory.forTab(tab); + + yield target.makeRemote(); + + Services.prefs.setBoolPref("devtools.canvasdebugger.enabled", true); + let toolbox = yield gDevTools.showToolbox(target, "canvasdebugger"); + let panel = toolbox.getCurrentPanel(); + return { target, panel }; + }); +} + +function teardown({target}) { + info("Destroying the specified canvas debugger."); + + let {tab} = target; + return gDevTools.closeToolbox(target).then(() => { + removeTab(tab); + }); +} + +/** + * Takes a string `script` and evaluates it directly in the content + * in potentially a different process. + */ +function evalInDebuggee(script) { + let deferred = promise.defer(); + + if (!mm) { + throw new Error("`loadFrameScripts()` must be called when using MessageManager."); + } + + let id = generateUUID().toString(); + mm.sendAsyncMessage("devtools:test:eval", { script: script, id: id }); + mm.addMessageListener("devtools:test:eval:response", handler); + + function handler({ data }) { + if (id !== data.id) { + return; + } + + mm.removeMessageListener("devtools:test:eval:response", handler); + deferred.resolve(data.value); + } + + return deferred.promise; +} + +function getSourceActor(aSources, aURL) { + let item = aSources.getItemForAttachment(a => a.source.url === aURL); + return item ? item.value : null; +} + +/** + * Waits until a predicate returns true. + * + * @param function predicate + * Invoked once in a while until it returns true. + * @param number interval [optional] + * How often the predicate is invoked, in milliseconds. + */ +function* waitUntil(predicate, interval = 10) { + if (yield predicate()) { + return Promise.resolve(true); + } + let deferred = Promise.defer(); + setTimeout(function () { + waitUntil(predicate).then(() => deferred.resolve(true)); + }, interval); + return deferred.promise; +} |