test_ext_tabs_sendMessage.html (11093B)
1 <!DOCTYPE HTML> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <title>Tabs sendMessage Test</title> 6 <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> 7 <script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script> 8 <script type="text/javascript" src="head.js"></script> 9 <link rel="stylesheet" href="/tests/SimpleTest/test.css"/> 10 </head> 11 <body> 12 13 <script type="text/javascript"> 14 "use strict"; 15 16 add_task(async function tabsSendMessageReply() { 17 await SpecialPowers.pushPrefEnv({ 18 set: [["dom.security.https_first", false]], 19 }); 20 const extension = ExtensionTestUtils.loadExtension({ 21 manifest: { 22 "permissions": ["tabs"], 23 "content_scripts": [{ 24 "matches": ["http://example.com/"], 25 "js": ["content-script.js"], 26 "run_at": "document_start", 27 }], 28 }, 29 30 background: async function() { 31 // eslint-disable-next-line prefer-const 32 let firstTab; 33 const promiseResponse = new Promise(resolve => { 34 browser.runtime.onMessage.addListener((msg, sender) => { 35 if (msg == "content-script-ready") { 36 const tabId = sender.tab.id; 37 38 Promise.all([ 39 promiseResponse, 40 41 browser.tabs.sendMessage(tabId, "respond-now"), 42 browser.tabs.sendMessage(tabId, "respond-now-2"), 43 new Promise(resolve => browser.tabs.sendMessage(tabId, "respond-soon", resolve)), 44 browser.tabs.sendMessage(tabId, "respond-promise"), 45 browser.tabs.sendMessage(tabId, "respond-promise-false"), 46 browser.tabs.sendMessage(tabId, "respond-false"), 47 browser.tabs.sendMessage(tabId, "respond-never"), 48 new Promise(resolve => { 49 browser.runtime.sendMessage("respond-never", response => { resolve(response); }); 50 }), 51 52 browser.tabs.sendMessage(tabId, "respond-error").catch(error => Promise.resolve({error})), 53 browser.tabs.sendMessage(tabId, "throw-error").catch(error => Promise.resolve({error})), 54 55 browser.tabs.sendMessage(tabId, "respond-uncloneable").catch(error => Promise.resolve({ error })), 56 browser.tabs.sendMessage(tabId, "reject-uncloneable").catch(error => Promise.resolve({ error })), 57 browser.tabs.sendMessage(tabId, "reject-undefined").catch(error => Promise.resolve({ error })), 58 browser.tabs.sendMessage(tabId, "throw-undefined").catch(error => Promise.resolve({ error })), 59 60 browser.tabs.sendMessage(firstTab, "no-listener").catch(error => Promise.resolve({error})), 61 ]).then(([response, respondNow, respondNow2, respondSoon, respondPromise, respondPromiseFalse, respondFalse, respondNever, respondNever2, respondError, throwError, respondUncloneable, rejectUncloneable, rejectUndefined, throwUndefined, noListener]) => { 62 browser.test.assertEq("expected-response", response, "Content script got the expected response"); 63 64 browser.test.assertEq("respond-now", respondNow, "Got the expected immediate response"); 65 browser.test.assertEq("respond-now-2", respondNow2, "Got the expected immediate response from the second listener"); 66 browser.test.assertEq("respond-soon", respondSoon, "Got the expected delayed response"); 67 browser.test.assertEq("respond-promise", respondPromise, "Got the expected promise response"); 68 browser.test.assertEq(false, respondPromiseFalse, "Got the expected false value as a promise result"); 69 browser.test.assertEq(undefined, respondFalse, "Got the expected no-response when onMessage returns false"); 70 browser.test.assertEq(undefined, respondNever, "Got the expected no-response resolution"); 71 browser.test.assertEq(undefined, respondNever2, "Got the expected no-response resolution"); 72 73 browser.test.assertEq("respond-error", respondError.error.message, "Got the expected error response"); 74 browser.test.assertEq("throw-error", throwError.error.message, "Got the expected thrown error response"); 75 76 browser.test.assertEq("Could not establish connection. Receiving end does not exist.", respondUncloneable.error.message, "An uncloneable response should be ignored"); 77 browser.test.assertEq("An unexpected error occurred", rejectUncloneable.error.message, "Got the expected error for a rejection with an uncloneable value"); 78 browser.test.assertEq("An unexpected error occurred", rejectUndefined.error.message, "Got the expected error for a void rejection"); 79 browser.test.assertEq("An unexpected error occurred", throwUndefined.error.message, "Got the expected error for a void throw"); 80 81 browser.test.assertEq("Could not establish connection. Receiving end does not exist.", 82 noListener.error.message, 83 "Got the expected no listener response"); 84 85 return browser.tabs.remove(tabId); 86 }).then(() => { 87 browser.test.notifyPass("sendMessage"); 88 }); 89 90 return Promise.resolve("expected-response"); 91 } else if (msg[0] == "got-response") { 92 resolve(msg[1]); 93 } 94 }); 95 }); 96 97 const tabs = await browser.tabs.query({currentWindow: true, active: true}); 98 firstTab = tabs[0].id; 99 browser.tabs.create({url: "http://example.com/"}); 100 }, 101 102 files: { 103 "content-script.js": async function() { 104 browser.runtime.onMessage.addListener((msg, sender, respond) => { 105 if (msg == "respond-now") { 106 respond(msg); 107 } else if (msg == "respond-soon") { 108 setTimeout(() => { respond(msg); }, 0); 109 return true; 110 } else if (msg == "respond-promise") { 111 return Promise.resolve(msg); 112 } else if (msg == "respond-promise-false") { 113 return Promise.resolve(false); 114 } else if (msg == "respond-false") { 115 // return false means that respond() is not expected to be called. 116 setTimeout(() => respond("should be ignored")); 117 return false; 118 } else if (msg == "respond-never") { 119 return undefined; 120 } else if (msg == "respond-error") { 121 return Promise.reject(new Error(msg)); 122 } else if (msg === "respond-uncloneable") { 123 return Promise.resolve(window); 124 } else if (msg === "reject-uncloneable") { 125 return Promise.reject(window); 126 } else if (msg == "reject-undefined") { 127 return Promise.reject(); 128 } else if (msg == "throw-undefined") { 129 throw undefined; // eslint-disable-line no-throw-literal 130 } else if (msg == "throw-error") { 131 throw new Error(msg); 132 } 133 }); 134 135 browser.runtime.onMessage.addListener((msg, sender, respond) => { 136 if (msg == "respond-now") { 137 respond("hello"); 138 } else if (msg == "respond-now-2") { 139 respond(msg); 140 } 141 }); 142 143 const response = await browser.runtime.sendMessage("content-script-ready"); 144 browser.runtime.sendMessage(["got-response", response]); 145 }, 146 }, 147 }); 148 149 await extension.startup(); 150 151 await extension.awaitFinish("sendMessage"); 152 153 await extension.unload(); 154 }); 155 156 157 add_task(async function tabsSendHidden() { 158 await SpecialPowers.pushPrefEnv({ 159 set: [["dom.security.https_first", false]], 160 }); 161 const extension = ExtensionTestUtils.loadExtension({ 162 manifest: { 163 "permissions": ["tabs"], 164 "content_scripts": [{ 165 "matches": ["http://example.com/content*"], 166 "js": ["content-script.js"], 167 "run_at": "document_start", 168 }], 169 }, 170 171 background: async function() { 172 let resolveContent; 173 browser.runtime.onMessage.addListener((msg) => { 174 if (msg[0] == "content-ready") { 175 resolveContent(msg[1]); 176 } 177 }); 178 179 const awaitContent = url => { 180 return new Promise(resolve => { 181 resolveContent = resolve; 182 }).then(result => { 183 browser.test.assertEq(url, result, "Expected content script URL"); 184 }); 185 }; 186 187 try { 188 const URL1 = "http://example.com/content1.html"; 189 const URL2 = "http://example.com/content2.html"; 190 191 const tab = await browser.tabs.create({url: URL1}); 192 await awaitContent(URL1); 193 194 let url = await browser.tabs.sendMessage(tab.id, URL1); 195 browser.test.assertEq(URL1, url, "Should get response from expected content window"); 196 197 await browser.tabs.update(tab.id, {url: URL2}); 198 await awaitContent(URL2); 199 200 url = await browser.tabs.sendMessage(tab.id, URL2); 201 browser.test.assertEq(URL2, url, "Should get response from expected content window"); 202 203 // Repeat once just to be sure the first message was processed by all 204 // listeners before we exit the test. 205 url = await browser.tabs.sendMessage(tab.id, URL2); 206 browser.test.assertEq(URL2, url, "Should get response from expected content window"); 207 208 await browser.tabs.remove(tab.id); 209 210 browser.test.notifyPass("contentscript-bfcache-window"); 211 } catch (error) { 212 browser.test.fail(`Error: ${error} :: ${error.stack}`); 213 browser.test.notifyFail("contentscript-bfcache-window"); 214 } 215 }, 216 217 files: { 218 "content-script.js": function() { 219 // Store this in a local variable to make sure we don't touch any 220 // properties of the possibly-hidden content window. 221 const href = window.location.href; 222 223 browser.runtime.onMessage.addListener((msg) => { 224 browser.test.assertEq(href, msg, "Should be in the expected content window"); 225 226 return Promise.resolve(href); 227 }); 228 229 browser.runtime.sendMessage(["content-ready", href]); 230 }, 231 }, 232 }); 233 234 await extension.startup(); 235 236 await extension.awaitFinish("contentscript-bfcache-window"); 237 238 await extension.unload(); 239 }); 240 241 242 add_task(async function tabsSendMessageNoExceptionOnNonExistentTab() { 243 await SpecialPowers.pushPrefEnv({ 244 set: [["dom.security.https_first", false]], 245 }); 246 const extension = ExtensionTestUtils.loadExtension({ 247 manifest: { 248 "permissions": ["tabs"], 249 }, 250 251 async background() { 252 const url = "http://example.com/mochitest/tests/mobile/shared/components/extensions/test/mochitest/file_dummy.html"; 253 const tab = await browser.tabs.create({url}); 254 255 try { 256 browser.tabs.sendMessage(tab.id, "message"); 257 browser.tabs.sendMessage(tab.id + 100, "message"); 258 } catch (e) { 259 browser.test.fail("no exception should be raised on tabs.sendMessage to nonexistent tabs"); 260 } 261 262 await browser.tabs.remove(tab.id); 263 264 browser.test.notifyPass("tabs.sendMessage"); 265 }, 266 }); 267 268 await extension.startup(); 269 await extension.awaitFinish("tabs.sendMessage"); 270 271 await extension.unload(); 272 }); 273 274 </script> 275 276 </body> 277 </html>