diff options
Diffstat (limited to 'devtools/shared/webconsole/test/common.js')
-rw-r--r-- | devtools/shared/webconsole/test/common.js | 345 |
1 files changed, 345 insertions, 0 deletions
diff --git a/devtools/shared/webconsole/test/common.js b/devtools/shared/webconsole/test/common.js new file mode 100644 index 000000000..b6649bc44 --- /dev/null +++ b/devtools/shared/webconsole/test/common.js @@ -0,0 +1,345 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim: set ft= javascript ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +var {classes: Cc, interfaces: Ci, utils: Cu} = Components; + +const XHTML_NS = "http://www.w3.org/1999/xhtml"; + +// This gives logging to stdout for tests +var {console} = Cu.import("resource://gre/modules/Console.jsm", {}); + +var {require} = Cu.import("resource://devtools/shared/Loader.jsm", {}); +var Services = require("Services"); +var WebConsoleUtils = require("devtools/client/webconsole/utils").Utils; +var {Task} = require("devtools/shared/task"); + +var ConsoleAPIStorage = Cc["@mozilla.org/consoleAPI-storage;1"] + .getService(Ci.nsIConsoleAPIStorage); +var {DebuggerServer} = require("devtools/server/main"); +var {DebuggerClient, ObjectClient} = require("devtools/shared/client/main"); + +var {ConsoleServiceListener, ConsoleAPIListener} = + require("devtools/server/actors/utils/webconsole-utils"); + +function initCommon() +{ + // Services.prefs.setBoolPref("devtools.debugger.log", true); +} + +function initDebuggerServer() +{ + if (!DebuggerServer.initialized) { + DebuggerServer.init(); + DebuggerServer.addBrowserActors(); + } + DebuggerServer.allowChromeProcess = true; +} + +function connectToDebugger(aCallback) +{ + initCommon(); + initDebuggerServer(); + + let transport = DebuggerServer.connectPipe(); + let client = new DebuggerClient(transport); + + let dbgState = { dbgClient: client }; + client.connect().then(response => aCallback(dbgState, response)); +} + +function attachConsole(aListeners, aCallback) { + _attachConsole(aListeners, aCallback); +} +function attachConsoleToTab(aListeners, aCallback) { + _attachConsole(aListeners, aCallback, true); +} +function attachConsoleToWorker(aListeners, aCallback) { + _attachConsole(aListeners, aCallback, true, true); +} + +function _attachConsole(aListeners, aCallback, aAttachToTab, aAttachToWorker) +{ + function _onAttachConsole(aState, aResponse, aWebConsoleClient) + { + if (aResponse.error) { + console.error("attachConsole failed: " + aResponse.error + " " + + aResponse.message); + } + + aState.client = aWebConsoleClient; + + aCallback(aState, aResponse); + } + + connectToDebugger(function _onConnect(aState, aResponse) { + if (aResponse.error) { + console.error("client.connect() failed: " + aResponse.error + " " + + aResponse.message); + aCallback(aState, aResponse); + return; + } + + if (aAttachToTab) { + aState.dbgClient.listTabs(function _onListTabs(aResponse) { + if (aResponse.error) { + console.error("listTabs failed: " + aResponse.error + " " + + aResponse.message); + aCallback(aState, aResponse); + return; + } + let tab = aResponse.tabs[aResponse.selected]; + aState.dbgClient.attachTab(tab.actor, function (response, tabClient) { + if (aAttachToWorker) { + let workerName = "console-test-worker.js#" + new Date().getTime(); + var worker = new Worker(workerName); + // Keep a strong reference to the Worker to avoid it being + // GCd during the test (bug 1237492). + aState._worker_ref = worker; + worker.addEventListener("message", function listener() { + worker.removeEventListener("message", listener); + tabClient.listWorkers(function (response) { + let worker = response.workers.filter(w => w.url == workerName)[0]; + if (!worker) { + console.error("listWorkers failed. Unable to find the " + + "worker actor\n"); + return; + } + tabClient.attachWorker(worker.actor, function (response, workerClient) { + if (!workerClient || response.error) { + console.error("attachWorker failed. No worker client or " + + " error: " + response.error); + return; + } + workerClient.attachThread({}, function (aResponse) { + aState.actor = workerClient.consoleActor; + aState.dbgClient.attachConsole(workerClient.consoleActor, aListeners, + _onAttachConsole.bind(null, aState)); + }); + }); + }); + }); + } else { + aState.actor = tab.consoleActor; + aState.dbgClient.attachConsole(tab.consoleActor, aListeners, + _onAttachConsole.bind(null, aState)); + } + }); + }); + } else { + aState.dbgClient.getProcess().then(response => { + aState.dbgClient.attachTab(response.form.actor, function () { + let consoleActor = response.form.consoleActor; + aState.actor = consoleActor; + aState.dbgClient.attachConsole(consoleActor, aListeners, + _onAttachConsole.bind(null, aState)); + }); + }); + } + }); +} + +function closeDebugger(aState, aCallback) +{ + aState.dbgClient.close().then(aCallback); + aState.dbgClient = null; + aState.client = null; +} + +function checkConsoleAPICalls(consoleCalls, expectedConsoleCalls) +{ + is(consoleCalls.length, expectedConsoleCalls.length, + "received correct number of console calls"); + expectedConsoleCalls.forEach(function (aMessage, aIndex) { + info("checking received console call #" + aIndex); + checkConsoleAPICall(consoleCalls[aIndex], expectedConsoleCalls[aIndex]); + }); +} + +function checkConsoleAPICall(aCall, aExpected) +{ + if (aExpected.level != "trace" && aExpected.arguments) { + is(aCall.arguments.length, aExpected.arguments.length, + "number of arguments"); + } + + checkObject(aCall, aExpected); +} + +function checkObject(aObject, aExpected) +{ + for (let name of Object.keys(aExpected)) + { + let expected = aExpected[name]; + let value = aObject[name]; + checkValue(name, value, expected); + } +} + +function checkValue(aName, aValue, aExpected) +{ + if (aExpected === null) { + ok(!aValue, "'" + aName + "' is null"); + } + else if (aValue === undefined) { + ok(false, "'" + aName + "' is undefined"); + } + else if (aValue === null) { + ok(false, "'" + aName + "' is null"); + } + else if (typeof aExpected == "string" || typeof aExpected == "number" || + typeof aExpected == "boolean") { + is(aValue, aExpected, "property '" + aName + "'"); + } + else if (aExpected instanceof RegExp) { + ok(aExpected.test(aValue), aName + ": " + aExpected + " matched " + aValue); + } + else if (Array.isArray(aExpected)) { + info("checking array for property '" + aName + "'"); + checkObject(aValue, aExpected); + } + else if (typeof aExpected == "object") { + info("checking object for property '" + aName + "'"); + checkObject(aValue, aExpected); + } +} + +function checkHeadersOrCookies(aArray, aExpected) +{ + let foundHeaders = {}; + + for (let elem of aArray) { + if (!(elem.name in aExpected)) { + continue; + } + foundHeaders[elem.name] = true; + info("checking value of header " + elem.name); + checkValue(elem.name, elem.value, aExpected[elem.name]); + } + + for (let header in aExpected) { + if (!(header in foundHeaders)) { + ok(false, header + " was not found"); + } + } +} + +function checkRawHeaders(aText, aExpected) +{ + let headers = aText.split(/\r\n|\n|\r/); + let arr = []; + for (let header of headers) { + let index = header.indexOf(": "); + if (index < 0) { + continue; + } + arr.push({ + name: header.substr(0, index), + value: header.substr(index + 2) + }); + } + + checkHeadersOrCookies(arr, aExpected); +} + +var gTestState = {}; + +function runTests(aTests, aEndCallback) +{ + function* driver() + { + let lastResult, sendToNext; + for (let i = 0; i < aTests.length; i++) { + gTestState.index = i; + let fn = aTests[i]; + info("will run test #" + i + ": " + fn.name); + lastResult = fn(sendToNext, lastResult); + sendToNext = yield lastResult; + } + yield aEndCallback(sendToNext, lastResult); + } + gTestState.driver = driver(); + return gTestState.driver.next(); +} + +function nextTest(aMessage) +{ + return gTestState.driver.next(aMessage); +} + +function withFrame(url) { + return new Promise(resolve => { + let iframe = document.createElement("iframe"); + iframe.onload = function () { + resolve(iframe); + }; + iframe.src = url; + document.body.appendChild(iframe); + }); +} + +function navigateFrame(iframe, url) { + return new Promise(resolve => { + iframe.onload = function () { + resolve(iframe); + }; + iframe.src = url; + }); +} + +function forceReloadFrame(iframe) { + return new Promise(resolve => { + iframe.onload = function () { + resolve(iframe); + }; + iframe.contentWindow.location.reload(true); + }); +} + +function withActiveServiceWorker(win, url, scope) { + let opts = {}; + if (scope) { + opts.scope = scope; + } + return win.navigator.serviceWorker.register(url, opts).then(swr => { + if (swr.active) { + return swr; + } + + // Unfortunately we can't just use navigator.serviceWorker.ready promise + // here. If the service worker is for a scope that does not cover the window + // then the ready promise will never resolve. Instead monitor the service + // workers state change events to determine when its activated. + return new Promise(resolve => { + let sw = swr.waiting || swr.installing; + sw.addEventListener("statechange", function stateHandler(evt) { + if (sw.state === "activated") { + sw.removeEventListener("statechange", stateHandler); + resolve(swr); + } + }); + }); + }); +} + +function messageServiceWorker(win, scope, message) { + return win.navigator.serviceWorker.getRegistration(scope).then(swr => { + return new Promise(resolve => { + win.navigator.serviceWorker.onmessage = evt => { + resolve(); + }; + let sw = swr.active || swr.waiting || swr.installing; + sw.postMessage({ type: "PING", message: message }); + }); + }); +} + +function unregisterServiceWorker(win) { + return win.navigator.serviceWorker.ready.then(swr => { + return swr.unregister(); + }); +} |