From 5ab825b83fd6f5c5f0643aa816880f8a41a41d2d Mon Sep 17 00:00:00 2001 From: Luca Greco Date: Thu, 18 Mar 2021 18:07:16 +0100 Subject: [PATCH] fix: Reject with real Error instances like Firefox does (#293) Co-authored-by: Federico Brigante --- src/browser-polyfill.js | 4 ++-- .../content.js | 19 +++++++++++++++++++ .../manifest.json | 4 +++- test/test-async-functions.js | 11 +++++++---- 4 files changed, 31 insertions(+), 7 deletions(-) diff --git a/src/browser-polyfill.js b/src/browser-polyfill.js index a1d43ea..3ece627 100644 --- a/src/browser-polyfill.js +++ b/src/browser-polyfill.js @@ -95,7 +95,7 @@ if (typeof browser === "undefined" || Object.getPrototypeOf(browser) !== Object. const makeCallback = (promise, metadata) => { return (...callbackArgs) => { if (extensionAPIs.runtime.lastError) { - promise.reject(extensionAPIs.runtime.lastError); + promise.reject(new Error(extensionAPIs.runtime.lastError.message)); } else if (metadata.singleCallbackArg || (callbackArgs.length <= 1 && metadata.singleCallbackArg !== false)) { promise.resolve(callbackArgs[0]); @@ -484,7 +484,7 @@ if (typeof browser === "undefined" || Object.getPrototypeOf(browser) !== Object. if (extensionAPIs.runtime.lastError.message === CHROME_SEND_MESSAGE_CALLBACK_NO_RESPONSE_MESSAGE) { resolve(); } else { - reject(extensionAPIs.runtime.lastError); + reject(new Error(extensionAPIs.runtime.lastError.message)); } } else if (reply && reply.__mozWebExtensionPolyfillReject__) { // Convert back the JSON representation of the error into diff --git a/test/fixtures/detect-existing-browser-api-object/content.js b/test/fixtures/detect-existing-browser-api-object/content.js index d01a83e..016459f 100644 --- a/test/fixtures/detect-existing-browser-api-object/content.js +++ b/test/fixtures/detect-existing-browser-api-object/content.js @@ -33,3 +33,22 @@ test("browser api object in background page", async (t) => { t.ok(!reply.windowBrowserIsUnchanged, "window.browser API object should have been defined by the polyfill"); } }); + +test("error types", async (t) => { + if (navigator.userAgent.includes("Firefox/")) { + try { + await browser.storage.sync.set({a: 'a'}); + t.fail('It should throw when attempting to call storage.sync with a temporary addon ID'); + } catch (error) { + t.equal(error.message, 'The storage API will not work with a temporary addon ID. Please add an explicit addon ID to your manifest. For more information see https://mzl.la/3lPk1aE.'); + t.ok(error instanceof Error); + } + } else { + await new Promise(resolve => { + chrome.storage.local.set({a: 'a'.repeat(10000000)}, resolve); + }); + t.ok(chrome.runtime.lastError, 'It should throw when attempting to set an object over quota'); + t.equal(chrome.runtime.lastError.message, 'QUOTA_BYTES quota exceeded'); + t.notOk(chrome.runtime.lastError instanceof Error); + } +}); diff --git a/test/fixtures/detect-existing-browser-api-object/manifest.json b/test/fixtures/detect-existing-browser-api-object/manifest.json index 490091a..af6f7a3 100644 --- a/test/fixtures/detect-existing-browser-api-object/manifest.json +++ b/test/fixtures/detect-existing-browser-api-object/manifest.json @@ -19,5 +19,7 @@ ] } ], - "permissions": [] + "permissions": [ + "storage" + ] } diff --git a/test/test-async-functions.js b/test/test-async-functions.js index 3088698..c0ea823 100644 --- a/test/test-async-functions.js +++ b/test/test-async-functions.js @@ -1,6 +1,6 @@ "use strict"; -const {deepEqual, equal, fail, ok, throws} = require("chai").assert; +const {deepEqual, equal, fail, ok, throws, instanceOf} = require("chai").assert; const sinon = require("sinon"); const {setupTestDOMWindow} = require("./setup"); @@ -56,7 +56,7 @@ describe("browser-polyfill", () => { it("rejects the returned promise if chrome.runtime.lastError is not null", () => { const fakeChrome = { runtime: { - lastError: new Error("fake lastError"), + lastError: {message: "fake lastError"}, }, tabs: { query: sinon.stub(), @@ -70,8 +70,11 @@ describe("browser-polyfill", () => { return window.browser.tabs.query({active: true}).then( () => fail("Expected a rejected promise"), - (err) => equal(err, fakeChrome.runtime.lastError, - "Got the expected error in the rejected promise") + (err) => { + instanceOf(err, window.Error, "Expected the error to be an instance of Error"); + equal(err.message, fakeChrome.runtime.lastError.message, + "Got the expected error in the rejected promise"); + } ); }); });