diff --git a/app/scripts/lib/Stores/ExtensionStore.test.ts b/app/scripts/lib/Stores/ExtensionStore.test.ts index 3750a0760a04..4ac9fe874e07 100644 --- a/app/scripts/lib/Stores/ExtensionStore.test.ts +++ b/app/scripts/lib/Stores/ExtensionStore.test.ts @@ -118,7 +118,7 @@ describe('ExtensionStore', () => { get: jest .fn() .mockImplementation(() => - Promise.resolve({ appState: { test: true } }), + Promise.resolve({ data: { test: true } }), ), } as unknown as browser.Storage.LocalStorageArea, }); @@ -126,20 +126,84 @@ describe('ExtensionStore', () => { await localStore.get(); expect(localStore.mostRecentRetrievedState).toStrictEqual({ - appState: { test: true }, + data: { test: true }, }); }); - it('should reset mostRecentRetrievedState to null if storage.local is empty', async () => { + it('should return default state, reset mostRecentRetrievedState to null, and set stateCorruptionDetected to true, if storage.local is an empty object', async () => { const localStore = setup({ localMock: { get: jest.fn().mockImplementation(() => Promise.resolve({})), } as unknown as browser.Storage.LocalStorageArea, }); - await localStore.get(); + const result = await localStore.get(); + + expect(result).toStrictEqual({ + data: { config: {} }, + meta: { version: 0 }, + }); + + expect(localStore.mostRecentRetrievedState).toStrictEqual(null); + expect(localStore.stateCorruptionDetected).toStrictEqual(true); + }); + + it('should return default state, reset mostRecentRetrievedState to null, and set stateCorruptionDetected to true, if storage.local returns undefined', async () => { + const localStore = setup({ + localMock: { + get: jest.fn().mockImplementation(() => Promise.resolve()), + } as unknown as browser.Storage.LocalStorageArea, + }); + + const result = await localStore.get(); + + expect(result).toStrictEqual({ + data: { config: {} }, + meta: { version: 0 }, + }); + + expect(localStore.mostRecentRetrievedState).toStrictEqual(null); + expect(localStore.stateCorruptionDetected).toStrictEqual(true); + }); + + it('should return default state, reset mostRecentRetrievedState to null, and set stateCorruptionDetected to true, if storage.local returns an object without a data property', async () => { + const localStore = setup({ + localMock: { + get: jest + .fn() + .mockImplementation(() => Promise.resolve({ foo: 'bar' })), + } as unknown as browser.Storage.LocalStorageArea, + }); + + const result = await localStore.get(); + + expect(result).toStrictEqual({ + data: { config: {} }, + meta: { version: 0 }, + }); + + expect(localStore.mostRecentRetrievedState).toStrictEqual(null); + expect(localStore.stateCorruptionDetected).toStrictEqual(true); + }); + + it('should return default state, reset mostRecentRetrievedState to null, and set stateCorruptionDetected to true, if storage.local returns an object with an undefined data property', async () => { + const localStore = setup({ + localMock: { + get: jest + .fn() + .mockImplementation(() => Promise.resolve({ data: undefined })), + } as unknown as browser.Storage.LocalStorageArea, + }); + + const result = await localStore.get(); + + expect(result).toStrictEqual({ + data: { config: {} }, + meta: { version: 0 }, + }); expect(localStore.mostRecentRetrievedState).toStrictEqual(null); + expect(localStore.stateCorruptionDetected).toStrictEqual(true); }); it('should set mostRecentRetrievedState to current state if isExtensionInitialized is true', async () => { diff --git a/app/scripts/lib/Stores/ExtensionStore.ts b/app/scripts/lib/Stores/ExtensionStore.ts index 4ce824732499..c52e66546b60 100644 --- a/app/scripts/lib/Stores/ExtensionStore.ts +++ b/app/scripts/lib/Stores/ExtensionStore.ts @@ -10,6 +10,8 @@ import { EmptyState, } from './BaseStore'; +const { sentry } = global; + /** * Returns whether or not the given object contains no keys * @@ -112,18 +114,20 @@ export class ExtensionStore extends BaseStore { * which will not be persisted. This should probably be a bug that we * report to sentry. * - * TODO: Investigate what happens in this case and log sentry report. */ if (!this.isSupported) { return this.generateFirstTimeState(); } try { - const result = await this.#get(); + const result = await this.#get(); // extension.storage.local always returns an obj // if the object is empty, treat it as undefined - if (isEmpty(result)) { + if (!result?.data) { this.mostRecentRetrievedState = null; this.stateCorruptionDetected = true; + + sentry.captureMessage('Empty/corrupted vault found'); + // If the data is missing, but we have a record of it existing at some // point return an empty object, return the fallback state tree from return this.generateFirstTimeState();