From 0a48bc172277718371e4191b03d83a10cf9fb828 Mon Sep 17 00:00:00 2001 From: Matias Arriola Date: Fri, 24 Sep 2021 00:50:07 -0300 Subject: [PATCH 1/2] Add key argument to serialize and unserialize invocations --- README.md | 6 +++--- index.d.ts | 4 ++-- src/__tests__/persist.test.ts | 4 ++-- src/__tests__/rehydrate.test.ts | 20 ++++++++++++-------- src/index.ts | 4 ++-- src/persist.ts | 2 +- src/rehydrate.ts | 2 +- src/types.ts | 4 ++-- 8 files changed, 25 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index af2a4dc..539cb69 100644 --- a/README.md +++ b/README.md @@ -196,8 +196,8 @@ API reference 2. **rememberedKeys** *(required)* - an array of persistable keys - if an empty array is provided nothing will get persisted; 3. **options** *(optional)* - plain object of extra options: - **prefix**: storage key prefix *(default: `'@@remember-'`)*; - - **serialize** - a plain function that takes unserialized store state and returns serialized state to be persisted *(default: `JSON.stringify`)*; - - **unserialize** - a plain function that takes serialized persisted state and returns unserialized to be set in the store *(default: `JSON.parse`)*; + - **serialize** - a plain function that takes unserialized store state and its key (`serialize(state, keyStr)`) and returns serialized state to be persisted *(default: `JSON.stringify`)*; + - **unserialize** - a plain function that takes serialized persisted state and its key (`serialize(serializedStr, keyStr)`) and returns unserialized to be set in the store *(default: `JSON.parse`)*; - **persistThrottle** - how much time should the persistence be throttled in milliseconds *(default: `100`)* - - **persistWholeStore** - a boolean which specifies if the whole store should be persisted at once. Generally only use this if you're using your own storage driver which has gigabytes of storage limits. Don't use this when using window.localStorage, window.sessionStorage or AsyncStorage as their limits are quite small - *(default: `false`)*; + - **persistWholeStore** - a boolean which specifies if the whole store should be persisted at once. Generally only use this if you're using your own storage driver which has gigabytes of storage limits. Don't use this when using window.localStorage, window.sessionStorage or AsyncStorage as their limits are quite small. When using this option, key won't be passed to `serialize` nor `unserialize` functions - *(default: `false`)*; - Returns - an enhancer to be used with Redux diff --git a/index.d.ts b/index.d.ts index f6473e8..823607c 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1,8 +1,8 @@ import { Action, AnyAction, Reducer, StoreEnhancer } from 'redux'; declare const REMEMBER_REHYDRATED = "@@REMEMBER_REHYDRATED"; declare const REMEMBER_PERSISTED = "@@REMEMBER_PERSISTED"; -type SerializeFunction = (data: any) => any; -type UnserializeFunction = (data: any) => any; +type SerializeFunction = (data: any, key?: string) => any; +type UnserializeFunction = (data: any, key?: string) => any; type Driver = { getItem: (key: string) => any; setItem: (key: string, value: any) => any; diff --git a/src/__tests__/persist.test.ts b/src/__tests__/persist.test.ts index 4e318d3..0572458 100644 --- a/src/__tests__/persist.test.ts +++ b/src/__tests__/persist.test.ts @@ -76,11 +76,11 @@ describe('persist.js', () => { ); expect(mockSerialize).nthCalledWith( - 1, 'yay' + 1, 'yay', 'key1' ); expect(mockSerialize).nthCalledWith( - 2, 'wow' + 2, 'wow', 'key3' ); }); diff --git a/src/__tests__/rehydrate.test.ts b/src/__tests__/rehydrate.test.ts index 9d5cd4f..8955775 100644 --- a/src/__tests__/rehydrate.test.ts +++ b/src/__tests__/rehydrate.test.ts @@ -111,7 +111,7 @@ describe('rehydrate.js', () => { beforeEach(() => { mockDriver = { - getItem: jest.fn((key) => `"${key}"`), + getItem: jest.fn((key) => `valueFor:${key.replace(mockPrefix, '')}`), setItem() {} }; @@ -135,19 +135,23 @@ describe('rehydrate.js', () => { }); it('returns unserialized state', async () => { + const mockUnserialize = jest.fn() + .mockImplementation((str) => str.toUpperCase()); + const res = await exec({ rememberedKeys: [ 'yay', 'k' ], - unserialize: ( - jest.fn() - .mockReturnValueOnce('val1') - .mockReturnValueOnce('val2') - ) + unserialize: mockUnserialize }); expect(res).toEqual({ - yay: 'val1', - k: 'val2' + yay: 'VALUEFOR:YAY', + k: 'VALUEFOR:K' }); + + expect(mockUnserialize) + .nthCalledWith(1, 'valueFor:yay', 'yay') + expect(mockUnserialize) + .nthCalledWith(2, 'valueFor:k', 'k') }); it('returns state filtering null and undefined', async () => { diff --git a/src/index.ts b/src/index.ts index a59626c..5a6269e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -52,8 +52,8 @@ const rememberEnhancer = ( rememberedKeys: string[], { prefix = '@persist-', - serialize = JSON.stringify, - unserialize = JSON.parse, + serialize = (data) => JSON.stringify(data), + unserialize = (data) => JSON.parse(data), persistThrottle = 100, persistWholeStore = false }: Partial = {} diff --git a/src/persist.ts b/src/persist.ts index b300e5a..56fe1e2 100644 --- a/src/persist.ts +++ b/src/persist.ts @@ -31,7 +31,7 @@ export const saveAllKeyed = ( return driver.setItem( `${prefix}${key}`, - serialize(state[key]) + serialize(state[key], key) ); }) ); diff --git a/src/rehydrate.ts b/src/rehydrate.ts index af17bc7..8076156 100644 --- a/src/rehydrate.ts +++ b/src/rehydrate.ts @@ -49,7 +49,7 @@ export const loadAllKeyed = async ({ return rememberedKeys.reduce((obj: { [key: string]: any }, key, i) => { if (items[i] !== null && items[i] !== undefined) { - obj[key] = unserialize(items[i]); + obj[key] = unserialize(items[i], key); } return obj; diff --git a/src/types.ts b/src/types.ts index 73f8c98..73395c1 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,5 +1,5 @@ -export type SerializeFunction = (data: any) => any; -export type UnserializeFunction = (data: any) => any; +export type SerializeFunction = (data: any, key?: string) => any; +export type UnserializeFunction = (data: any, key?: string) => any; export type Driver = { getItem: (key: string) => any; From e8713e0cf2fa49a912679e31f7ad69839217bb18 Mon Sep 17 00:00:00 2001 From: Matias Arriola Date: Fri, 24 Sep 2021 12:08:26 -0300 Subject: [PATCH 2/2] Add test coverage for enhancer default options --- src/__tests__/index.test.ts | 44 ++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/src/__tests__/index.test.ts b/src/__tests__/index.test.ts index 585f0f3..d747dbc 100644 --- a/src/__tests__/index.test.ts +++ b/src/__tests__/index.test.ts @@ -8,7 +8,7 @@ describe('index.js', () => { rehydrateReducer: jest.fn(() => 'REHYDRATE_REDUCER') }; - let mockInit: Function; + let mockInit: jest.Mock; let index: typeof indexModule; beforeEach(() => { @@ -168,5 +168,47 @@ describe('index.js', () => { { driver, ...opts } ) }); + + it('calls init() with default options', () => { + let optionDefaults: any; + mockInit.mockImplementationOnce((store, rememberedKeys, opts) => { + optionDefaults = opts; + }); + const store = 'the store!!!'; + + const driver = { + getItem() {}, + setItem() {} + }; + + const rememberedKeys = [ 'zz', 'bb', 'kk' ]; + + const rootReducer = () => 'the root of the reducers'; + const initialState = 'yup, initial state'; + const enhancer: any = 'another enhancer'; + + index.rememberEnhancer(driver, rememberedKeys)(() => store)( + rootReducer, initialState, enhancer + ); + + expect(mockInit).toBeCalledWith( + store, + rememberedKeys, + { driver, ...optionDefaults } + ) + + const stringifySpy = jest.spyOn(JSON, 'stringify'); + const parseSpy = jest.spyOn(JSON, 'parse'); + + expect(optionDefaults).toMatchObject({ + prefix : '@persist-', + persistThrottle : 100, + persistWholeStore : false + }); + expect(optionDefaults.serialize('hello', 'auth')).toEqual('\"hello\"'); + expect(stringifySpy).toHaveBeenCalledWith('hello'); + expect(optionDefaults.unserialize('\"bye\"', 'auth')).toEqual('bye'); + expect(parseSpy).toHaveBeenCalledWith('\"bye\"'); + }); }); });