test_SpecialPowersSandbox.js (5398B)
1 "use strict"; 2 3 /* eslint-disable @microsoft/sdl/no-insecure-url */ 4 5 const { XPCShellContentUtils } = ChromeUtils.importESModule( 6 "resource://testing-common/XPCShellContentUtils.sys.mjs" 7 ); 8 9 XPCShellContentUtils.init(this); 10 11 const HTML = String.raw`<!DOCTYPE html> 12 <html lang="en"> 13 <head> 14 <meta charset="UTF-8"> 15 <title></title> 16 </head> 17 <body> 18 <span id="span">Hello there.</span> 19 </body> 20 </html>`; 21 22 const server = XPCShellContentUtils.createHttpServer({ 23 hosts: ["example.com", "example.org"], 24 }); 25 26 server.registerPathHandler("/", (request, response) => { 27 response.setHeader("Content-Type", "text/html"); 28 response.write(HTML); 29 }); 30 /** 31 * Tests that the shared sandbox functionality for cross-process script 32 * execution works as expected. In particular, ensures that Assert methods 33 * report the correct diagnostics in the caller scope. 34 */ 35 36 let scope = this; 37 38 async function interceptDiagnostics(func) { 39 let originalRecord = scope.do_report_result; 40 try { 41 let diags = []; 42 43 scope.do_report_result = (passed, msg, stack) => { 44 diags.push({ passed, msg, stack }); 45 }; 46 47 await func(); 48 49 return diags; 50 } finally { 51 scope.do_report_result = originalRecord; 52 } 53 } 54 55 add_task(async function () { 56 const frameSrc = "http://example.com/"; 57 const subframeSrc = "http://example.org/"; 58 59 let page = await XPCShellContentUtils.loadContentPage(frameSrc, { 60 remote: true, 61 remoteSubframes: true, 62 }); 63 64 let { SpecialPowers, browsingContext } = page; 65 66 let expected = [ 67 [false, "Thing - 1 == 2"], 68 [true, "Hmm - 1 == 1"], 69 [true, "Yay. - true == true"], 70 [false, "Boo!. - false == true"], 71 [false, "Missing expected exception Rej_bad"], 72 [true, "Rej_ok"], 73 ]; 74 75 // Test that a representative variety of assertions work as expected, and 76 // trigger the expected calls to the harness's reporting function. 77 // 78 // Note: Assert.sys.mjs has its own tests, and defers all of its reporting to a 79 // single reporting function, so we don't need to test it comprehensively. We 80 // just need to make sure that the general functionality works as expected. 81 let tests = { 82 "SpecialPowers.spawn": () => { 83 return SpecialPowers.spawn(browsingContext, [], async () => { 84 Assert.equal(1, 2, "Thing"); 85 Assert.equal(1, 1, "Hmm"); 86 Assert.ok(true, "Yay."); 87 Assert.ok(false, "Boo!."); 88 await Assert.rejects(Promise.resolve(), /./, "Rej_bad"); 89 await Assert.rejects(Promise.reject(new Error("k")), /k/, "Rej_ok"); 90 }); 91 }, 92 "SpecialPowers.spawn-subframe": () => { 93 return SpecialPowers.spawn(browsingContext, [subframeSrc], async src => { 94 let subFrame = this.content.document.createElement("iframe"); 95 subFrame.src = src; 96 this.content.document.body.appendChild(subFrame); 97 98 await new Promise(resolve => { 99 subFrame.addEventListener("load", resolve, { once: true }); 100 }); 101 102 await SpecialPowers.spawn(subFrame, [], async () => { 103 Assert.equal(1, 2, "Thing"); 104 Assert.equal(1, 1, "Hmm"); 105 Assert.ok(true, "Yay."); 106 Assert.ok(false, "Boo!."); 107 await Assert.rejects(Promise.resolve(), /./, "Rej_bad"); 108 await Assert.rejects(Promise.reject(new Error("k")), /k/, "Rej_ok"); 109 }); 110 }); 111 }, 112 "SpecialPowers.spawnChrome": () => { 113 return SpecialPowers.spawnChrome([], async () => { 114 Assert.equal(1, 2, "Thing"); 115 Assert.equal(1, 1, "Hmm"); 116 Assert.ok(true, "Yay."); 117 Assert.ok(false, "Boo!."); 118 await Assert.rejects(Promise.resolve(), /./, "Rej_bad"); 119 await Assert.rejects(Promise.reject(new Error("k")), /k/, "Rej_ok"); 120 }); 121 }, 122 "SpecialPowers.loadChromeScript": async () => { 123 let script = SpecialPowers.loadChromeScript(() => { 124 /* eslint-env mozilla/chrome-script */ 125 const resultPromise = (async () => { 126 Assert.equal(1, 2, "Thing"); 127 Assert.equal(1, 1, "Hmm"); 128 Assert.ok(true, "Yay."); 129 Assert.ok(false, "Boo!."); 130 await Assert.rejects(Promise.resolve(), /./, "Rej_bad"); 131 await Assert.rejects(Promise.reject(new Error("k")), /k/, "Rej_ok"); 132 })(); 133 this.addMessageListener("ping", () => resultPromise); 134 }); 135 136 await script.sendQuery("ping"); 137 script.destroy(); 138 }, 139 }; 140 141 for (let [name, func] of Object.entries(tests)) { 142 info(`Starting task: ${name}`); 143 144 let diags = await interceptDiagnostics(func); 145 146 let results = diags.map(diag => [diag.passed, diag.msg]); 147 148 deepEqual(results, expected, "Got expected assertions"); 149 for (let { msg, stack } of diags) { 150 ok(stack, `Got stack for: ${msg}`); 151 // Unlike the html version of this test, this one does not include a "/" 152 // in front of the file name, because somehow Android only includes the 153 // file name, and not the fuller path. 154 let expectedFilenamePart = "test_SpecialPowersSandbox.js:"; 155 if (name === "SpecialPowers.loadChromeScript") { 156 // Unfortunately, the original file name is not included; 157 // the function name or a dummy value is used instead. 158 expectedFilenamePart = "loadChromeScript anonymous function>:"; 159 } 160 if (!stack.includes(expectedFilenamePart)) { 161 ok(false, `Stack does not contain ${expectedFilenamePart}: ${stack}`); 162 } 163 } 164 } 165 });