Skip to content

Commit

Permalink
Remove redux-persist and upgrade Redux
Browse files Browse the repository at this point in the history
  • Loading branch information
mhoran committed May 4, 2024
1 parent f90ccc0 commit c76f73d
Show file tree
Hide file tree
Showing 13 changed files with 504 additions and 204 deletions.
6 changes: 0 additions & 6 deletions __mocks__/redux-persist.js

This file was deleted.

51 changes: 43 additions & 8 deletions __tests__/lib/weechat/action_transformer.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { AnyAction, configureStore } from '@reduxjs/toolkit';
import { UnknownAction, configureStore } from '@reduxjs/toolkit';
import { StoreState, reducer } from '../../../src/store';
import { transformToReduxAction } from '../../../src/lib/weechat/action_transformer';
import { ThunkAction } from 'redux-thunk';
Expand All @@ -23,7 +23,12 @@ describe('transformToReduxAction', () => {
currentBufferId: '8578d9c00'
} as AppState
};
const store = configureStore({ reducer, preloadedState });
const store = configureStore({
reducer,
preloadedState,
enhancers: (getDefaultEnhancers) =>
getDefaultEnhancers({ autoBatch: false })
});

const action = transformToReduxAction({
id: 'buffers',
Expand Down Expand Up @@ -67,7 +72,12 @@ describe('transformToReduxAction', () => {
});
expect(action).toBeDefined();

const thunk = action as ThunkAction<void, StoreState, void, AnyAction>;
const thunk = action as ThunkAction<
void,
StoreState,
void,
UnknownAction
>;
const dispatch = jest.fn();
thunk(
dispatch,
Expand All @@ -90,7 +100,12 @@ describe('transformToReduxAction', () => {
currentBufferId: '8578d9c00'
} as AppState
};
const store = configureStore({ reducer, preloadedState });
const store = configureStore({
reducer,
preloadedState,
enhancers: (getDefaultEnhancers) =>
getDefaultEnhancers({ autoBatch: false })
});

const action = transformToReduxAction({
id: 'buffers',
Expand Down Expand Up @@ -124,7 +139,12 @@ describe('transformToReduxAction', () => {
currentBufferId: '83a41cd80'
} as AppState
};
const store = configureStore({ reducer, preloadedState });
const store = configureStore({
reducer,
preloadedState,
enhancers: (getDefaultEnhancers) =>
getDefaultEnhancers({ autoBatch: false })
});

const action = transformToReduxAction({
id: '_buffer_closing',
Expand Down Expand Up @@ -166,7 +186,12 @@ describe('transformToReduxAction', () => {
currentBufferId: '83a41cd80'
} as AppState
};
const store = configureStore({ reducer, preloadedState });
const store = configureStore({
reducer,
preloadedState,
enhancers: (getDefaultEnhancers) =>
getDefaultEnhancers({ autoBatch: false })
});

const action = transformToReduxAction({
id: '_buffer_closing',
Expand All @@ -193,7 +218,12 @@ describe('transformToReduxAction', () => {
'83d204d80': { full_name: 'irc.libera.#weechat' } as WeechatBuffer
}
};
const store = configureStore({ reducer, preloadedState });
const store = configureStore({
reducer,
preloadedState,
enhancers: (getDefaultEnhancers) =>
getDefaultEnhancers({ autoBatch: false })
});

const action = transformToReduxAction({
id: 'last_read_lines',
Expand Down Expand Up @@ -235,7 +265,12 @@ describe('transformToReduxAction', () => {
]
}
};
const store = configureStore({ reducer, preloadedState });
const store = configureStore({
reducer,
preloadedState,
enhancers: (getDefaultEnhancers) =>
getDefaultEnhancers({ autoBatch: false })
});

const action = transformToReduxAction({
id: '_nicklist_diff',
Expand Down
206 changes: 206 additions & 0 deletions __tests__/store/persist.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
import AsyncStorage from '@react-native-async-storage/async-storage';
import {
Reducer,
configureStore,
createAction,
createReducer
} from '@reduxjs/toolkit';
import {
initializeStoreAction,
persistMiddleware,
persistReducer
} from '../../src/store/persist';

jest.useFakeTimers();

const testAction = createAction('persist/TEST');
const reducer = createReducer({ preloaded: false }, (builder) => {
builder.addCase(testAction, (state) => {
return { ...state, allowed: true, unallowed: true };
});
});

beforeEach(async () => {
await AsyncStorage.clear();
jest.clearAllMocks();
});

it('defaults _persist state prior to rehydration', () => {
const state = persistReducer(reducer)(undefined, { type: '@@init' });

expect(state._persist?.version).toEqual(-1);
expect(state._persist?.rehydrated).toEqual(false);
expect(state.preloaded).toEqual(false);
});

it('merges _persist state with preloaded state', () => {
const preloadedState = { preloaded: true };
const state = persistReducer(reducer)(preloadedState, { type: '@@init' });

expect(state._persist?.version).toEqual(-1);
expect(state._persist?.rehydrated).toEqual(false);
expect(state.preloaded).toEqual(true);
});

it('merges persisted state on rehydration', async () => {
await AsyncStorage.setItem(
'persist:state',
JSON.stringify({
_persist: JSON.stringify({ version: -1, rehydrated: true }),
allowed: JSON.stringify(true)
})
);
const store = configureStore({
reducer: persistReducer(reducer),
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware().prepend(
persistMiddleware({ key: 'state', allowlist: ['allowed'] })
)
});

await jest.runAllTimersAsync();

expect(store.getState()._persist?.version).toEqual(-1);
expect(store.getState()._persist?.rehydrated).toEqual(true);
expect((store.getState() as Record<string, unknown>).allowed).toEqual(true);
});

it('persists allowlisted keys on dispatch', async () => {
const store = configureStore({
reducer: persistReducer(reducer),
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware().prepend(
persistMiddleware({ key: 'state', allowlist: ['allowed'] })
)
});

await jest.runAllTimersAsync();

expect(store.getState()._persist?.rehydrated).toEqual(true);

store.dispatch(testAction());

await jest.runAllTimersAsync();

const persisted = await AsyncStorage.getItem('persist:state');
expect(persisted).not.toBeNull();

const outer = JSON.parse(persisted!);

expect(outer).toHaveProperty('_persist');
expect(outer).toHaveProperty('allowed');

const _persist = JSON.parse(outer['_persist']);
const allowed = JSON.parse(outer['allowed']);

expect(_persist.version).toEqual(-1);
expect(_persist.rehydrated).toEqual(true);
expect(allowed).toEqual(true);
});

it('does not persist before rehydration', async () => {
const initializeMock = jest.fn();
const mockPersistReducer = (baseReducer: Reducer) =>
createReducer(
{ _persist: { rehydrated: false, version: -1 } },
(builder) => {
builder.addCase(initializeStoreAction, () => initializeMock());
builder.addDefaultCase((state, action) => baseReducer(state, action));
}
);
const store = configureStore({
reducer: mockPersistReducer(reducer),
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware().prepend(
persistMiddleware({ key: 'state', allowlist: ['allowed'] })
)
});

expect(initializeMock).not.toHaveBeenCalled();

store.dispatch(testAction());

await jest.runAllTimersAsync();

const persisted = await AsyncStorage.getItem('persist:state');
expect(persisted).toBeNull();
});

it('does not persist unallowed keys', async () => {
const store = configureStore({
reducer: persistReducer(reducer),
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware().prepend(
persistMiddleware({ key: 'state', allowlist: ['allowed'] })
)
});

await jest.runAllTimersAsync();

store.dispatch(testAction());

await jest.runAllTimersAsync();

const persisted = await AsyncStorage.getItem('persist:state');
expect(persisted).not.toBeNull();

const outer = JSON.parse(persisted!);

expect(outer).toHaveProperty('allowed');
expect(outer).not.toHaveProperty('unallowed');
});

it('does not run migrations when there is no persisted state', async () => {
const migrate = jest.fn();
const store = configureStore({
reducer: persistReducer(reducer),
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware().prepend(
persistMiddleware({
key: 'state',
allowlist: ['allowed'],
version: 0,
migrate
})
)
});

await jest.runAllTimersAsync();

expect(migrate).not.toHaveBeenCalled();
expect(store.getState()._persist.version).toEqual(0);
expect(store.getState()._persist.rehydrated).toEqual(true);
});

it('runs necessary migrations', async () => {
await AsyncStorage.setItem(
'persist:state',
JSON.stringify({
_persist: JSON.stringify({ version: -1, rehydrated: true }),
allowed: JSON.stringify(true)
})
);
const migrate = jest.fn(() => ({
_persist: { version: -1, rehydrated: true },
allowed: true
}));
const store = configureStore({
reducer: persistReducer(reducer),
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware().prepend(
persistMiddleware({
key: 'state',
allowlist: ['allowed'],
version: 0,
migrate
})
)
});

await jest.runAllTimersAsync();

expect(migrate).toHaveBeenCalled();
expect(store.getState()._persist.version).toEqual(0);
expect(store.getState()._persist.rehydrated).toEqual(true);
expect(store.getState().allowed).toEqual(true);
});
8 changes: 6 additions & 2 deletions __tests__/usecase/buffers/ui/BufferContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@ describe('BufferContainer', () => {
type: 0
}
}
}
},
enhancers: (getDefaultEnhancers) =>
getDefaultEnhancers({ autoBatch: false })
});

render(
Expand Down Expand Up @@ -133,7 +135,9 @@ describe('BufferContainer', () => {
type: 0
}
}
}
},
enhancers: (getDefaultEnhancers) =>
getDefaultEnhancers({ autoBatch: false })
});

render(
Expand Down
2 changes: 1 addition & 1 deletion jest.config.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module.exports = {
preset: 'jest-expo',
transformIgnorePatterns: [
'node_modules/(?!((jest-)?react-native|@react-native(-community)?)|expo(nent)?|@expo(nent)?/.*|@expo-google-fonts/.*|react-navigation|@react-navigation/.*|@unimodules/.*|unimodules|sentry-expo|native-base|react-native-svg)'
'node_modules/(?!((jest-)?react-native|@react-native(-community)?)|expo(nent)?|@expo(nent)?/.*|@expo-google-fonts/.*|react-navigation|@react-navigation/.*|@unimodules/.*|unimodules|sentry-expo|native-base|react-native-svg|react-redux)'
]
};
Loading

0 comments on commit c76f73d

Please sign in to comment.