Skip to content

Commit 48df663

Browse files
mhsattariandai-shi
andauthored
fix(utils): subscribe method of createJSONStorage should only run in the client (#2585)
* fix: prevent calling storage subscribe unless in client * test: add test for getStringStorage method from createJSONStorage to not be called in server * use try-catch * Revert "test: add test for getStringStorage method from createJSONStorage to not be called in server" This reverts commit 71d2fa0. * test: checking localStorage/sessionStorage access with createJSONStorage in server * test: improve checking localStorage/sessionStorage access with createJSONStorage in server * test: use defineProperty for checking localStorage/sessionStorage access with createJSONStorage in server * fix: ts error in new test * improve detecting browser storage access in client * Update src/vanilla/utils/atomWithStorage.ts * patch console.warn for atomWithStorage (in non-browser environment) test --------- Co-authored-by: daishi <[email protected]> Co-authored-by: Daishi Kato <[email protected]>
1 parent b236667 commit 48df663

File tree

2 files changed

+53
-4
lines changed

2 files changed

+53
-4
lines changed

src/vanilla/utils/atomWithStorage.ts

+10-3
Original file line numberDiff line numberDiff line change
@@ -161,15 +161,22 @@ export function createJSONStorage<Value>(
161161
callback(newValue)
162162
})
163163

164-
let subscriber = getStringStorage()?.subscribe
164+
let subscriber: StringSubscribe | undefined
165+
try {
166+
subscriber = getStringStorage()?.subscribe
167+
} catch {
168+
// ignore
169+
}
165170
if (
166171
!subscriber &&
167172
typeof window !== 'undefined' &&
168173
typeof window.addEventListener === 'function' &&
169-
window.Storage &&
170-
getStringStorage() instanceof window.Storage
174+
window.Storage
171175
) {
172176
subscriber = (key, callback) => {
177+
if (!(getStringStorage() instanceof window.Storage)) {
178+
return () => {}
179+
}
173180
const storageEventCallback = (e: StorageEvent) => {
174181
if (e.storageArea === getStringStorage() && e.key === key) {
175182
callback(e.newValue)

tests/react/vanilla-utils/atomWithStorage.test.tsx

+43-1
Original file line numberDiff line numberDiff line change
@@ -354,20 +354,62 @@ describe('atomWithStorage (in non-browser environment)', () => {
354354
}
355355

356356
const addEventListener = window.addEventListener
357+
const localStorage = window.localStorage
358+
const sessionStorage = window.sessionStorage
359+
const consoleWarn = window.console.warn
357360

358361
beforeAll(() => {
359362
;(window as any).addEventListener = undefined
363+
// patch console.warn to prevent logging along test results
364+
Object.defineProperty(window.console, 'warn', {
365+
value: () => {},
366+
})
367+
Object.defineProperties(window, {
368+
localStorage: {
369+
get() {
370+
throw new Error('localStorage is not available.')
371+
},
372+
},
373+
sessionStorage: {
374+
get() {
375+
throw new Error('sessionStorage is not available.')
376+
},
377+
},
378+
})
360379
})
361380

362381
afterAll(() => {
363382
window.addEventListener = addEventListener
383+
Object.defineProperty(window.console, 'warn', {
384+
value: consoleWarn,
385+
})
386+
Object.defineProperties(window, {
387+
localStorage: {
388+
get() {
389+
return localStorage
390+
},
391+
},
392+
sessionStorage: {
393+
get() {
394+
return sessionStorage
395+
},
396+
},
397+
})
364398
})
365399

366400
it('createJSONStorage with undefined window.addEventListener', async () => {
367401
const storage = createJSONStorage(() => asyncDummyStorage)
368-
369402
expect(storage.subscribe).toBeUndefined()
370403
})
404+
405+
it('createJSONStorage with localStorage', async () => {
406+
expect(() => createJSONStorage()).not.toThrow()
407+
expect(() => createJSONStorage(() => window.localStorage)).not.toThrow()
408+
})
409+
410+
it('createJSONStorage with sessionStorage', async () => {
411+
expect(() => createJSONStorage(() => window.sessionStorage)).not.toThrow()
412+
})
371413
})
372414

373415
describe('atomWithStorage (with browser storage)', () => {

0 commit comments

Comments
 (0)