fix: sendMessage promise should resolve to undefined when no listeners reply

This commit is contained in:
Simon Lydell 2018-07-02 12:38:05 +02:00 committed by Luca Greco
parent 7ff6e8a1dc
commit 4e1e98add2
4 changed files with 46 additions and 1 deletions

View File

@ -7,6 +7,7 @@
"use strict";
if (typeof browser === "undefined") {
const CHROME_SEND_MESSAGE_CALLBACK_NO_RESPONSE_MESSAGE = "The message port closed before a response was received.";
const SEND_RESPONSE_DEPRECATION_WARNING = `
Returning a Promise is the preferred way to send a reply from an
onMessage/onMessageExternal listener, as the sendResponse will be
@ -446,7 +447,14 @@ if (typeof browser === "undefined") {
const wrappedSendMessageCallback = ({reject, resolve}, reply) => {
if (chrome.runtime.lastError) {
reject(chrome.runtime.lastError);
// Detect when none of the listers replied to the sendMessage call and resolve
// the promise to undefined as in Firefox.
// See https://github.com/mozilla/webextension-polyfill/issues/130
if (chrome.runtime.lastError.message === CHROME_SEND_MESSAGE_CALLBACK_NO_RESPONSE_MESSAGE) {
resolve();
} else {
reject(chrome.runtime.lastError);
}
} else if (reply && reply.__mozWebExtensionPolyfillReject__) {
// Convert back the JSON representation of the error into
// an Error instance.

View File

@ -45,6 +45,9 @@ browser.runtime.onMessage.addListener((msg, sender, sendResponse) => {
case "test - sendMessage with listener callback throws":
throw new Error("listener throws");
case "test - sendMessage and no listener answers":
return undefined;
default:
return Promise.resolve(
`Unxpected message received by the background page: ${JSON.stringify(msg)}\n`);
@ -52,6 +55,10 @@ browser.runtime.onMessage.addListener((msg, sender, sendResponse) => {
});
browser.runtime.onMessage.addListener((msg, sender, sendResponse) => {
if (msg === "test - sendMessage and no listener answers") {
return undefined;
}
setTimeout(() => {
sendResponse("second listener reply");
}, 100);

View File

@ -75,3 +75,8 @@ test("sendMessage with listener callback throws", async (t) => {
t.equal(err.message, "listener throws", "Got an error with the expected message");
}
});
test("sendMessage and no listener answers", async (t) => {
const reply = await browser.runtime.sendMessage("test - sendMessage and no listener answers");
t.equal(reply, undefined, "Got undefined reply as expected");
});

View File

@ -238,5 +238,30 @@ describe("browser-polyfill", () => {
});
});
});
it("resolves to undefined when no listeners reply", () => {
const fakeChrome = {
runtime: {
// This error message is defined as CHROME_SEND_MESSAGE_CALLBACK_NO_RESPONSE_MESSAGE
// in the polyfill sources and it is used to recognize when Chrome has detected that
// none of the listeners replied.
lastError: {
message: "The message port closed before a response was received.",
},
sendMessage: sinon.stub(),
},
};
fakeChrome.runtime.sendMessage.onFirstCall().callsArgWith(1, [undefined]);
return setupTestDOMWindow(fakeChrome).then(window => {
const promise = window.browser.runtime.sendMessage("some_message");
ok(fakeChrome.runtime.sendMessage.calledOnce, "sendMessage has been called once");
return promise.then(reply => {
deepEqual(reply, undefined, "sendMessage promise should be resolved to undefined");
});
});
});
});
});