Skip to content

Commit ec58e10

Browse files
committed
Restructure configureStore test to allow valid mocking
1 parent a2fe2e3 commit ec58e10

File tree

3 files changed

+67
-19
lines changed

3 files changed

+67
-19
lines changed

packages/toolkit/src/query/tests/cleanup.test.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ test('data stays in store when one component requiring the data stays in the sto
153153
expect(getSubStateB()).toEqual(statusB)
154154
})
155155

156-
test.only('Minimizes the number of subscription dispatches when multiple components ask for the same data', async () => {
156+
test('Minimizes the number of subscription dispatches when multiple components ask for the same data', async () => {
157157
const listenerMiddleware = createListenerMiddleware()
158158
const storeRef = setupApiStore(api, undefined, {
159159
middleware: {

packages/toolkit/src/tests/configureStore.test.ts

+65-18
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,64 @@
11
import { vi } from 'vitest'
22
import type { StoreEnhancer, StoreEnhancerStoreCreator } from '@reduxjs/toolkit'
3-
import { configureStore } from '@reduxjs/toolkit'
4-
import * as RTK from '@reduxjs/toolkit'
5-
import * as redux from 'redux'
6-
import * as devtools from '@internal/devtoolsExtension'
3+
import type * as Redux from 'redux'
4+
import type * as DevTools from '@internal/devtoolsExtension'
5+
6+
vi.doMock('redux', async () => {
7+
const redux: any = await vi.importActual('redux')
78

8-
describe('configureStore', () => {
99
vi.spyOn(redux, 'applyMiddleware')
1010
vi.spyOn(redux, 'combineReducers')
1111
vi.spyOn(redux, 'compose')
1212
vi.spyOn(redux, 'createStore')
13+
14+
return redux
15+
})
16+
17+
vi.doMock('@internal/devtoolsExtension', async () => {
18+
const devtools: typeof DevTools = await vi.importActual(
19+
'@internal/devtoolsExtension'
20+
)
1321
vi.spyOn(devtools, 'composeWithDevTools') // @remap-prod-remove-line
22+
return devtools
23+
})
24+
25+
function originalReduxCompose(...funcs: Function[]) {
26+
if (funcs.length === 0) {
27+
// infer the argument type so it is usable in inference down the line
28+
return <T>(arg: T) => arg
29+
}
30+
31+
if (funcs.length === 1) {
32+
return funcs[0]
33+
}
34+
35+
return funcs.reduce(
36+
(a, b) =>
37+
(...args: any) =>
38+
a(b(...args))
39+
)
40+
}
1441

15-
const reducer: redux.Reducer = (state = {}, _action) => state
42+
function originalComposeWithDevtools() {
43+
if (arguments.length === 0) return undefined
44+
if (typeof arguments[0] === 'object') return originalReduxCompose
45+
return originalReduxCompose.apply(null, arguments as any as Function[])
46+
}
47+
48+
describe('configureStore', async () => {
49+
// RTK's internal `composeWithDevtools` function isn't publicly exported,
50+
// so we can't mock it. However, it _does_ try to access the global extension method
51+
// attached to `window`. So, if we mock _that_, we'll know if the enhancer ran.
52+
const mockDevtoolsCompose = vi
53+
.fn()
54+
.mockImplementation(originalComposeWithDevtools)
55+
;(window as any).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ = mockDevtoolsCompose
56+
57+
const redux = await import('redux')
58+
59+
const { configureStore } = await import('@reduxjs/toolkit')
60+
61+
const reducer: Redux.Reducer = (state = {}, _action) => state
1662

1763
beforeEach(() => {
1864
vi.clearAllMocks()
@@ -22,13 +68,14 @@ describe('configureStore', () => {
2268
it('calls createStore with the reducer', () => {
2369
configureStore({ reducer })
2470
expect(configureStore({ reducer })).toBeInstanceOf(Object)
25-
expect(redux.applyMiddleware).toHaveBeenCalled()
26-
expect(devtools.composeWithDevTools).toHaveBeenCalled() // @remap-prod-remove-line
71+
2772
expect(redux.createStore).toHaveBeenCalledWith(
2873
reducer,
2974
undefined,
3075
expect.any(Function)
3176
)
77+
expect(redux.applyMiddleware).toHaveBeenCalled()
78+
expect(mockDevtoolsCompose).toHaveBeenCalled() // @remap-prod-remove-line
3279
})
3380
})
3481

@@ -42,7 +89,7 @@ describe('configureStore', () => {
4289
expect(configureStore({ reducer })).toBeInstanceOf(Object)
4390
expect(redux.combineReducers).toHaveBeenCalledWith(reducer)
4491
expect(redux.applyMiddleware).toHaveBeenCalled()
45-
expect(devtools.composeWithDevTools).toHaveBeenCalled() // @remap-prod-remove-line-line
92+
expect(mockDevtoolsCompose).toHaveBeenCalled() // @remap-prod-remove-line-line
4693
expect(redux.createStore).toHaveBeenCalledWith(
4794
expect.any(Function),
4895
undefined,
@@ -63,7 +110,7 @@ describe('configureStore', () => {
63110
it('calls createStore without any middleware', () => {
64111
expect(configureStore({ middleware: [], reducer })).toBeInstanceOf(Object)
65112
expect(redux.applyMiddleware).toHaveBeenCalledWith()
66-
expect(devtools.composeWithDevTools).toHaveBeenCalled() // @remap-prod-remove-line-line
113+
expect(mockDevtoolsCompose).toHaveBeenCalled() // @remap-prod-remove-line-line
67114
expect(redux.createStore).toHaveBeenCalledWith(
68115
reducer,
69116
undefined,
@@ -82,7 +129,7 @@ describe('configureStore', () => {
82129
expect.any(Function), // immutableCheck
83130
expect.any(Function) // serializableCheck
84131
)
85-
expect(devtools.composeWithDevTools).toHaveBeenCalled() // @remap-prod-remove-line-line
132+
expect(mockDevtoolsCompose).toHaveBeenCalled() // @remap-prod-remove-line-line
86133
expect(redux.createStore).toHaveBeenCalledWith(
87134
reducer,
88135
undefined,
@@ -121,13 +168,13 @@ describe('configureStore', () => {
121168

122169
describe('given custom middleware', () => {
123170
it('calls createStore with custom middleware and without default middleware', () => {
124-
const thank: redux.Middleware = (_store) => (next) => (action) =>
171+
const thank: Redux.Middleware = (_store) => (next) => (action) =>
125172
next(action)
126173
expect(configureStore({ middleware: [thank], reducer })).toBeInstanceOf(
127174
Object
128175
)
129176
expect(redux.applyMiddleware).toHaveBeenCalledWith(thank)
130-
expect(devtools.composeWithDevTools).toHaveBeenCalled() // @remap-prod-remove-line-line
177+
expect(mockDevtoolsCompose).toHaveBeenCalled() // @remap-prod-remove-line-line
131178
expect(redux.createStore).toHaveBeenCalledWith(
132179
reducer,
133180
undefined,
@@ -139,7 +186,7 @@ describe('configureStore', () => {
139186
describe('middleware builder notation', () => {
140187
it('calls builder, passes getDefaultMiddleware and uses returned middlewares', () => {
141188
const thank = vi.fn(
142-
((_store) => (next) => (action) => 'foobar') as redux.Middleware
189+
((_store) => (next) => (action) => 'foobar') as Redux.Middleware
143190
)
144191

145192
const builder = vi.fn((getDefaultMiddleware) => {
@@ -182,7 +229,7 @@ describe('configureStore', () => {
182229
Object
183230
)
184231
expect(redux.applyMiddleware).toHaveBeenCalled()
185-
expect(devtools.composeWithDevTools).toHaveBeenCalledWith(options) // @remap-prod-remove-line
232+
expect(mockDevtoolsCompose).toHaveBeenCalledWith(options) // @remap-prod-remove-line
186233
expect(redux.createStore).toHaveBeenCalledWith(
187234
reducer,
188235
undefined,
@@ -195,7 +242,7 @@ describe('configureStore', () => {
195242
it('calls createStore with preloadedState', () => {
196243
expect(configureStore({ reducer })).toBeInstanceOf(Object)
197244
expect(redux.applyMiddleware).toHaveBeenCalled()
198-
expect(devtools.composeWithDevTools).toHaveBeenCalled() // @remap-prod-remove-line
245+
expect(mockDevtoolsCompose).toHaveBeenCalled() // @remap-prod-remove-line
199246
expect(redux.createStore).toHaveBeenCalledWith(
200247
reducer,
201248
undefined,
@@ -206,12 +253,12 @@ describe('configureStore', () => {
206253

207254
describe('given enhancers', () => {
208255
it('calls createStore with enhancers', () => {
209-
const enhancer: redux.StoreEnhancer = (next) => next
256+
const enhancer: Redux.StoreEnhancer = (next) => next
210257
expect(configureStore({ enhancers: [enhancer], reducer })).toBeInstanceOf(
211258
Object
212259
)
213260
expect(redux.applyMiddleware).toHaveBeenCalled()
214-
expect(devtools.composeWithDevTools).toHaveBeenCalled() // @remap-prod-remove-line
261+
expect(mockDevtoolsCompose).toHaveBeenCalled() // @remap-prod-remove-line
215262
expect(redux.createStore).toHaveBeenCalledWith(
216263
reducer,
217264
undefined,

packages/toolkit/vitest.config.ts

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export default defineConfig({
1717
},
1818
deps: {
1919
interopDefault: true,
20+
inline: ['redux', '@reduxjs/toolkit'],
2021
},
2122
},
2223
})

0 commit comments

Comments
 (0)