11import { vi } from 'vitest'
22import 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 ,
0 commit comments