Skip to content

Commit

Permalink
fix: sendMessage promise should resolve to undefined when no listener…
Browse files Browse the repository at this point in the history
…s reply
  • Loading branch information
lydell authored and rpl committed Jul 4, 2018
1 parent 7ff6e8a commit 4e1e98a
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 1 deletion.
10 changes: 9 additions & 1 deletion src/browser-polyfill.js
Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down
7 changes: 7 additions & 0 deletions test/fixtures/runtime-messaging-extension/background.js
Expand Up @@ -45,13 +45,20 @@ 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`);
}
});

browser.runtime.onMessage.addListener((msg, sender, sendResponse) => {
if (msg === "test - sendMessage and no listener answers") {
return undefined;
}

setTimeout(() => {
sendResponse("second listener reply");
}, 100);
Expand Down
5 changes: 5 additions & 0 deletions test/fixtures/runtime-messaging-extension/content.js
Expand Up @@ -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");
});
25 changes: 25 additions & 0 deletions test/test-runtime-onMessage.js
Expand Up @@ -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");
});
});
});
});
});

0 comments on commit 4e1e98a

Please sign in to comment.