166 lines
6.6 KiB
JavaScript
166 lines
6.6 KiB
JavaScript
/* vim: set ts=2 et sw=2 tw=80: */
|
|
/* Any copyright is dedicated to the Public Domain.
|
|
http://creativecommons.org/publicdomain/zero/1.0/ */
|
|
|
|
// This test asserts that the new debugger works from the browser toolbox process
|
|
// Its pass a big piece of Javascript string to the browser toolbox process via
|
|
// MOZ_TOOLBOX_TEST_SCRIPT env variable. It does that as test resources fetched from
|
|
// chrome://mochitests/ package isn't available from browser toolbox process.
|
|
|
|
// There are shutdown issues for which multiple rejections are left uncaught.
|
|
// See bug 1018184 for resolving these issues.
|
|
const { PromiseTestUtils } = scopedCuImport("resource://testing-common/PromiseTestUtils.jsm");
|
|
PromiseTestUtils.whitelistRejectionsGlobally(/File closed/);
|
|
|
|
// On debug test runner, it takes about 50s to run the test.
|
|
requestLongerTimeout(4);
|
|
|
|
const { fetch } = require("devtools/shared/DevToolsUtils");
|
|
|
|
const debuggerHeadURL = CHROME_URL_ROOT + "../../debugger/new/test/mochitest/head.js";
|
|
const helpersURL = CHROME_URL_ROOT + "../../debugger/new/test/mochitest/helpers.js";
|
|
const testScriptURL = CHROME_URL_ROOT + "test_browser_toolbox_debugger.js";
|
|
|
|
add_task(async function runTest() {
|
|
await new Promise(done => {
|
|
const options = {"set": [
|
|
["devtools.debugger.prompt-connection", false],
|
|
["devtools.debugger.remote-enabled", true],
|
|
["devtools.chrome.enabled", true],
|
|
// Test-only pref to allow passing `testScript` argument to the browser
|
|
// toolbox
|
|
["devtools.browser-toolbox.allow-unsafe-script", true],
|
|
// On debug test runner, it takes more than the default time (20s)
|
|
// to get a initialized console
|
|
["devtools.debugger.remote-timeout", 120000]
|
|
]};
|
|
SpecialPowers.pushPrefEnv(options, done);
|
|
});
|
|
|
|
const s = Cu.Sandbox("http://mozilla.org");
|
|
|
|
// Use a unique id for the fake script name in order to be able to run
|
|
// this test more than once. That's because the Sandbox is not immediately
|
|
// destroyed and so the debugger would display only one file but not necessarily
|
|
// connected to the latest sandbox.
|
|
const id = new Date().getTime();
|
|
|
|
// Pass a fake URL to evalInSandbox. If we just pass a filename,
|
|
// Debugger is going to fail and only display root folder (`/`) listing.
|
|
// But it won't try to fetch this url and use sandbox content as expected.
|
|
const testUrl = `http://mozilla.org/browser-toolbox-test-${id}.js`;
|
|
Cu.evalInSandbox("(" + function() {
|
|
this.plop = function plop() {
|
|
return 1;
|
|
};
|
|
} + ").call(this)", s, "1.8", testUrl, 0);
|
|
|
|
// Execute the function every second in order to trigger the breakpoint
|
|
const interval = setInterval(s.plop, 1000);
|
|
|
|
// Be careful, this JS function is going to be executed in the browser toolbox,
|
|
// which lives in another process. So do not try to use any scope variable!
|
|
const env = Cc["@mozilla.org/process/environment;1"]
|
|
.getService(Ci.nsIEnvironment);
|
|
// First inject a very minimal head, with simplest assertion methods
|
|
// and very common globals
|
|
/* eslint-disable no-unused-vars */
|
|
const testHead = (function() {
|
|
const info = msg => dump(msg + "\n");
|
|
const is = (a, b, description) => {
|
|
let msg = "'" + JSON.stringify(a) + "' is equal to '" + JSON.stringify(b) + "'";
|
|
if (description) {
|
|
msg += " - " + description;
|
|
}
|
|
if (a !== b) {
|
|
msg = "FAILURE: " + msg;
|
|
dump(msg + "\n");
|
|
throw new Error(msg);
|
|
} else {
|
|
msg = "SUCCESS: " + msg;
|
|
dump(msg + "\n");
|
|
}
|
|
};
|
|
const ok = (a, description) => {
|
|
let msg = "'" + JSON.stringify(a) + "' is true";
|
|
if (description) {
|
|
msg += " - " + description;
|
|
}
|
|
if (!a) {
|
|
msg = "FAILURE: " + msg;
|
|
dump(msg + "\n");
|
|
throw new Error(msg);
|
|
} else {
|
|
msg = "SUCCESS: " + msg;
|
|
dump(msg + "\n");
|
|
}
|
|
};
|
|
|
|
const registerCleanupFunction = () => {};
|
|
|
|
const { require } = ChromeUtils.import("resource://devtools/shared/Loader.jsm", {});
|
|
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm", {});
|
|
|
|
// Copied from shared-head.js:
|
|
// test_browser_toolbox_debugger.js uses waitForPaused, which relies on waitUntil
|
|
// which is normally provided by shared-head.js
|
|
const { setTimeout } = ChromeUtils.import("resource://gre/modules/Timer.jsm", {});
|
|
function waitUntil(predicate, interval = 10) {
|
|
if (predicate()) {
|
|
return Promise.resolve(true);
|
|
}
|
|
return new Promise(resolve => {
|
|
// TODO: fixme.
|
|
// eslint-disable-next-line mozilla/no-arbitrary-setTimeout
|
|
setTimeout(function() {
|
|
waitUntil(predicate, interval).then(() => resolve(true));
|
|
}, interval);
|
|
});
|
|
}
|
|
}).toSource().replace(/^\(function\(\) \{|\}\)$/g, "");
|
|
/* eslint-enable no-unused-vars */
|
|
// Stringify testHead's function and remove `(function {` prefix and `})` suffix
|
|
// to ensure inner symbols gets exposed to next pieces of code
|
|
// Then inject new debugger head file
|
|
let { content: debuggerHead } = await fetch(debuggerHeadURL);
|
|
|
|
// We remove its import of shared-head, which isn't available in browser toolbox process
|
|
// And isn't needed thanks to testHead's symbols
|
|
debuggerHead = debuggerHead.replace(/Services.scriptloader.loadSubScript[^\)]*\);/g, "");
|
|
|
|
// Also include the debugger helpers which are separated from debugger's head to be
|
|
// reused in other modules.
|
|
const { content: debuggerHelpers } = await fetch(helpersURL);
|
|
debuggerHead = debuggerHead + debuggerHelpers;
|
|
|
|
// Finally, fetch the debugger test script that is going to be execute in the browser
|
|
// toolbox process
|
|
const testScript = (await fetch(testScriptURL)).content;
|
|
const source =
|
|
"try { let testUrl = \"" + testUrl + "\";" + testHead + debuggerHead + testScript + "} catch (e) {" +
|
|
" dump('Exception: '+ e + ' at ' + e.fileName + ':' + " +
|
|
" e.lineNumber + '\\nStack: ' + e.stack + '\\n');" +
|
|
"}";
|
|
env.set("MOZ_TOOLBOX_TEST_SCRIPT", source);
|
|
registerCleanupFunction(() => {
|
|
env.set("MOZ_TOOLBOX_TEST_SCRIPT", "");
|
|
});
|
|
|
|
const { BrowserToolboxProcess } = ChromeUtils.import("resource://devtools/client/framework/ToolboxProcess.jsm", {});
|
|
// Use two promises, one for each BrowserToolboxProcess.init callback
|
|
// arguments, to ensure that we wait for toolbox run and close events.
|
|
let closePromise;
|
|
await new Promise(onRun => {
|
|
closePromise = new Promise(onClose => {
|
|
info("Opening the browser toolbox\n");
|
|
BrowserToolboxProcess.init(onClose, onRun);
|
|
});
|
|
});
|
|
ok(true, "Browser toolbox started\n");
|
|
|
|
await closePromise;
|
|
ok(true, "Browser toolbox process just closed");
|
|
|
|
clearInterval(interval);
|
|
});
|