ChromeTask.js (4909B)
1 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ 2 /* vim: set ts=2 et sw=2 tw=80 filetype=javascript: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this file, 5 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 "use strict"; 8 9 function ChromeTask_ChromeScript() { 10 /* eslint-env mozilla/chrome-script */ 11 12 "use strict"; 13 14 const { Assert: AssertCls } = ChromeUtils.importESModule( 15 "resource://testing-common/Assert.sys.mjs" 16 ); 17 18 addMessageListener("chrome-task:spawn", async function (aData) { 19 let id = aData.id; 20 let source = aData.runnable || "()=>{}"; 21 22 function getStack(aStack) { 23 let frames = []; 24 for (let frame = aStack; frame; frame = frame.caller) { 25 frames.push(frame.filename + ":" + frame.name + ":" + frame.lineNumber); 26 } 27 return frames.join("\n"); 28 } 29 30 /* eslint-disable no-unused-vars */ 31 var Assert = new AssertCls((err, message, stack) => { 32 sendAsyncMessage("chrome-task:test-result", { 33 id, 34 condition: !err, 35 name: err ? err.message : message, 36 stack: getStack(err ? err.stack : stack), 37 }); 38 }); 39 40 var ok = Assert.ok.bind(Assert); 41 var is = Assert.equal.bind(Assert); 42 var isnot = Assert.notEqual.bind(Assert); 43 44 function todo(expr, name) { 45 sendAsyncMessage("chrome-task:test-todo", { id, expr, name }); 46 } 47 48 function todo_is(a, b, name) { 49 sendAsyncMessage("chrome-task:test-todo_is", { id, a, b, name }); 50 } 51 52 function info(name) { 53 sendAsyncMessage("chrome-task:test-info", { id, name }); 54 } 55 /* eslint-enable no-unused-vars */ 56 57 try { 58 let sb = Cu.Sandbox(Services.scriptSecurityManager.getSystemPrincipal(), { 59 sandboxPrototype: { 60 __proto__: globalThis, 61 Assert, 62 ok, 63 is, 64 isnot, 65 todo, 66 todo_is, 67 info, 68 }, 69 }); 70 let runnable = Cu.evalInSandbox(`(() => (${source}))()`, sb); 71 let result = await runnable.call(this, aData.arg); 72 sendAsyncMessage("chrome-task:complete", { 73 id, 74 result, 75 }); 76 } catch (ex) { 77 sendAsyncMessage("chrome-task:complete", { 78 id, 79 error: ex.toString(), 80 }); 81 } 82 }); 83 } 84 85 /** 86 * This object provides the public module functions. 87 */ 88 var ChromeTask = { 89 /** 90 * the ChromeScript if it has already been loaded. 91 */ 92 _chromeScript: null, 93 94 /** 95 * Mapping from message id to associated promise. 96 */ 97 _promises: new Map(), 98 99 /** 100 * Incrementing integer to generate unique message id. 101 */ 102 _messageID: 1, 103 104 /** 105 * Creates and starts a new task in the chrome process. 106 * 107 * @param arg A single serializable argument that will be passed to the 108 * task when executed on the content process. 109 * @param task 110 * - A generator or function which will be serialized and sent to 111 * the remote browser to be executed. Unlike Task.spawn, this 112 * argument may not be an iterator as it will be serialized and 113 * sent to the remote browser. 114 * @return {Promise} 115 * Resolves when the task finishes without errors. 116 * @rejects An error message if execution fails. 117 */ 118 spawn: function ChromeTask_spawn(arg, task) { 119 // Load the frame script if needed. 120 let handle = ChromeTask._chromeScript; 121 if (!handle) { 122 handle = SpecialPowers.loadChromeScript(ChromeTask_ChromeScript); 123 handle.addMessageListener("chrome-task:complete", ChromeTask.onComplete); 124 handle.addMessageListener("chrome-task:test-result", ChromeTask.onResult); 125 handle.addMessageListener("chrome-task:test-info", ChromeTask.onInfo); 126 handle.addMessageListener("chrome-task:test-todo", ChromeTask.onTodo); 127 handle.addMessageListener( 128 "chrome-task:test-todo_is", 129 ChromeTask.onTodoIs 130 ); 131 ChromeTask._chromeScript = handle; 132 } 133 134 let deferred = {}; 135 deferred.promise = new Promise((resolve, reject) => { 136 deferred.resolve = resolve; 137 deferred.reject = reject; 138 }); 139 140 let id = ChromeTask._messageID++; 141 ChromeTask._promises.set(id, deferred); 142 143 handle.sendAsyncMessage("chrome-task:spawn", { 144 id, 145 runnable: task.toString(), 146 arg, 147 }); 148 149 return deferred.promise; 150 }, 151 152 onComplete(aData) { 153 let deferred = ChromeTask._promises.get(aData.id); 154 ChromeTask._promises.delete(aData.id); 155 156 if (aData.error) { 157 deferred.reject(aData.error); 158 } else { 159 deferred.resolve(aData.result); 160 } 161 }, 162 163 onResult(aData) { 164 SimpleTest.record(aData.condition, aData.name); 165 }, 166 167 onInfo(aData) { 168 SimpleTest.info(aData.name); 169 }, 170 171 onTodo(aData) { 172 SimpleTest.todo(aData.expr, aData.name); 173 }, 174 175 onTodoIs(aData) { 176 SimpleTest.todo_is(aData.a, aData.b, aData.name); 177 }, 178 };