diff --git a/apps/browser/src/platform/services/abstractions/abstract-chrome-storage-api.service.ts b/apps/browser/src/platform/services/abstractions/abstract-chrome-storage-api.service.ts index 4690562fd7..47a128bc1b 100644 --- a/apps/browser/src/platform/services/abstractions/abstract-chrome-storage-api.service.ts +++ b/apps/browser/src/platform/services/abstractions/abstract-chrome-storage-api.service.ts @@ -74,8 +74,12 @@ export default abstract class AbstractChromeStorageService } async get(key: string): Promise { - return new Promise((resolve) => { - this.chromeStorageApi.get(key, (obj: any) => { + return new Promise((resolve, reject) => { + this.chromeStorageApi.get(key, (obj) => { + if (chrome.runtime.lastError) { + return reject(chrome.runtime.lastError); + } + if (obj != null && obj[key] != null) { resolve(this.processGetObject(obj[key])); return; @@ -98,16 +102,24 @@ export default abstract class AbstractChromeStorageService } const keyedObj = { [key]: obj }; - return new Promise((resolve) => { + return new Promise((resolve, reject) => { this.chromeStorageApi.set(keyedObj, () => { + if (chrome.runtime.lastError) { + return reject(chrome.runtime.lastError); + } + resolve(); }); }); } async remove(key: string): Promise { - return new Promise((resolve) => { + return new Promise((resolve, reject) => { this.chromeStorageApi.remove(key, () => { + if (chrome.runtime.lastError) { + return reject(chrome.runtime.lastError); + } + resolve(); }); }); diff --git a/apps/browser/src/platform/services/abstractions/chrome-storage-api.service.spec.ts b/apps/browser/src/platform/services/abstractions/chrome-storage-api.service.spec.ts index ceadc16a58..ac8a01375f 100644 --- a/apps/browser/src/platform/services/abstractions/chrome-storage-api.service.spec.ts +++ b/apps/browser/src/platform/services/abstractions/chrome-storage-api.service.spec.ts @@ -51,6 +51,10 @@ describe("ChromeStorageApiService", () => { }); }); + afterEach(() => { + chrome.runtime.lastError = undefined; + }); + it("uses `objToStore` to prepare a value for set", async () => { const key = "key"; const value = { key: "value" }; @@ -73,6 +77,15 @@ describe("ChromeStorageApiService", () => { await service.save(key, null); expect(removeMock).toHaveBeenCalledWith(key, expect.any(Function)); }); + + it("translates chrome.runtime.lastError to promise rejection", async () => { + setMock.mockImplementation((data, callback) => { + chrome.runtime.lastError = new Error("Test Error"); + callback(); + }); + + await expect(async () => await service.save("test", {})).rejects.toThrow("Test Error"); + }); }); describe("get", () => { @@ -87,6 +100,10 @@ describe("ChromeStorageApiService", () => { }); }); + afterEach(() => { + chrome.runtime.lastError = undefined; + }); + it("returns a stored value when it is serialized", async () => { const value = { key: "value" }; store[key] = objToStore(value); @@ -112,5 +129,15 @@ describe("ChromeStorageApiService", () => { const result = await service.get(key); expect(result).toBeNull(); }); + + it("translates chrome.runtime.lastError to promise rejection", async () => { + getMock.mockImplementation((key, callback) => { + chrome.runtime.lastError = new Error("Test Error"); + callback(); + chrome.runtime.lastError = undefined; + }); + + await expect(async () => await service.get("test")).rejects.toThrow("Test Error"); + }); }); }); diff --git a/apps/browser/src/platform/services/browser-local-storage.service.spec.ts b/apps/browser/src/platform/services/browser-local-storage.service.spec.ts index bd79dd6fa5..13e26c26dd 100644 --- a/apps/browser/src/platform/services/browser-local-storage.service.spec.ts +++ b/apps/browser/src/platform/services/browser-local-storage.service.spec.ts @@ -62,6 +62,7 @@ describe("BrowserLocalStorageService", () => { }); afterEach(() => { + chrome.runtime.lastError = undefined; jest.resetAllMocks(); }); @@ -121,6 +122,24 @@ describe("BrowserLocalStorageService", () => { expect(clearMock).toHaveBeenCalledTimes(1); }); + + it("throws if get has chrome.runtime.lastError", async () => { + getMock.mockImplementation((key, callback) => { + chrome.runtime.lastError = new Error("Get Test Error"); + callback(); + }); + + await expect(async () => await service.reseed()).rejects.toThrow("Get Test Error"); + }); + + it("throws if save has chrome.runtime.lastError", async () => { + saveMock.mockImplementation((obj, callback) => { + chrome.runtime.lastError = new Error("Save Test Error"); + callback(); + }); + + await expect(async () => await service.reseed()).rejects.toThrow("Save Test Error"); + }); }); describe.each(["get", "has", "save", "remove"] as const)("%s", (method) => { diff --git a/apps/browser/src/platform/services/browser-local-storage.service.ts b/apps/browser/src/platform/services/browser-local-storage.service.ts index 7957b6edea..0ba200055b 100644 --- a/apps/browser/src/platform/services/browser-local-storage.service.ts +++ b/apps/browser/src/platform/services/browser-local-storage.service.ts @@ -81,8 +81,11 @@ export default class BrowserLocalStorageService extends AbstractChromeStorageSer * Clears local storage */ private async clear() { - return new Promise((resolve) => { + return new Promise((resolve, reject) => { this.chromeStorageApi.clear(() => { + if (chrome.runtime.lastError) { + return reject(chrome.runtime.lastError); + } resolve(); }); }); @@ -95,8 +98,12 @@ export default class BrowserLocalStorageService extends AbstractChromeStorageSer * @returns Promise resolving to keyed object of all stored data */ private async getAll(): Promise> { - return new Promise((resolve) => { + return new Promise((resolve, reject) => { this.chromeStorageApi.get(null, (allStorage) => { + if (chrome.runtime.lastError) { + return reject(chrome.runtime.lastError); + } + const resolved = Object.entries(allStorage).reduce( (agg, [key, value]) => { agg[key] = this.processGetObject(value); @@ -110,7 +117,7 @@ export default class BrowserLocalStorageService extends AbstractChromeStorageSer } private async saveAll(data: Record): Promise { - return new Promise((resolve) => { + return new Promise((resolve, reject) => { const keyedData = Object.entries(data).reduce( (agg, [key, value]) => { agg[key] = objToStore(value); @@ -119,6 +126,10 @@ export default class BrowserLocalStorageService extends AbstractChromeStorageSer {} as Record, ); this.chromeStorageApi.set(keyedData, () => { + if (chrome.runtime.lastError) { + return reject(chrome.runtime.lastError); + } + resolve(); }); });