-
Notifications
You must be signed in to change notification settings - Fork 48
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add storage class to handle gracefull degration (#61)
* add storage class to handle gracefull degration * refactor storage to use IProxyStorage * mock storage implementation for integration tests * remove unused useRef from src/use-localstorage.ts Co-authored-by: Pier-Luc Gendreau <[email protected]> Co-authored-by: Pier-Luc Gendreau <[email protected]>
- Loading branch information
1 parent
2b85b87
commit 7b83c40
Showing
6 changed files
with
283 additions
and
100 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
/** | ||
* Test if localStorage API is available | ||
* From https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API/Using_the_Web_Storage_API#Feature-detecting_localStorage | ||
* @returns {boolean} | ||
*/ | ||
export function localStorageAvailable(): boolean { | ||
try { | ||
var x = '@rehooks/local-storage:' + new Date().toISOString(); | ||
localStorage.setItem(x, x); | ||
localStorage.removeItem(x); | ||
return true; | ||
} | ||
catch(e) { | ||
return e instanceof DOMException && ( | ||
// everything except Firefox | ||
e.code === 22 || | ||
// Firefox | ||
e.code === 1014 || | ||
// test name field too, because code might not be present | ||
// everything except Firefox | ||
e.name === 'QuotaExceededError' || | ||
// Firefox | ||
e.name === 'NS_ERROR_DOM_QUOTA_REACHED') && | ||
// acknowledge QuotaExceededError only if there's something already stored | ||
(localStorage && localStorage.length !== 0); | ||
} | ||
} | ||
|
||
|
||
interface IProxyStorage { | ||
getItem(key: string): string | null | ||
setItem(Key: string, value: string): void | ||
removeItem(key: string): void | ||
} | ||
|
||
export class LocalStorageProxy implements IProxyStorage { | ||
getItem(key: string): string | null { | ||
return localStorage.getItem(key) | ||
} | ||
|
||
setItem(key: string, value: string): void { | ||
localStorage.setItem(key, value) | ||
} | ||
|
||
removeItem(key: string): void { | ||
localStorage.removeItem(key) | ||
} | ||
} | ||
|
||
export class MemoryStorageProxy implements IProxyStorage { | ||
private _memoryStorage = new Map<string, string>() | ||
|
||
getItem(key: string): string | null { | ||
return this._memoryStorage.get(key) ?? null | ||
} | ||
|
||
setItem(key: string, value: string): void { | ||
this._memoryStorage.set(key, value) | ||
} | ||
|
||
removeItem(key: string): void { | ||
this._memoryStorage.delete(key) | ||
} | ||
} | ||
|
||
const proxyStorageFrom = (isAvailable: boolean) => isAvailable | ||
? new LocalStorageProxy() | ||
: new MemoryStorageProxy() | ||
|
||
export const storage = proxyStorageFrom(localStorageAvailable()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
import { MemoryStorageProxy, LocalStorageProxy } from '../src/storage' | ||
|
||
describe('ProxyStorage', () => { | ||
describe('when localStorage is available', () => { | ||
// check assumption localStorage is available in tests | ||
window.localStorage.setItem('hi', 'hi') | ||
expect(window.localStorage.getItem('hi')).toEqual('hi') | ||
|
||
const storage = new LocalStorageProxy() | ||
|
||
it('calls localStorage.setItem', () => { | ||
storage.setItem('key1', 'value2') | ||
expect(localStorage.getItem('key1')).toEqual('value2') | ||
}) | ||
|
||
it('calls localStorage.getItem', () => { | ||
localStorage.setItem('key2', 'value1') | ||
expect(storage.getItem('key2')).toEqual('value1') | ||
}) | ||
|
||
it('calls localStorage.removeItem', () => { | ||
localStorage.setItem('key3', 'value1') | ||
expect(storage.removeItem('key3')).toEqual(undefined) | ||
expect(localStorage.getItem('key3')).toEqual(null) | ||
}) | ||
}) | ||
|
||
describe('when localStorage is not available', () => { | ||
// check assumption localStorage is available in tests | ||
window.localStorage.setItem('hi', 'hi') | ||
expect(window.localStorage.getItem('hi')).toEqual('hi') | ||
|
||
const storage = new MemoryStorageProxy() | ||
|
||
it('returns default instead of calling localStorage.setItem', () => { | ||
expect(storage.setItem('key4', 'value2')).toEqual(undefined) | ||
expect(localStorage.getItem('key4')).toEqual(null) | ||
}) | ||
|
||
it('returns default instead of calling localStorage.getItem', () => { | ||
localStorage.setItem('key5', 'value1') | ||
expect(storage.getItem('key5')).toEqual(null) | ||
}) | ||
|
||
it('returns default instead of calling localStorage.getItem', () => { | ||
localStorage.setItem('key6', 'value1') | ||
expect(storage.removeItem('key6')).toEqual(undefined) | ||
expect(localStorage.getItem('key6')).toEqual('value1') | ||
}) | ||
}) | ||
}) |
Oops, something went wrong.