From 97acf680a6839f43ca2fa2e29ccc7ec47970a9f3 Mon Sep 17 00:00:00 2001 From: Federico Brigante Date: Wed, 10 Mar 2021 16:58:33 -0600 Subject: [PATCH] Reject with real Errors like Firefox does --- src/browser-polyfill.js | 4 ++-- .../content.js | 17 ++++++++++++++++- .../manifest.json | 4 +++- test/test-async-functions.js | 11 +++++++---- 4 files changed, 28 insertions(+), 8 deletions(-) diff --git a/src/browser-polyfill.js b/src/browser-polyfill.js index a1d43ea6..3ece6274 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 d01a83e8..7b320cba 100644 --- a/test/fixtures/detect-existing-browser-api-object/content.js +++ b/test/fixtures/detect-existing-browser-api-object/content.js @@ -1,6 +1,6 @@ /* global originalAPIObjects */ -test("browser api object in content script", (t) => { +test("browser api object in content script", async (t) => { t.ok(browser && browser.runtime, "a global browser API object should be defined"); t.ok(chrome && chrome.runtime, "a global chrome API object should be defined"); @@ -10,12 +10,27 @@ test("browser api object in content script", (t) => { // On Firefox, window is not the global object for content scripts, and so we expect window.browser to not // be defined. t.equal(window.browser, undefined, "window.browser is expected to be undefined on Firefox"); + + try { + await browser.storage.sync.set({a: 'a'.repeat(10000000)}); + t.fail('It should throw when attempting to set an object over quota'); + } catch (error) { + t.ok(error instanceof Error); + } } else { // Check that the polyfill has created a wrapped API namespace as expected. t.notEqual(browser.runtime, chrome.runtime, "browser.runtime and chrome.runtime should not be equal"); // On chrome, window is the global object and so the polyfilled browser API should // be also equal to window.browser. t.equal(browser, window.browser, "browser and window.browser should be the same object"); + + chrome.storage.local.set({a: 'a'.repeat(10000000)}, () => { + 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); + }); + + t.end(); } }); diff --git a/test/fixtures/detect-existing-browser-api-object/manifest.json b/test/fixtures/detect-existing-browser-api-object/manifest.json index 490091ac..af6f7a38 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 30886986..c0ea823e 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"); + } ); }); });