mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-19 08:15:31 +00:00
Bug 1561150: Support test assertions in SpecialPowers.spawn sandboxes. r=nika
Differential Revision: https://phabricator.services.mozilla.com/D35747 --HG-- extra : rebase_source : 62aa469b15c2ebfb0de299c163b26ed68361ee1e extra : source : 0b3e2164f1283b639782b41b7fd640986d3feca5
This commit is contained in:
parent
b459f53a11
commit
3c304b4239
@ -22,6 +22,7 @@ support-files = file_SpecialPowersFrame1.html
|
|||||||
support-files =
|
support-files =
|
||||||
specialPowers_framescript.js
|
specialPowers_framescript.js
|
||||||
[test_SpecialPowersPushPrefEnv.html]
|
[test_SpecialPowersPushPrefEnv.html]
|
||||||
|
[test_SpecialPowersSandbox.html]
|
||||||
[test_SpecialPowersSpawn.html]
|
[test_SpecialPowersSpawn.html]
|
||||||
support-files = file_spawn.html
|
support-files = file_spawn.html
|
||||||
[test_SimpletestGetTestFileURL.html]
|
[test_SimpletestGetTestFileURL.html]
|
||||||
|
@ -0,0 +1,96 @@
|
|||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Test for SpecialPowers sandboxes</title>
|
||||||
|
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||||
|
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<iframe id="iframe"></iframe>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
/**
|
||||||
|
* Tests that the shared sandbox functionality for cross-process script
|
||||||
|
* execution works as expected. In particular, ensures that Assert methods
|
||||||
|
* report the correct diagnostics in the caller scope.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* eslint-disable prettier/prettier */
|
||||||
|
/* globals SpecialPowers, Assert */
|
||||||
|
|
||||||
|
async function interceptDiagnostics(func) {
|
||||||
|
let originalRecord = SimpleTest.record;
|
||||||
|
try {
|
||||||
|
let diags = [];
|
||||||
|
|
||||||
|
SimpleTest.record = (condition, name, diag, stack) => {
|
||||||
|
diags.push({condition, name, diag, stack});
|
||||||
|
};
|
||||||
|
|
||||||
|
await func();
|
||||||
|
|
||||||
|
return diags;
|
||||||
|
} finally {
|
||||||
|
SimpleTest.record = originalRecord;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
add_task(async function() {
|
||||||
|
let frame = document.getElementById("iframe");
|
||||||
|
frame.src = "https://example.com/tests/testing/mochitest/tests/Harness_sanity/file_spawn.html";
|
||||||
|
|
||||||
|
await new Promise(resolve => {
|
||||||
|
frame.addEventListener("load", resolve, {once: true});
|
||||||
|
});
|
||||||
|
|
||||||
|
let expected = [
|
||||||
|
[false, "Thing - 1 == 2", "got 1, expected 2 (operator ==)"],
|
||||||
|
[true, "Hmm - 1 == 1", undefined],
|
||||||
|
[true, "Yay. - true == true", undefined],
|
||||||
|
[false, "Boo!. - false == true", "got false, expected true (operator ==)"],
|
||||||
|
];
|
||||||
|
|
||||||
|
// Test that a representative variety of assertions work as expected, and
|
||||||
|
// trigger the expected calls to the harness's reporting function.
|
||||||
|
//
|
||||||
|
// Note: Assert.jsm has its own tests, and defers all of its reporting to a
|
||||||
|
// single reporting function, so we don't need to test it comprehensively. We
|
||||||
|
// just need to make sure that the general functionality works as expected.
|
||||||
|
let tests = {
|
||||||
|
"SpecialPowers.spawn": () => {
|
||||||
|
return SpecialPowers.spawn(frame, [], () => {
|
||||||
|
Assert.equal(1, 2, "Thing");
|
||||||
|
Assert.equal(1, 1, "Hmm");
|
||||||
|
Assert.ok(true, "Yay.");
|
||||||
|
Assert.ok(false, "Boo!.");
|
||||||
|
});
|
||||||
|
},
|
||||||
|
"SpecialPowers.loadChromeScript": async () => {
|
||||||
|
let script = SpecialPowers.loadChromeScript(() => {
|
||||||
|
this.addMessageListener("ping", () => "pong");
|
||||||
|
|
||||||
|
Assert.equal(1, 2, "Thing");
|
||||||
|
Assert.equal(1, 1, "Hmm");
|
||||||
|
Assert.ok(true, "Yay.");
|
||||||
|
Assert.ok(false, "Boo!.");
|
||||||
|
});
|
||||||
|
|
||||||
|
await script.sendQuery("ping");
|
||||||
|
script.destroy();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
for (let [name, func] of Object.entries(tests)) {
|
||||||
|
info(`Starting task: ${name}`);
|
||||||
|
|
||||||
|
let diags = await interceptDiagnostics(func);
|
||||||
|
|
||||||
|
let results = diags.map(diag => [diag.condition, diag.name, diag.diag]);
|
||||||
|
|
||||||
|
isDeeply(results, expected, "Got expected assertions");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -17,6 +17,8 @@ ChromeUtils.defineModuleGetter(this, "MockColorPicker",
|
|||||||
"resource://specialpowers/MockColorPicker.jsm");
|
"resource://specialpowers/MockColorPicker.jsm");
|
||||||
ChromeUtils.defineModuleGetter(this, "MockPermissionPrompt",
|
ChromeUtils.defineModuleGetter(this, "MockPermissionPrompt",
|
||||||
"resource://specialpowers/MockPermissionPrompt.jsm");
|
"resource://specialpowers/MockPermissionPrompt.jsm");
|
||||||
|
ChromeUtils.defineModuleGetter(this, "SpecialPowersSandbox",
|
||||||
|
"resource://specialpowers/SpecialPowersSandbox.jsm");
|
||||||
ChromeUtils.defineModuleGetter(this, "WrapPrivileged",
|
ChromeUtils.defineModuleGetter(this, "WrapPrivileged",
|
||||||
"resource://specialpowers/WrapPrivileged.jsm");
|
"resource://specialpowers/WrapPrivileged.jsm");
|
||||||
ChromeUtils.defineModuleGetter(this, "PrivateBrowsingUtils",
|
ChromeUtils.defineModuleGetter(this, "PrivateBrowsingUtils",
|
||||||
@ -130,6 +132,28 @@ class SpecialPowersAPI extends JSWindowActorChild {
|
|||||||
this._extensionListeners = null;
|
this._extensionListeners = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
receiveMessage(message) {
|
||||||
|
switch (message.name) {
|
||||||
|
case "Assert": {
|
||||||
|
// An assertion has been done in a mochitest chrome script
|
||||||
|
let {name, passed, stack, diag} = message.data;
|
||||||
|
|
||||||
|
let SimpleTest = (
|
||||||
|
this.contentWindow &&
|
||||||
|
this.contentWindow.wrappedJSObject.SimpleTest);
|
||||||
|
|
||||||
|
if (SimpleTest) {
|
||||||
|
SimpleTest.record(passed, name, diag, stack && stack.formattedStack);
|
||||||
|
} else {
|
||||||
|
// Well, this is unexpected.
|
||||||
|
dump(name + "\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Privileged object wrapping API
|
* Privileged object wrapping API
|
||||||
*
|
*
|
||||||
@ -337,7 +361,6 @@ class SpecialPowersAPI extends JSWindowActorChild {
|
|||||||
destroy: () => {
|
destroy: () => {
|
||||||
listeners = [];
|
listeners = [];
|
||||||
this._removeMessageListener("SPChromeScriptMessage", chromeScript);
|
this._removeMessageListener("SPChromeScriptMessage", chromeScript);
|
||||||
this._removeMessageListener("SPChromeScriptAssert", chromeScript);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
receiveMessage: (aMessage) => {
|
receiveMessage: (aMessage) => {
|
||||||
@ -356,56 +379,11 @@ class SpecialPowersAPI extends JSWindowActorChild {
|
|||||||
for (let listener of listeners.filter(o => o.name == name)) {
|
for (let listener of listeners.filter(o => o.name == name)) {
|
||||||
result = listener.listener(message);
|
result = listener.listener(message);
|
||||||
}
|
}
|
||||||
} else if (aMessage.name == "SPChromeScriptAssert") {
|
|
||||||
assert(aMessage.json);
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
this._addMessageListener("SPChromeScriptMessage", chromeScript);
|
this._addMessageListener("SPChromeScriptMessage", chromeScript);
|
||||||
this._addMessageListener("SPChromeScriptAssert", chromeScript);
|
|
||||||
|
|
||||||
let assert = json => {
|
|
||||||
// An assertion has been done in a mochitest chrome script
|
|
||||||
let {name, err, message, stack} = json;
|
|
||||||
|
|
||||||
// Try to fetch a test runner from the mochitest
|
|
||||||
// in order to properly log these assertions and notify
|
|
||||||
// all usefull log observers
|
|
||||||
let window = this.contentWindow;
|
|
||||||
let parentRunner, repr = o => o;
|
|
||||||
if (window) {
|
|
||||||
window = window.wrappedJSObject;
|
|
||||||
parentRunner = window.TestRunner;
|
|
||||||
if (window.repr) {
|
|
||||||
repr = window.repr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Craft a mochitest-like report string
|
|
||||||
var resultString = err ? "TEST-UNEXPECTED-FAIL" : "TEST-PASS";
|
|
||||||
var diagnostic =
|
|
||||||
message ? message :
|
|
||||||
("assertion @ " + stack.filename + ":" + stack.lineNumber);
|
|
||||||
if (err) {
|
|
||||||
diagnostic +=
|
|
||||||
" - got " + repr(err.actual) +
|
|
||||||
", expected " + repr(err.expected) +
|
|
||||||
" (operator " + err.operator + ")";
|
|
||||||
}
|
|
||||||
var msg = [resultString, name, diagnostic].join(" | ");
|
|
||||||
if (parentRunner) {
|
|
||||||
if (err) {
|
|
||||||
parentRunner.addFailedTest(name);
|
|
||||||
parentRunner.error(msg);
|
|
||||||
} else {
|
|
||||||
parentRunner.log(msg);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// When we are running only a single mochitest, there is no test runner
|
|
||||||
dump(msg + "\n");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return this.wrap(chromeScript);
|
return this.wrap(chromeScript);
|
||||||
}
|
}
|
||||||
@ -1236,6 +1214,10 @@ class SpecialPowersAPI extends JSWindowActorChild {
|
|||||||
* passed will be copied via structured clone, as will its return
|
* passed will be copied via structured clone, as will its return
|
||||||
* value.
|
* value.
|
||||||
*
|
*
|
||||||
|
* The sandbox also has access to an Assert object, as provided by
|
||||||
|
* Assert.jsm. Any assertion methods called before the task resolves
|
||||||
|
* will be relayed back to the test environment of the caller.
|
||||||
|
*
|
||||||
* @param {BrowsingContext or FrameLoaderOwner or WindowProxy} target
|
* @param {BrowsingContext or FrameLoaderOwner or WindowProxy} target
|
||||||
* The target in which to run the task. This may be any element
|
* The target in which to run the task. This may be any element
|
||||||
* which implements the FrameLoaderOwner interface (including
|
* which implements the FrameLoaderOwner interface (including
|
||||||
@ -1269,32 +1251,26 @@ class SpecialPowersAPI extends JSWindowActorChild {
|
|||||||
browsingContext = BrowsingContext.getFromWindow(target);
|
browsingContext = BrowsingContext.getFromWindow(target);
|
||||||
}
|
}
|
||||||
|
|
||||||
let {caller} = Components.stack;
|
|
||||||
return this.sendQuery("Spawn", {
|
return this.sendQuery("Spawn", {
|
||||||
browsingContext,
|
browsingContext,
|
||||||
args,
|
args,
|
||||||
task: String(task),
|
task: String(task),
|
||||||
caller: {
|
caller: SpecialPowersSandbox.getCallerInfo(Components.stack.caller),
|
||||||
filename: caller.filename,
|
|
||||||
lineNumber: caller.lineNumber,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_spawnTask(task, args, caller) {
|
_spawnTask(task, args, caller, taskId) {
|
||||||
let sb = Cu.Sandbox(Cu.getGlobalForObject({}),
|
let sb = new SpecialPowersSandbox(null, data => {
|
||||||
{wantGlobalProperties: ["ChromeUtils"]});
|
this.sendAsyncMessage("ProxiedAssert", {taskId, data});
|
||||||
|
});
|
||||||
|
|
||||||
sb.SpecialPowers = this;
|
sb.sandbox.SpecialPowers = this;
|
||||||
Object.defineProperty(sb, "content", {
|
Object.defineProperty(sb.sandbox, "content", {
|
||||||
get: () => { return this.contentWindow; },
|
get: () => { return this.contentWindow; },
|
||||||
enumerable: true,
|
enumerable: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
let func = Cu.evalInSandbox(`(${task})`, sb, undefined,
|
return sb.execute(task, args, caller);
|
||||||
caller.filename, caller.lineNumber);
|
|
||||||
|
|
||||||
return func(...args);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getFocusedElementForWindow(targetWindow, aDeep) {
|
getFocusedElementForWindow(targetWindow, aDeep) {
|
||||||
|
@ -14,6 +14,7 @@ XPCOMUtils.defineLazyModuleGetters(this, {
|
|||||||
ExtensionTestCommon: "resource://testing-common/ExtensionTestCommon.jsm",
|
ExtensionTestCommon: "resource://testing-common/ExtensionTestCommon.jsm",
|
||||||
PerTestCoverageUtils: "resource://testing-common/PerTestCoverageUtils.jsm",
|
PerTestCoverageUtils: "resource://testing-common/PerTestCoverageUtils.jsm",
|
||||||
ServiceWorkerCleanUp: "resource://gre/modules/ServiceWorkerCleanUp.jsm",
|
ServiceWorkerCleanUp: "resource://gre/modules/ServiceWorkerCleanUp.jsm",
|
||||||
|
SpecialPowersSandbox: "resource://specialpowers/SpecialPowersSandbox.jsm",
|
||||||
});
|
});
|
||||||
|
|
||||||
class SpecialPowersError extends Error {
|
class SpecialPowersError extends Error {
|
||||||
@ -99,6 +100,10 @@ function doPrefEnvOp(fn) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Supplies the unique IDs for tasks created by SpecialPowers.spawn(),
|
||||||
|
// used to bounce assertion messages back down to the correct child.
|
||||||
|
let nextTaskID = 1;
|
||||||
|
|
||||||
class SpecialPowersAPIParent extends JSWindowActorParent {
|
class SpecialPowersAPIParent extends JSWindowActorParent {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
@ -106,6 +111,7 @@ class SpecialPowersAPIParent extends JSWindowActorParent {
|
|||||||
this._processCrashObserversRegistered = false;
|
this._processCrashObserversRegistered = false;
|
||||||
this._chromeScriptListeners = [];
|
this._chromeScriptListeners = [];
|
||||||
this._extensions = new Map();
|
this._extensions = new Map();
|
||||||
|
this._taskActors = new Map();
|
||||||
}
|
}
|
||||||
|
|
||||||
_observe(aSubject, aTopic, aData) {
|
_observe(aSubject, aTopic, aData) {
|
||||||
@ -564,50 +570,35 @@ class SpecialPowersAPIParent extends JSWindowActorParent {
|
|||||||
// Setup a chrome sandbox that has access to sendAsyncMessage
|
// Setup a chrome sandbox that has access to sendAsyncMessage
|
||||||
// and {add,remove}MessageListener in order to communicate with
|
// and {add,remove}MessageListener in order to communicate with
|
||||||
// the mochitest.
|
// the mochitest.
|
||||||
let systemPrincipal = Services.scriptSecurityManager.getSystemPrincipal();
|
let sb = new SpecialPowersSandbox(
|
||||||
let sandboxOptions = Object.assign({wantGlobalProperties: ["ChromeUtils"]},
|
scriptName,
|
||||||
aMessage.json.sandboxOptions);
|
data => {
|
||||||
let sb = Cu.Sandbox(systemPrincipal, sandboxOptions);
|
this.sendAsyncMessage("Assert", data);
|
||||||
sb.sendAsyncMessage = (name, message) => {
|
|
||||||
this.sendAsyncMessage("SPChromeScriptMessage",
|
|
||||||
{ id, name, message });
|
|
||||||
};
|
|
||||||
sb.addMessageListener = (name, listener) => {
|
|
||||||
this._chromeScriptListeners.push({ id, name, listener });
|
|
||||||
};
|
|
||||||
sb.removeMessageListener = (name, listener) => {
|
|
||||||
let index = this._chromeScriptListeners.findIndex(function(obj) {
|
|
||||||
return obj.id == id && obj.name == name && obj.listener == listener;
|
|
||||||
});
|
|
||||||
if (index >= 0) {
|
|
||||||
this._chromeScriptListeners.splice(index, 1);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
sb.actorParent = this.manager;
|
|
||||||
|
|
||||||
// Also expose assertion functions
|
|
||||||
let reporter = (err, message, stack) => {
|
|
||||||
// Pipe assertions back to parent process
|
|
||||||
this.sendAsyncMessage("SPChromeScriptAssert",
|
|
||||||
{ id, name: scriptName, err, message,
|
|
||||||
stack });
|
|
||||||
};
|
|
||||||
Object.defineProperty(sb, "assert", {
|
|
||||||
get() {
|
|
||||||
let scope = Cu.createObjectIn(sb);
|
|
||||||
Services.scriptloader.loadSubScript("resource://specialpowers/Assert.jsm",
|
|
||||||
scope);
|
|
||||||
|
|
||||||
let assert = new scope.Assert(reporter);
|
|
||||||
delete sb.assert;
|
|
||||||
return sb.assert = assert;
|
|
||||||
},
|
},
|
||||||
configurable: true,
|
aMessage.data);
|
||||||
|
|
||||||
|
Object.assign(sb.sandbox, {
|
||||||
|
sendAsyncMessage: (name, message) => {
|
||||||
|
this.sendAsyncMessage("SPChromeScriptMessage",
|
||||||
|
{ id, name, message });
|
||||||
|
},
|
||||||
|
addMessageListener: (name, listener) => {
|
||||||
|
this._chromeScriptListeners.push({ id, name, listener });
|
||||||
|
},
|
||||||
|
removeMessageListener: (name, listener) => {
|
||||||
|
let index = this._chromeScriptListeners.findIndex(function(obj) {
|
||||||
|
return obj.id == id && obj.name == name && obj.listener == listener;
|
||||||
|
});
|
||||||
|
if (index >= 0) {
|
||||||
|
this._chromeScriptListeners.splice(index, 1);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
actorParent: this.manager,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Evaluate the chrome script
|
// Evaluate the chrome script
|
||||||
try {
|
try {
|
||||||
Cu.evalInSandbox(jsScript, sb, "1.8", scriptName, 1);
|
Cu.evalInSandbox(jsScript, sb.sandbox, "1.8", scriptName, 1);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw new SpecialPowersError(
|
throw new SpecialPowersError(
|
||||||
"Error while executing chrome script '" + scriptName + "':\n" +
|
"Error while executing chrome script '" + scriptName + "':\n" +
|
||||||
@ -772,7 +763,21 @@ class SpecialPowersAPIParent extends JSWindowActorParent {
|
|||||||
let {browsingContext, task, args, caller} = aMessage.data;
|
let {browsingContext, task, args, caller} = aMessage.data;
|
||||||
|
|
||||||
let spParent = browsingContext.currentWindowGlobal.getActor("SpecialPowers");
|
let spParent = browsingContext.currentWindowGlobal.getActor("SpecialPowers");
|
||||||
return spParent.sendQuery("Spawn", {task, args, caller});
|
|
||||||
|
let taskId = nextTaskID++;
|
||||||
|
spParent._taskActors.set(taskId, this);
|
||||||
|
|
||||||
|
return spParent.sendQuery("Spawn", {task, args, caller, taskId}).finally(() => {
|
||||||
|
spParent._taskActors.delete(taskId);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
case "ProxiedAssert": {
|
||||||
|
let {taskId, data} = aMessage.data;
|
||||||
|
let actor = this._taskActors.get(taskId);
|
||||||
|
|
||||||
|
actor.sendAsyncMessage("Assert", data);
|
||||||
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
case "SPRemoveAllServiceWorkers": {
|
case "SPRemoveAllServiceWorkers": {
|
||||||
|
@ -122,8 +122,11 @@ class SpecialPowersChild extends SpecialPowersAPI {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case "Spawn":
|
case "Spawn":
|
||||||
let {task, args, caller} = aMessage.data;
|
let {task, args, caller, taskId} = aMessage.data;
|
||||||
return this._spawnTask(task, args, caller);
|
return this._spawnTask(task, args, caller, taskId);
|
||||||
|
|
||||||
|
default:
|
||||||
|
return super.receiveMessage(aMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
71
testing/specialpowers/content/SpecialPowersSandbox.jsm
Normal file
71
testing/specialpowers/content/SpecialPowersSandbox.jsm
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
/* 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/. */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This modules handles creating and provisioning Sandboxes for
|
||||||
|
* executing cross-process code from SpecialPowers. This allows all such
|
||||||
|
* sandboxes to have a similar environment, and in particular allows
|
||||||
|
* them to run test assertions in the target process and propagate
|
||||||
|
* results back to the caller.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var EXPORTED_SYMBOLS = ["SpecialPowersSandbox"];
|
||||||
|
|
||||||
|
ChromeUtils.defineModuleGetter(this, "Assert",
|
||||||
|
"resource://testing-common/Assert.jsm");
|
||||||
|
|
||||||
|
class SpecialPowersSandbox {
|
||||||
|
constructor(name, reportCallback, opts = {}) {
|
||||||
|
this.name = name;
|
||||||
|
this.reportCallback = reportCallback;
|
||||||
|
|
||||||
|
this._Assert = null;
|
||||||
|
|
||||||
|
this.sandbox = Cu.Sandbox(Cu.getGlobalForObject({}),
|
||||||
|
Object.assign({wantGlobalProperties: ["ChromeUtils"]},
|
||||||
|
opts.sandboxOptions));
|
||||||
|
|
||||||
|
for (let prop of ["assert", "Assert"]) {
|
||||||
|
Object.defineProperty(this.sandbox, prop, {
|
||||||
|
get: () => {
|
||||||
|
return this.Assert;
|
||||||
|
},
|
||||||
|
enumerable: true,
|
||||||
|
configurable: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static getCallerInfo(frame) {
|
||||||
|
return {
|
||||||
|
filename: frame.filename,
|
||||||
|
lineNumber: frame.lineNumber,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
get Assert() {
|
||||||
|
if (!this._Assert) {
|
||||||
|
this._Assert = new Assert((err, message, stack) => {
|
||||||
|
this.report(err, message, stack);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return this._Assert;
|
||||||
|
}
|
||||||
|
|
||||||
|
report(err, name, stack) {
|
||||||
|
let diag;
|
||||||
|
if (err) {
|
||||||
|
diag = `got ${uneval(err.actual)}, expected ${uneval(err.expected)} ` +
|
||||||
|
`(operator ${err.operator})`;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.reportCallback({name, diag, passed: !err, stack});
|
||||||
|
}
|
||||||
|
|
||||||
|
execute(task, args, caller) {
|
||||||
|
let func = Cu.evalInSandbox(`(${task})`, this.sandbox, undefined,
|
||||||
|
caller.filename, caller.lineNumber);
|
||||||
|
return func(...args);
|
||||||
|
}
|
||||||
|
}
|
@ -23,6 +23,7 @@ FINAL_TARGET_FILES.content += [
|
|||||||
'content/SpecialPowersAPIParent.jsm',
|
'content/SpecialPowersAPIParent.jsm',
|
||||||
'content/SpecialPowersChild.jsm',
|
'content/SpecialPowersChild.jsm',
|
||||||
'content/SpecialPowersParent.jsm',
|
'content/SpecialPowersParent.jsm',
|
||||||
|
'content/SpecialPowersSandbox.jsm',
|
||||||
'content/WrapPrivileged.jsm',
|
'content/WrapPrivileged.jsm',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -163,6 +163,10 @@ add_task(async function test2() {
|
|||||||
is(result.username, "xhruser2", "Checking for username");
|
is(result.username, "xhruser2", "Checking for username");
|
||||||
is(result.password, "xhrpass2", "Checking for password");
|
is(result.password, "xhrpass2", "Checking for password");
|
||||||
|
|
||||||
|
// Wait for the assert from the parent script to run and send back its reply,
|
||||||
|
// so it's processed before the test ends.
|
||||||
|
await SpecialPowers.executeAfterFlushingMessageQueue();
|
||||||
|
|
||||||
newWin.close();
|
newWin.close();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
Loading…
Reference in New Issue
Block a user