browser_ext_messaging.js (6698B)
1 /* Any copyright is dedicated to the Public Domain. 2 http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 /* eslint-env webextensions */ 5 6 "use strict"; 7 8 const TEST_URL = "https://example.com/"; 9 10 // These allowed rejections are copied from 11 // browser/components/extensions/test/browser/head.js. 12 const { PromiseTestUtils } = ChromeUtils.importESModule( 13 "resource://testing-common/PromiseTestUtils.sys.mjs" 14 ); 15 PromiseTestUtils.allowMatchingRejectionsGlobally( 16 /Message manager disconnected/ 17 ); 18 PromiseTestUtils.allowMatchingRejectionsGlobally( 19 /Receiving end does not exist/ 20 ); 21 22 const extension = ExtensionTestUtils.loadExtension({ 23 manifest: { 24 content_scripts: [ 25 { 26 matches: [TEST_URL], 27 js: ["content-script.js"], 28 run_at: "document_start", 29 }, 30 ], 31 }, 32 background() { 33 let currentPort; 34 35 browser.runtime.onConnect.addListener(port => { 36 currentPort = port; 37 port.onDisconnect.addListener(() => 38 browser.test.sendMessage("port-disconnected") 39 ); 40 port.onMessage.addListener(msg => 41 browser.test.sendMessage("port-message-received", msg) 42 ); 43 browser.test.sendMessage("port-connected"); 44 }); 45 46 browser.test.onMessage.addListener(async msg => { 47 if (msg !== "test:port-message-send") { 48 browser.test.fail(`Unexpected test message received: ${msg}`); 49 } 50 51 currentPort.postMessage("ping"); 52 }); 53 54 browser.test.sendMessage("background:ready"); 55 }, 56 files: { 57 "content-script.js": function contentScript() { 58 const port = browser.runtime.connect(); 59 port.onMessage.addListener(msg => port.postMessage(`${msg}-pong`)); 60 }, 61 }, 62 }); 63 64 add_task(async function setup_first_test() { 65 await extension.startup(); 66 67 await extension.awaitMessage("background:ready"); 68 }); 69 70 addRDMTaskWithPreAndPost( 71 TEST_URL, 72 async function pre_task() { 73 await extension.awaitMessage("port-connected"); 74 }, 75 async function test_port_kept_connected_on_switch_to_RDB() { 76 extension.sendMessage("test:port-message-send"); 77 78 is( 79 await extension.awaitMessage("port-message-received"), 80 "ping-pong", 81 "Got the expected message back from the content script" 82 ); 83 }, 84 async function post_task() { 85 extension.sendMessage("test:port-message-send"); 86 87 is( 88 await extension.awaitMessage("port-message-received"), 89 "ping-pong", 90 "Got the expected message back from the content script" 91 ); 92 } 93 ); 94 95 add_task(async function cleanup_first_test() { 96 await extension.awaitMessage("port-disconnected"); 97 98 await extension.unload(); 99 }); 100 101 addRDMTask(TEST_URL, async function test_tab_sender() { 102 const extension2 = ExtensionTestUtils.loadExtension({ 103 manifest: { 104 permissions: ["tabs"], 105 106 content_scripts: [ 107 { 108 matches: [TEST_URL], 109 js: ["content-script.js"], 110 run_at: "document_start", 111 }, 112 ], 113 }, 114 115 async background() { 116 const TEST_URL = "https://example.com/"; // eslint-disable-line no-shadow 117 118 browser.test.log("Background script init"); 119 120 let extTab; 121 const contentMessage = new Promise(resolve => { 122 browser.test.log("Listen to content"); 123 const listener = async (msg, sender) => { 124 browser.test.assertEq( 125 msg, 126 "hello-from-content", 127 "Background script got hello-from-content message" 128 ); 129 130 const tabs = await browser.tabs.query({ 131 currentWindow: true, 132 active: true, 133 }); 134 browser.test.assertEq( 135 tabs.length, 136 1, 137 "One tab is active in the current window" 138 ); 139 extTab = tabs[0]; 140 browser.test.log(`Tab: id ${extTab.id}, url ${extTab.url}`); 141 browser.test.assertEq(extTab.url, TEST_URL, "Tab has the test URL"); 142 143 browser.test.assertTrue(!!sender, "Message has a sender"); 144 browser.test.assertTrue(!!sender.tab, "Message has a sender.tab"); 145 browser.test.assertEq( 146 sender.tab.id, 147 extTab.id, 148 "Sender's tab ID matches the RDM tab ID" 149 ); 150 browser.test.assertEq( 151 sender.tab.url, 152 extTab.url, 153 "Sender's tab URL matches the RDM tab URL" 154 ); 155 156 browser.runtime.onMessage.removeListener(listener); 157 resolve(); 158 }; 159 browser.runtime.onMessage.addListener(listener); 160 }); 161 162 // Wait for "resume" message so we know the content script is also ready. 163 await new Promise(resolve => { 164 browser.test.onMessage.addListener(resolve); 165 browser.test.sendMessage("background-script-ready"); 166 }); 167 168 await contentMessage; 169 170 browser.test.log("Send message from background to content"); 171 const contentSender = await browser.tabs.sendMessage( 172 extTab.id, 173 "hello-from-background" 174 ); 175 browser.test.assertEq( 176 contentSender.id, 177 browser.runtime.id, 178 "The sender ID in content matches this extension" 179 ); 180 181 browser.test.notifyPass("rdm-messaging"); 182 }, 183 184 files: { 185 "content-script.js": async function () { 186 browser.test.log("Content script init"); 187 188 browser.test.log("Listen to background"); 189 browser.runtime.onMessage.addListener((msg, sender, respond) => { 190 browser.test.assertEq( 191 msg, 192 "hello-from-background", 193 "Content script got hello-from-background message" 194 ); 195 196 browser.test.assertTrue(!!sender, "Message has a sender"); 197 browser.test.assertTrue(!!sender.id, "Message has a sender.id"); 198 199 const { id } = sender; 200 respond({ id }); 201 }); 202 203 // Wait for "resume" message so we know the background script is also ready. 204 await new Promise(resolve => { 205 browser.test.onMessage.addListener(resolve); 206 browser.test.sendMessage("content-script-ready"); 207 }); 208 209 browser.test.log("Send message from content to background"); 210 browser.runtime.sendMessage("hello-from-content"); 211 }, 212 }, 213 }); 214 215 const contentScriptReady = extension2.awaitMessage("content-script-ready"); 216 const backgroundScriptReady = extension2.awaitMessage( 217 "background-script-ready" 218 ); 219 const finish = extension2.awaitFinish("rdm-messaging"); 220 221 await extension2.startup(); 222 223 // It appears the background script and content script can loaded in either order, so 224 // we'll wait for the both to listen before proceeding. 225 await backgroundScriptReady; 226 await contentScriptReady; 227 extension2.sendMessage("resume"); 228 229 await finish; 230 await extension2.unload(); 231 });