diff --git a/src/vanilla/utils/atomWithStorage.ts b/src/vanilla/utils/atomWithStorage.ts index b508854f37..150ae5b9cb 100644 --- a/src/vanilla/utils/atomWithStorage.ts +++ b/src/vanilla/utils/atomWithStorage.ts @@ -161,15 +161,22 @@ export function createJSONStorage( callback(newValue) }) - let subscriber = getStringStorage()?.subscribe + let subscriber: StringSubscribe | undefined + try { + subscriber = getStringStorage()?.subscribe + } catch { + // ignore + } if ( !subscriber && typeof window !== 'undefined' && typeof window.addEventListener === 'function' && - window.Storage && - getStringStorage() instanceof window.Storage + window.Storage ) { subscriber = (key, callback) => { + if (!(getStringStorage() instanceof window.Storage)) { + return () => {} + } const storageEventCallback = (e: StorageEvent) => { if (e.storageArea === getStringStorage() && e.key === key) { callback(e.newValue) diff --git a/tests/react/vanilla-utils/atomWithStorage.test.tsx b/tests/react/vanilla-utils/atomWithStorage.test.tsx index 66a836dc65..c668bd746f 100644 --- a/tests/react/vanilla-utils/atomWithStorage.test.tsx +++ b/tests/react/vanilla-utils/atomWithStorage.test.tsx @@ -354,20 +354,62 @@ describe('atomWithStorage (in non-browser environment)', () => { } const addEventListener = window.addEventListener + const localStorage = window.localStorage + const sessionStorage = window.sessionStorage + const consoleWarn = window.console.warn beforeAll(() => { ;(window as any).addEventListener = undefined + // patch console.warn to prevent logging along test results + Object.defineProperty(window.console, 'warn', { + value: () => {}, + }) + Object.defineProperties(window, { + localStorage: { + get() { + throw new Error('localStorage is not available.') + }, + }, + sessionStorage: { + get() { + throw new Error('sessionStorage is not available.') + }, + }, + }) }) afterAll(() => { window.addEventListener = addEventListener + Object.defineProperty(window.console, 'warn', { + value: consoleWarn, + }) + Object.defineProperties(window, { + localStorage: { + get() { + return localStorage + }, + }, + sessionStorage: { + get() { + return sessionStorage + }, + }, + }) }) it('createJSONStorage with undefined window.addEventListener', async () => { const storage = createJSONStorage(() => asyncDummyStorage) - expect(storage.subscribe).toBeUndefined() }) + + it('createJSONStorage with localStorage', async () => { + expect(() => createJSONStorage()).not.toThrow() + expect(() => createJSONStorage(() => window.localStorage)).not.toThrow() + }) + + it('createJSONStorage with sessionStorage', async () => { + expect(() => createJSONStorage(() => window.sessionStorage)).not.toThrow() + }) }) describe('atomWithStorage (with browser storage)', () => {