UNPKG

8.34 kBPlain TextView Raw
1import type { StoreEnhancer, StoreEnhancerStoreCreator } from '@reduxjs/toolkit'
2import { configureStore } from '@reduxjs/toolkit'
3import * as RTK from '@reduxjs/toolkit'
4import * as redux from 'redux'
5import * as devtools from '@internal/devtoolsExtension'
6
7describe('configureStore', () => {
8 jest.spyOn(redux, 'applyMiddleware')
9 jest.spyOn(redux, 'combineReducers')
10 jest.spyOn(redux, 'compose')
11 jest.spyOn(redux, 'createStore')
12 jest.spyOn(devtools, 'composeWithDevTools') // @remap-prod-remove-line
13
14 const reducer: redux.Reducer = (state = {}, _action) => state
15
16 beforeEach(() => jest.clearAllMocks())
17
18 describe('given a function reducer', () => {
19 it('calls createStore with the reducer', () => {
20 configureStore({ reducer })
21 expect(configureStore({ reducer })).toBeInstanceOf(Object)
22 expect(redux.applyMiddleware).toHaveBeenCalled()
23 expect(devtools.composeWithDevTools).toHaveBeenCalled() // @remap-prod-remove-line
24 expect(redux.createStore).toHaveBeenCalledWith(
25 reducer,
26 undefined,
27 expect.any(Function)
28 )
29 })
30 })
31
32 describe('given an object of reducers', () => {
33 it('calls createStore with the combined reducers', () => {
34 const reducer = {
35 reducer() {
36 return true
37 },
38 }
39 expect(configureStore({ reducer })).toBeInstanceOf(Object)
40 expect(redux.combineReducers).toHaveBeenCalledWith(reducer)
41 expect(redux.applyMiddleware).toHaveBeenCalled()
42 expect(devtools.composeWithDevTools).toHaveBeenCalled() // @remap-prod-remove-line-line
43 expect(redux.createStore).toHaveBeenCalledWith(
44 expect.any(Function),
45 undefined,
46 expect.any(Function)
47 )
48 })
49 })
50
51 describe('given no reducer', () => {
52 it('throws', () => {
53 expect(configureStore).toThrow(
54 '"reducer" is a required argument, and must be a function or an object of functions that can be passed to combineReducers'
55 )
56 })
57 })
58
59 describe('given no middleware', () => {
60 it('calls createStore without any middleware', () => {
61 expect(configureStore({ middleware: [], reducer })).toBeInstanceOf(Object)
62 expect(redux.applyMiddleware).toHaveBeenCalledWith()
63 expect(devtools.composeWithDevTools).toHaveBeenCalled() // @remap-prod-remove-line-line
64 expect(redux.createStore).toHaveBeenCalledWith(
65 reducer,
66 undefined,
67 expect.any(Function)
68 )
69 })
70 })
71
72 describe('given undefined middleware', () => {
73 it('calls createStore with default middleware', () => {
74 expect(configureStore({ middleware: undefined, reducer })).toBeInstanceOf(
75 Object
76 )
77 expect(redux.applyMiddleware).toHaveBeenCalledWith(
78 expect.any(Function), // thunk
79 expect.any(Function), // immutableCheck
80 expect.any(Function) // serializableCheck
81 )
82 expect(devtools.composeWithDevTools).toHaveBeenCalled() // @remap-prod-remove-line-line
83 expect(redux.createStore).toHaveBeenCalledWith(
84 reducer,
85 undefined,
86 expect.any(Function)
87 )
88 })
89 })
90
91 describe('given a middleware creation function that returns undefined', () => {
92 it('throws an error', () => {
93 const invalidBuilder = jest.fn((getDefaultMiddleware) => undefined as any)
94 expect(() =>
95 configureStore({ middleware: invalidBuilder, reducer })
96 ).toThrow(
97 'when using a middleware builder function, an array of middleware must be returned'
98 )
99 })
100 })
101
102 describe('given a middleware creation function that returns an array with non-functions', () => {
103 it('throws an error', () => {
104 const invalidBuilder = jest.fn((getDefaultMiddleware) => [true] as any)
105 expect(() =>
106 configureStore({ middleware: invalidBuilder, reducer })
107 ).toThrow('each middleware provided to configureStore must be a function')
108 })
109 })
110
111 describe('given custom middleware that contains non-functions', () => {
112 it('throws an error', () => {
113 expect(() =>
114 configureStore({ middleware: [true] as any, reducer })
115 ).toThrow('each middleware provided to configureStore must be a function')
116 })
117 })
118
119 describe('given custom middleware', () => {
120 it('calls createStore with custom middleware and without default middleware', () => {
121 const thank: redux.Middleware = (_store) => (next) => (action) =>
122 next(action)
123 expect(configureStore({ middleware: [thank], reducer })).toBeInstanceOf(
124 Object
125 )
126 expect(redux.applyMiddleware).toHaveBeenCalledWith(thank)
127 expect(devtools.composeWithDevTools).toHaveBeenCalled() // @remap-prod-remove-line-line
128 expect(redux.createStore).toHaveBeenCalledWith(
129 reducer,
130 undefined,
131 expect.any(Function)
132 )
133 })
134 })
135
136 describe('middleware builder notation', () => {
137 it('calls builder, passes getDefaultMiddleware and uses returned middlewares', () => {
138 const thank = jest.fn(
139 ((_store) => (next) => (action) => 'foobar') as redux.Middleware
140 )
141
142 const builder = jest.fn((getDefaultMiddleware) => {
143 expect(getDefaultMiddleware).toEqual(expect.any(Function))
144 expect(getDefaultMiddleware()).toEqual(expect.any(Array))
145
146 return [thank]
147 })
148
149 const store = configureStore({ middleware: builder, reducer })
150
151 expect(builder).toHaveBeenCalled()
152
153 expect(store.dispatch({ type: 'test' })).toBe('foobar')
154 })
155 })
156
157 describe('with devTools disabled', () => {
158 it('calls createStore without devTools enhancer', () => {
159 expect(configureStore({ devTools: false, reducer })).toBeInstanceOf(
160 Object
161 )
162 expect(redux.applyMiddleware).toHaveBeenCalled()
163 expect(redux.compose).toHaveBeenCalled()
164 expect(redux.createStore).toHaveBeenCalledWith(
165 reducer,
166 undefined,
167 expect.any(Function)
168 )
169 })
170 })
171
172 describe('with devTools options', () => {
173 it('calls createStore with devTools enhancer and option', () => {
174 const options = {
175 name: 'myApp',
176 trace: true,
177 }
178 expect(configureStore({ devTools: options, reducer })).toBeInstanceOf(
179 Object
180 )
181 expect(redux.applyMiddleware).toHaveBeenCalled()
182 expect(devtools.composeWithDevTools).toHaveBeenCalledWith(options) // @remap-prod-remove-line
183 expect(redux.createStore).toHaveBeenCalledWith(
184 reducer,
185 undefined,
186 expect.any(Function)
187 )
188 })
189 })
190
191 describe('given preloadedState', () => {
192 it('calls createStore with preloadedState', () => {
193 expect(configureStore({ reducer })).toBeInstanceOf(Object)
194 expect(redux.applyMiddleware).toHaveBeenCalled()
195 expect(devtools.composeWithDevTools).toHaveBeenCalled() // @remap-prod-remove-line
196 expect(redux.createStore).toHaveBeenCalledWith(
197 reducer,
198 undefined,
199 expect.any(Function)
200 )
201 })
202 })
203
204 describe('given enhancers', () => {
205 it('calls createStore with enhancers', () => {
206 const enhancer: redux.StoreEnhancer = (next) => next
207 expect(configureStore({ enhancers: [enhancer], reducer })).toBeInstanceOf(
208 Object
209 )
210 expect(redux.applyMiddleware).toHaveBeenCalled()
211 expect(devtools.composeWithDevTools).toHaveBeenCalled() // @remap-prod-remove-line
212 expect(redux.createStore).toHaveBeenCalledWith(
213 reducer,
214 undefined,
215 expect.any(Function)
216 )
217 })
218
219 it('accepts a callback for customizing enhancers', () => {
220 let dummyEnhancerCalled = false
221
222 const dummyEnhancer: StoreEnhancer =
223 (createStore: StoreEnhancerStoreCreator) =>
224 (reducer, ...args: any[]) => {
225 dummyEnhancerCalled = true
226
227 return createStore(reducer, ...args)
228 }
229
230 const reducer = () => ({})
231
232 const store = configureStore({
233 reducer,
234 enhancers: (defaultEnhancers) => {
235 return [...defaultEnhancers, dummyEnhancer]
236 },
237 })
238
239 expect(dummyEnhancerCalled).toBe(true)
240 })
241 })
242})