/* 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"; function ChromeTask_ChromeScript() { "use strict"; const { Assert: AssertCls } = ChromeUtils.importESModule( "resource://testing-common/Assert.sys.mjs" ); addMessageListener("chrome-task:spawn", async function (aData) { let id = aData.id; let source = aData.runnable || "()=>{}"; function getStack(aStack) { let frames = []; for (let frame = aStack; frame; frame = frame.caller) { frames.push(frame.filename + ":" + frame.name + ":" + frame.lineNumber); } return frames.join("\n"); } /* eslint-disable no-unused-vars */ var Assert = new AssertCls((err, message, stack) => { sendAsyncMessage("chrome-task:test-result", { id, condition: !err, name: err ? err.message : message, stack: getStack(err ? err.stack : stack), }); }); var ok = Assert.ok.bind(Assert); var is = Assert.equal.bind(Assert); var isnot = Assert.notEqual.bind(Assert); function todo(expr, name) { sendAsyncMessage("chrome-task:test-todo", { id, expr, name }); } function todo_is(a, b, name) { sendAsyncMessage("chrome-task:test-todo_is", { id, a, b, name }); } function info(name) { sendAsyncMessage("chrome-task:test-info", { id, name }); } /* eslint-enable no-unused-vars */ try { let sb = Cu.Sandbox(Services.scriptSecurityManager.getSystemPrincipal(), { sandboxPrototype: { __proto__: globalThis, Assert, ok, is, isnot, todo, todo_is, info, }, }); let runnable = Cu.evalInSandbox(`(() => (${source}))()`, sb); let result = await runnable.call(this, aData.arg); sendAsyncMessage("chrome-task:complete", { id, result, }); } catch (ex) { sendAsyncMessage("chrome-task:complete", { id, error: ex.toString(), }); } }); } /** * This object provides the public module functions. */ var ChromeTask = { /** * the ChromeScript if it has already been loaded. */ _chromeScript: null, /** * Mapping from message id to associated promise. */ _promises: new Map(), /** * Incrementing integer to generate unique message id. */ _messageID: 1, /** * Creates and starts a new task in the chrome process. * * @param arg A single serializable argument that will be passed to the * task when executed on the content process. * @param task * - A generator or function which will be serialized and sent to * the remote browser to be executed. Unlike Task.spawn, this * argument may not be an iterator as it will be serialized and * sent to the remote browser. * @return {Promise} * Resolves when the task finishes without errors. * @rejects An error message if execution fails. */ spawn: function ChromeTask_spawn(arg, task) { // Load the frame script if needed. let handle = ChromeTask._chromeScript; if (!handle) { handle = SpecialPowers.loadChromeScript(ChromeTask_ChromeScript); handle.addMessageListener("chrome-task:complete", ChromeTask.onComplete); handle.addMessageListener("chrome-task:test-result", ChromeTask.onResult); handle.addMessageListener("chrome-task:test-info", ChromeTask.onInfo); handle.addMessageListener("chrome-task:test-todo", ChromeTask.onTodo); handle.addMessageListener( "chrome-task:test-todo_is", ChromeTask.onTodoIs ); ChromeTask._chromeScript = handle; } let deferred = {}; deferred.promise = new Promise((resolve, reject) => { deferred.resolve = resolve; deferred.reject = reject; }); let id = ChromeTask._messageID++; ChromeTask._promises.set(id, deferred); handle.sendAsyncMessage("chrome-task:spawn", { id, runnable: task.toString(), arg, }); return deferred.promise; }, onComplete(aData) { let deferred = ChromeTask._promises.get(aData.id); ChromeTask._promises.delete(aData.id); if (aData.error) { deferred.reject(aData.error); } else { deferred.resolve(aData.result); } }, onResult(aData) { SimpleTest.record(aData.condition, aData.name); }, onInfo(aData) { SimpleTest.info(aData.name); }, onTodo(aData) { SimpleTest.todo(aData.expr, aData.name); }, onTodoIs(aData) { SimpleTest.todo_is(aData.a, aData.b, aData.name); }, };