"use strict"; // Regression Test for Bug 1877223: Warning message should emit to console when // message sent to a message listener, and sender does not receive the // expected response returned by sendResponse. If listener function passed to // browser.runtime.onMessage.addListener() is async, sendResponse will be ignored. function expectedWarning(extension) { return ( "sendResponse() has no effect because the runtime.onMessage handler " + `has already returned a Promise. (extension: ${extension.id})` ); } async function collectConsoleMessages(extension, finishEventName) { const { messages } = await promiseConsoleOutput(async () => { let page = await ExtensionTestUtils.loadContentPage( `moz-extension://${extension.uuid}/page.html`, { extension } ); await extension.awaitFinish(finishEventName); await page.close(); }); return messages; } add_task(async function test_emit_warning_before_promise_returns() { let extension = ExtensionTestUtils.loadExtension({ background() { browser.runtime.onMessage.addListener( async (msg, sender, sendResponse) => { sendResponse("Hi from listener"); } ); }, files: { "page.html": ``, "page.js": async () => { await browser.runtime.sendMessage("ping"); browser.test.notifyPass("message-sent-to-listener"); }, }, }); await extension.startup(); let messages = await collectConsoleMessages( extension, "message-sent-to-listener" ); ok( messages.some(m => m.errorMessage?.includes(expectedWarning(extension))), "sendResponse warning logged when sendResponse is called before the listener's promise returns" ); await extension.unload(); }); add_task(async function test_emit_warning_after_promise_returns() { let extension = ExtensionTestUtils.loadExtension({ background() { browser.runtime.onMessage.addListener( async (msg, sender, sendResponse) => { await Promise.resolve(); sendResponse("Hi from listener"); } ); }, files: { "page.html": ``, "page.js": async () => { await browser.runtime.sendMessage("ping"); browser.test.notifyPass("message-sent-to-listener"); }, }, }); await extension.startup(); let messages = await collectConsoleMessages( extension, "message-sent-to-listener" ); ok( messages.some(m => m.errorMessage?.includes(expectedWarning(extension))), "sendResponse warning logged when sendResponse is called after the listener's promise returns" ); await extension.unload(); }); add_task(async function test_send_response_not_ignored_and_no_warning_logged() { let extension = ExtensionTestUtils.loadExtension({ background() { browser.runtime.onMessage.addListener((msg, sender, sendResponse) => { setTimeout(() => sendResponse("Hi from listener"), 0); return true; }); }, files: { "page.html": ``, "page.js": async () => { let response = await browser.runtime.sendMessage("ping"); browser.test.assertEq( "Hi from listener", response, "sendResponse's response reaches the caller" ); browser.test.notifyPass("message-sent-to-listener"); }, }, }); await extension.startup(); let messages = await collectConsoleMessages( extension, "message-sent-to-listener" ); ok( !messages.some(m => m.errorMessage?.includes("sendResponse() has no effect") ), "No sendResponse warning logged when the listener correctly uses return true without async" ); await extension.unload(); });