UNPKG

@reduxjs/toolkit

Version:

The official, opinionated, batteries-included toolset for efficient Redux development

209 lines (176 loc) 6.25 kB
import { configureStore } from '../configureStore' import { createSlice } from '../createSlice' import type { AutoBatchOptions } from '../autoBatchEnhancer' import { autoBatchEnhancer, prepareAutoBatched } from '../autoBatchEnhancer' import { delay } from '../utils' import { debounce } from 'lodash' interface CounterState { value: number } const counterSlice = createSlice({ name: 'counter', initialState: { value: 0 } as CounterState, reducers: { incrementBatched: { // Batched, low-priority reducer(state) { state.value += 1 }, prepare: prepareAutoBatched<void>(), }, // Not batched, normal priority decrementUnbatched(state) { state.value -= 1 }, }, }) const { incrementBatched, decrementUnbatched } = counterSlice.actions const makeStore = (autoBatchOptions?: AutoBatchOptions) => { return configureStore({ reducer: counterSlice.reducer, enhancers: (getDefaultEnhancers) => getDefaultEnhancers({ autoBatch: autoBatchOptions, }), }) } let store: ReturnType<typeof makeStore> let subscriptionNotifications = 0 const cases: AutoBatchOptions[] = [ { type: 'tick' }, { type: 'raf' }, { type: 'timer', timeout: 0 }, { type: 'timer', timeout: 10 }, { type: 'timer', timeout: 20 }, { type: 'callback', queueNotification: debounce((notify: () => void) => { notify() }, 5), }, ] describe.each(cases)('autoBatchEnhancer: %j', (autoBatchOptions) => { beforeEach(() => { subscriptionNotifications = 0 store = makeStore(autoBatchOptions) store.subscribe(() => { subscriptionNotifications++ }) }) test('Does not alter normal subscription notification behavior', async () => { store.dispatch(decrementUnbatched()) expect(subscriptionNotifications).toBe(1) store.dispatch(decrementUnbatched()) expect(subscriptionNotifications).toBe(2) store.dispatch(decrementUnbatched()) expect(subscriptionNotifications).toBe(3) store.dispatch(decrementUnbatched()) await delay(25) expect(subscriptionNotifications).toBe(4) }) test('Only notifies once if several batched actions are dispatched in a row', async () => { store.dispatch(incrementBatched()) expect(subscriptionNotifications).toBe(0) store.dispatch(incrementBatched()) expect(subscriptionNotifications).toBe(0) store.dispatch(incrementBatched()) expect(subscriptionNotifications).toBe(0) store.dispatch(incrementBatched()) await delay(25) expect(subscriptionNotifications).toBe(1) }) test('Notifies immediately if a non-batched action is dispatched', async () => { store.dispatch(incrementBatched()) expect(subscriptionNotifications).toBe(0) store.dispatch(incrementBatched()) expect(subscriptionNotifications).toBe(0) store.dispatch(decrementUnbatched()) expect(subscriptionNotifications).toBe(1) store.dispatch(incrementBatched()) await delay(25) expect(subscriptionNotifications).toBe(2) }) test('Does not notify at end of tick if last action was normal priority', async () => { store.dispatch(incrementBatched()) expect(subscriptionNotifications).toBe(0) store.dispatch(incrementBatched()) expect(subscriptionNotifications).toBe(0) store.dispatch(decrementUnbatched()) expect(subscriptionNotifications).toBe(1) store.dispatch(incrementBatched()) store.dispatch(decrementUnbatched()) expect(subscriptionNotifications).toBe(2) store.dispatch(decrementUnbatched()) expect(subscriptionNotifications).toBe(3) await delay(25) expect(subscriptionNotifications).toBe(3) }) }) describe.each(cases)( 'autoBatchEnhancer with fake timers: %j', (autoBatchOptions) => { beforeAll(() => { vitest.useFakeTimers({ toFake: ['setTimeout', 'queueMicrotask', 'requestAnimationFrame'], }) }) afterAll(() => { vitest.useRealTimers() }) beforeEach(() => { subscriptionNotifications = 0 store = makeStore(autoBatchOptions) store.subscribe(() => { subscriptionNotifications++ }) }) test('Does not alter normal subscription notification behavior', () => { store.dispatch(decrementUnbatched()) expect(subscriptionNotifications).toBe(1) store.dispatch(decrementUnbatched()) expect(subscriptionNotifications).toBe(2) store.dispatch(decrementUnbatched()) expect(subscriptionNotifications).toBe(3) store.dispatch(decrementUnbatched()) vitest.runAllTimers() expect(subscriptionNotifications).toBe(4) }) test('Only notifies once if several batched actions are dispatched in a row', () => { store.dispatch(incrementBatched()) expect(subscriptionNotifications).toBe(0) store.dispatch(incrementBatched()) expect(subscriptionNotifications).toBe(0) store.dispatch(incrementBatched()) expect(subscriptionNotifications).toBe(0) store.dispatch(incrementBatched()) vitest.runAllTimers() expect(subscriptionNotifications).toBe(1) }) test('Notifies immediately if a non-batched action is dispatched', () => { store.dispatch(incrementBatched()) expect(subscriptionNotifications).toBe(0) store.dispatch(incrementBatched()) expect(subscriptionNotifications).toBe(0) store.dispatch(decrementUnbatched()) expect(subscriptionNotifications).toBe(1) store.dispatch(incrementBatched()) vitest.runAllTimers() expect(subscriptionNotifications).toBe(2) }) test('Does not notify at end of tick if last action was normal priority', () => { store.dispatch(incrementBatched()) expect(subscriptionNotifications).toBe(0) store.dispatch(incrementBatched()) expect(subscriptionNotifications).toBe(0) store.dispatch(decrementUnbatched()) expect(subscriptionNotifications).toBe(1) store.dispatch(incrementBatched()) store.dispatch(decrementUnbatched()) expect(subscriptionNotifications).toBe(2) store.dispatch(decrementUnbatched()) expect(subscriptionNotifications).toBe(3) vitest.runAllTimers() expect(subscriptionNotifications).toBe(3) }) }, )