@yoroi/common
Version:
The Common package of Yoroi SDK
326 lines (259 loc) • 9.84 kB
text/typescript
/* eslint-disable @typescript-eslint/no-shadow */
import AsyncStorage from '@react-native-async-storage/async-storage'
import {App} from '@yoroi/types'
import {parseSafe} from '../../utils/parsers'
import {mountAsyncMultiStorage, mountAsyncStorage} from './async-storage'
describe('prefixed storage', () => {
beforeEach(() => AsyncStorage.clear())
it('getAllKeys, setItem, getItem, removeItem, clear', async () => {
const storage = mountAsyncStorage({path: '/'})
await storage
.getAllKeys()
.then((keys: ReadonlyArray<string>) => expect(keys).toEqual([]))
await storage.setItem('item1', item1)
expect(await storage.getItem('item1')).toEqual(item1)
await storage.setItem('item2', item2)
expect(await storage.getItem('item2')).toEqual(item2)
expect(await storage.getItem('does not exist')).toEqual(null)
expect(await storage.getAllKeys()).toEqual(['item1', 'item2'])
await storage.removeItem('item1')
expect(await storage.getItem('item1')).toEqual(null)
expect(await storage.getAllKeys()).toEqual(['item2'])
await storage.clear()
expect(await storage.getAllKeys()).toEqual([])
})
it('getAllKeys, setItem, getItem, removeItem, clear, with prefix', async () => {
const rootStorage = mountAsyncStorage({path: '/'})
const storage = rootStorage.join('prefix/')
expect(await storage.getAllKeys()).toEqual([])
await storage.setItem('item1', item1)
expect(await storage.getItem('item1')).toEqual(item1)
await storage.setItem('item2', item2)
expect(await storage.getItem('item2')).toEqual(item2)
expect(await storage.getItem('does not exist')).toEqual(null)
expect(await storage.getAllKeys()).toEqual(['item1', 'item2'])
await storage.removeItem('item1')
expect(await storage.getItem('item1')).toEqual(null)
expect(await storage.getAllKeys()).toEqual(['item2'])
await storage.clear()
expect(await storage.getAllKeys()).toEqual([])
})
it('getAllKeys, multiSet, multiGet, multiRemove', async () => {
const rootStorage = mountAsyncStorage({path: '/'})
const storage = rootStorage.join('prefix/')
await storage.multiSet<any>([
['item1', item1],
['item2', item2],
])
const keys = await storage.getAllKeys()
expect(keys).toEqual(['item1', 'item2'])
const items1 = await storage.multiGet(['item1', 'item2'])
expect(items1).toEqual([
['item1', {a: 123, b: 234}],
['item2', {c: 123, d: 234}],
])
await storage.multiRemove(['item1', 'item2'])
const items2 = await storage.multiGet(['item1', 'item2'])
expect(items2).toEqual([
['item1', null],
['item2', null],
])
await storage
.getAllKeys()
.then((keys: ReadonlyArray<string>) => expect(keys).toEqual([]))
})
it('getAllKeys', async () => {
const rootStorage = mountAsyncStorage({path: '/'})
const storage1 = rootStorage.join('prefix/1/')
expect(await storage1.getAllKeys()).toEqual([])
await storage1.setItem('key1', item1)
await storage1.setItem('key2', item2)
expect(await storage1.getAllKeys()).toEqual(['key1', 'key2'])
const storage2 = rootStorage.join('prefix/2/3/')
expect(await storage2.getAllKeys()).toEqual([])
await storage2.setItem('key1', item1)
await storage2.setItem('key2', item2)
expect(await storage2.getAllKeys()).toEqual(['key1', 'key2'])
const storage = rootStorage.join('prefix/')
expect(await storage.getAllKeys()).toEqual([])
await storage.setItem('key1', item1)
await storage.setItem('key2', item2)
expect(await storage.getAllKeys()).toEqual(['key1', 'key2'])
})
it('join', async () => {
const rootStorage = mountAsyncStorage({path: '/'})
const root = rootStorage.join('/')
await root.setItem('key1', item1)
await root.setItem('key2', item2)
expect(await root.getAllKeys()).toEqual(['key1', 'key2'])
const storage = root.join('dir/')
expect(await storage.getAllKeys()).toEqual([])
await storage.setItem('item1', item1)
expect(await storage.getItem('item1')).toEqual(item1)
await storage.setItem('item2', item2)
expect(await storage.getItem('item2')).toEqual(item2)
expect(await storage.getItem('does not exist')).toEqual(null)
expect(await storage.getAllKeys()).toEqual(['item1', 'item2'])
await storage.removeItem('item1')
expect(await storage.getItem('item1')).toEqual(null)
expect(await storage.getAllKeys()).toEqual(['item2'])
await storage.clear()
expect(await storage.getAllKeys()).toEqual([])
})
describe('stringify/parse', () => {
it('getItem, setItem', async () => {
const storage = mountAsyncStorage({path: '/'})
const item = 'text'
const storedItem = 'item123'
await storage.setItem('item', item, (data: unknown) => {
expect(data).toBe(item)
return storedItem
}) // overrides JSON.stringify
const parsedResult = await storage.getItem('item', (data: unknown) => {
expect(data).toBe(storedItem)
return item
}) // overrides JSON.parse
expect(parsedResult).toBe(item)
})
it('multiGet, multiSet', async () => {
const storage = mountAsyncStorage({path: '/'})
const item1 = 'item1'
const storedItem1 = `${item1}-modified`
const item2 = 'item2'
const storedItem2 = `${item2}-modified`
const tuples: [string, unknown][] = [
['item1', item1],
['item2', item2],
]
await storage.multiSet<any>(tuples, (data: unknown) => {
expect([item1, item2]).toContain(data)
return `${data}-modified`
}) // overrides JSON.stringify
const parsedResult = await storage.multiGet(
['item1', 'item2'],
(data: string | null) => {
expect([storedItem1, storedItem2]).toContain(data)
return data?.slice(0, 5)
},
) // overrides JSON.parse
expect(parsedResult).toEqual(tuples)
})
})
it('clears sub-storage', async () => {
const rootStorage = mountAsyncStorage({path: '/'})
const storage1 = rootStorage.join('1/')
const storage2 = storage1.join('2/')
const storage3 = storage2.join('3/')
await rootStorage.setItem('a', '000')
await rootStorage.setItem('1', '000')
await storage1.setItem('b', 111)
await storage2.setItem('c', 222)
await storage3.setItem('d', 333)
expect(await snapshot()).toEqual({
// folder named "1"
'/1/2/3/d': 333,
'/1/2/c': 222,
'/1/b': 111,
// file named "1"
'/1': '000',
'/a': '000',
})
expect(await storage1.getAllKeys()).toEqual(['b'])
await storage1.clear()
expect(await snapshot()).toEqual({
'/a': '000',
'/1': '000',
})
})
it('removeFolder', async () => {
const rootStorage = mountAsyncStorage({path: '/'})
const storage1 = rootStorage.join('1/')
const storage2 = storage1.join('2/')
const storage3 = storage2.join('3/')
await rootStorage.setItem('a', '000')
await rootStorage.setItem('1', '000')
await storage1.setItem('b', 111)
await storage2.setItem('c', 222)
await storage3.setItem('d', 333)
expect(await snapshot()).toEqual({
// folder named "1"
'/1/2/3/d': 333,
'/1/2/c': 222,
'/1/b': 111,
// root folder
'/1': '000',
'/a': '000',
})
await storage2.removeFolder('3/')
expect(await snapshot()).toEqual({
'/1/2/c': 222,
'/1/b': 111,
'/1': '000',
'/a': '000',
})
await rootStorage.removeFolder('1/')
expect(await snapshot()).toEqual({
'/1': '000',
'/a': '000',
})
})
})
describe('multi storage', () => {
beforeEach(() => AsyncStorage.clear())
it('saveMany, readAll, readMany, keys, and clear providing the serializers', async () => {
const storage = mountAsyncMultiStorage(options)
await storage.saveMany([item3, item4])
const readItems = await storage.readAll()
expect(readItems).toEqual([
['1', item3],
['2', item4],
])
const readItem = await storage.readMany(['1'])
expect(readItem).toEqual([['1', item3]])
const keys = await storage.getAllKeys()
expect(keys).toEqual(['1', '2'])
await storage.clear()
const emptyKeys = await storage.getAllKeys()
expect(emptyKeys).toEqual([])
})
it('saveMany, readAll, readMany, keys, and clear default serializers / key as extractor', async () => {
const rootStorage = mountAsyncStorage({path: '/'})
const storage = mountAsyncMultiStorage({
storage: rootStorage.join('multiStorage/'),
dataFolder: 'dataFolder/',
keyExtractor: 'id',
})
await storage.saveMany([item3, item4])
const readItems = await storage.readAll()
expect(readItems).toEqual([
['1', item3],
['2', item4],
])
storage.removeMany(['2'])
const keys = await storage.getAllKeys()
expect(keys).toEqual(['1'])
const readItem = await storage.readMany(['1'])
expect(readItem).toEqual([['1', item3]])
await storage.clear()
const emptyKeys = await storage.getAllKeys()
expect(emptyKeys).toEqual([])
})
})
const options: App.MultiStorageOptions<any> = {
storage: mountAsyncStorage({path: '/'}).join('multiStorage/'),
dataFolder: 'dataFolder/',
keyExtractor: (item: any) => item.id,
serializer: JSON.stringify,
deserializer: (data: any) => JSON.parse(data as string),
}
const item1 = {a: 123, b: 234}
const item2 = {c: 123, d: 234}
const item3 = {id: 1, a: 123, b: 234}
const item4 = {id: '2', c: 123, d: 234}
const snapshot = async () => {
const keys = await AsyncStorage.getAllKeys()
const entries = await AsyncStorage.multiGet(keys).then((entries) =>
entries.map(([key, value]) => [key, parseSafe(value)]),
)
return Object.fromEntries(entries)
}