Skip to content

Instantly share code, notes, and snippets.

@FaberVitale
Last active March 5, 2022 12:08
Show Gist options
  • Save FaberVitale/e84cd0524dda8ca1f85a4a6b1671b34f to your computer and use it in GitHub Desktop.
Save FaberVitale/e84cd0524dda8ca1f85a4a6b1671b34f to your computer and use it in GitHub Desktop.
Testing listeners (createListenerMiddleware - @reduxjs/toolkit)
import { counterActions } from './slice';
import { AppListenerEffectAPI } from './store';
export async function addOneToIncrementBy(
{ payload }: ReturnType<typeof counterActions.incrementByAmount>,
listenerApi: AppListenerEffectAPI
) {
listenerApi.dispatch(counterActions.increment())
}
import { PayloadAction, createSlice } from '@reduxjs/toolkit';
export interface CounterState {
value: number;
}
export const counterSlice = createSlice({
name: 'counter',
initialState: { value: 0 } as CounterState,
reducers: {
increment(state) {
state.value += 1;
},
decrement(state) {
state.value -= 1;
},
incrementByAmount: (state, action: PayloadAction<number>) => {
state.value += action.payload;
}
}
});
export const counterActions = counterSlice.actions;
import { configureStore, createListenerMiddleware, addListener } from '@reduxjs/toolkit';
import { counterSlice, counterActions } from './counter.slice';
import { addOneToIncrementBy } from './counter.listener';
describe('myListenerTests', () => {
const onMiddlewareError = jest.fn((): void => {});
const listenerMiddlewareInstance = createListenerMiddleware({ onError: onMiddlewareError })
function setupStore() {
return configureStore({
reducer: {
[counterSlice.name]: counterSlice.reducer,
},
middleware: gDM =>
gDM().prepend(createListenerMiddleware(listenerMiddlewareInstance.middleware)
});
}
let store = setupStore();
beforeEach(() => {
listenerMiddlewareInstance.clearListeners(); // Stops and cancels active listeners https://redux-toolkit.js.org/api/createListenerMiddleware#clearlisteners
onMiddlewareError.mockClear(); // https://jestjs.io/docs/mock-function-api#mockfnmockclear
store = setupStore(); // resets store
});
test('addOneToIncrementBy synchronously adds +1 after incrementByAmount is dispatched', async () => {
store.dispatch(addListener({
actionCreator: counterActions.incrementByAmount,
effect: addOneToIncrementBy
})
store.dipatch(counterActions.incrementByAmount(4));
expect(store.getState().counter).toBe(5);
});
});
const listenerMiddlewareInstance = createListenerMiddleware();
const store = configureStore({
reducer: {
[counterSlice.name]: counterSlice.reducer,
},
middleware: gDM =>
gDM().prepend(createListenerMiddleware(listenerMiddlewareInstance.middleware)
});
});
// Infer the `RootState` and `AppDispatch` types from the store itself
export type RootState = ReturnType<typeof store.getState>
// Inferred type: {posts: PostsState, comments: CommentsState, users: UsersState}
export type AppDispatch = typeof store.dispatch
export type AppListenerEffectAPI = ListenerEffectAPI<RootState, AppDispatch>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment