From 3e3c8732bcbf947f009d0c44748dad7d2d0fbd8b Mon Sep 17 00:00:00 2001 From: cwomack Date: Fri, 18 Oct 2024 12:52:04 -0600 Subject: [PATCH] fix(core): Check for storage initialization errors --- .../__tests__/storage/DefaultStorage.test.ts | 30 ++++++++++++++++ .../__tests__/storage/SessionStorage.test.ts | 32 ++++++++++++++++- packages/core/src/storage/utils.ts | 36 ++++++++++++++----- 3 files changed, 89 insertions(+), 9 deletions(-) diff --git a/packages/core/__tests__/storage/DefaultStorage.test.ts b/packages/core/__tests__/storage/DefaultStorage.test.ts index 47214d899d7..4f2c7f68c45 100644 --- a/packages/core/__tests__/storage/DefaultStorage.test.ts +++ b/packages/core/__tests__/storage/DefaultStorage.test.ts @@ -35,4 +35,34 @@ describe('DefaultStorage', () => { await defaultStorage.clear(); expect(defaultStorage.getItem(key)).resolves.toBeNull(); }); + + it('should fall back to alternative storage when localStorage is not accessible', async () => { + // Mock window.localStorage to throw an error + const originalLocalStorage = window.localStorage; + Object.defineProperty(window, 'localStorage', { + get: () => { + throw new Error('localStorage is not accessible'); + }, + }); + + console.error = jest.fn(); // Mock console.error + + // Create a new DefaultStorage instance to trigger the fallback + const fallbackStorage = new DefaultStorage(); + + // Verify that the storage still works as expected + await fallbackStorage.setItem(key, value); + expect(await fallbackStorage.getItem(key)).toEqual(value); + + // Verify that the error was logged + expect(console.error).toHaveBeenCalledWith( + 'LocalStorage access failed:', + expect.any(Error), + ); + + // Restore the original localStorage + Object.defineProperty(window, 'localStorage', { + value: originalLocalStorage, + }); + }); }); diff --git a/packages/core/__tests__/storage/SessionStorage.test.ts b/packages/core/__tests__/storage/SessionStorage.test.ts index df6116d823e..21434116af4 100644 --- a/packages/core/__tests__/storage/SessionStorage.test.ts +++ b/packages/core/__tests__/storage/SessionStorage.test.ts @@ -3,7 +3,7 @@ import { SessionStorage } from '../../src/storage/SessionStorage'; const key = 'k'; const value = 'value'; -describe('sessionStorage', () => { +describe('SessionStorage', () => { let sessionStorage: SessionStorage; beforeEach(() => { @@ -37,4 +37,34 @@ describe('sessionStorage', () => { await sessionStorage.clear(); expect(await sessionStorage.getItem(key)).toBeNull(); }); + + it('should fall back to alternative storage when sessionStorage is not accessible', async () => { + // Mock window.sessionStorage to throw an error + const originalSessionStorage = window.sessionStorage; + Object.defineProperty(window, 'sessionStorage', { + get: () => { + throw new Error('sessionStorage is not accessible'); + }, + }); + + console.error = jest.fn(); // Mock console.error + + // Create a new SessionStorage instance to trigger the fallback + const fallbackStorage = new SessionStorage(); + + // Verify that the storage still works as expected + await fallbackStorage.setItem(key, value); + expect(await fallbackStorage.getItem(key)).toEqual(value); + + // Verify that the error was logged + expect(console.error).toHaveBeenCalledWith( + 'SessionStorage access failed:', + expect.any(Error), + ); + + // Restore the original sessionStorage + Object.defineProperty(window, 'sessionStorage', { + value: originalSessionStorage, + }); + }); }); diff --git a/packages/core/src/storage/utils.ts b/packages/core/src/storage/utils.ts index 527d91d7f4e..45ccae4ceb0 100644 --- a/packages/core/src/storage/utils.ts +++ b/packages/core/src/storage/utils.ts @@ -7,16 +7,36 @@ import { InMemoryStorage } from './InMemoryStorage'; * @internal * @returns Either a reference to window.localStorage or an in-memory storage as fallback */ -export const getLocalStorageWithFallback = (): Storage => - typeof window !== 'undefined' && window.localStorage - ? window.localStorage - : new InMemoryStorage(); +export const getLocalStorageWithFallback = (): Storage => { + try { + // Attempt to use localStorage directly + if (typeof window !== 'undefined' && window.localStorage) { + return window.localStorage; + } + } catch (e) { + // Handle any errors related to localStorage access + console.error('LocalStorage access failed:', e); + } + + // Return in-memory storage as a fallback if localStorage is not accessible + return new InMemoryStorage(); +}; /** * @internal * @returns Either a reference to window.sessionStorage or an in-memory storage as fallback */ -export const getSessionStorageWithFallback = (): Storage => - typeof window !== 'undefined' && window.sessionStorage - ? window.sessionStorage - : new InMemoryStorage(); +export const getSessionStorageWithFallback = (): Storage => { + try { + // Attempt to use sessionStorage directly + if (typeof window !== 'undefined' && window.sessionStorage) { + return window.sessionStorage; + } + } catch (e) { + // Handle any errors related to sessionStorage access + console.error('SessionStorage access failed:', e); + } + + // Return in-memory storage as a fallback if sessionStorage is not accessible + return new InMemoryStorage(); +};