@@ -5,39 +5,34 @@ import PropTypes from 'prop-types'
55import semver from 'semver'
66import { createStore } from 'redux'
77import { Provider , createProvider , connect } from '../../src/index.js'
8+ import { ReactReduxContext } from "../../src/components/context"
89import * as rtl from 'react-testing-library'
910import 'jest-dom/extend-expect'
11+ import ReactDOM from "react-dom"
1012
1113const createExampleTextReducer = ( ) => ( state = "example text" ) => state ;
1214
1315describe ( 'React' , ( ) => {
1416 describe ( 'Provider' , ( ) => {
1517 afterEach ( ( ) => rtl . cleanup ( ) )
18+
1619 const createChild = ( storeKey = 'store' ) => {
1720 class Child extends Component {
1821 render ( ) {
19- const store = this . context [ storeKey ] ;
20-
21- let text = '' ;
22-
23- if ( store ) {
24- text = store . getState ( ) . toString ( )
25- }
26-
2722 return (
2823 < div data-testid = "store" >
29- { storeKey } - { text }
24+ < ReactReduxContext . Consumer >
25+ { ( { storeState} ) => {
26+ return `${ storeKey } - ${ storeState } `
27+ } }
28+ </ ReactReduxContext . Consumer >
29+
3030 </ div >
3131 )
3232 }
3333 }
3434
35-
36- Child . contextTypes = {
37- [ storeKey ] : PropTypes . object . isRequired
38- }
39-
40- return Child
35+ return Child
4136 }
4237 const Child = createChild ( ) ;
4338
@@ -90,10 +85,12 @@ describe('React', () => {
9085 }
9186 } )
9287
93- it ( 'should add the store to the child context' , ( ) => {
88+ it ( 'should add the store state to context' , ( ) => {
9489 const store = createStore ( createExampleTextReducer ( ) )
9590
96- const spy = jest . spyOn ( console , 'error' ) . mockImplementation ( ( ) => { } )
91+ const spy = jest . spyOn ( console , 'error' ) . mockImplementation ( ( e ) => {
92+ const q = 42 ;
93+ } )
9794 const tester = rtl . render (
9895 < Provider store = { store } >
9996 < Child />
@@ -105,22 +102,6 @@ describe('React', () => {
105102 expect ( tester . getByTestId ( 'store' ) ) . toHaveTextContent ( 'store - example text' )
106103 } )
107104
108- it ( 'should add the store to the child context using a custom store key' , ( ) => {
109- const store = createStore ( createExampleTextReducer ( ) )
110- const CustomProvider = createProvider ( 'customStoreKey' ) ;
111- const CustomChild = createChild ( 'customStoreKey' ) ;
112-
113- const spy = jest . spyOn ( console , 'error' ) . mockImplementation ( ( ) => { } ) ;
114- const tester = rtl . render (
115- < CustomProvider store = { store } >
116- < CustomChild />
117- </ CustomProvider >
118- )
119- expect ( spy ) . toHaveBeenCalledTimes ( 0 )
120- spy . mockRestore ( )
121-
122- expect ( tester . getByTestId ( 'store' ) ) . toHaveTextContent ( 'customStoreKey - example text' )
123- } )
124105
125106 it ( 'should warn once when receiving a new store in props' , ( ) => {
126107 const store1 = createStore ( ( state = 10 ) => state + 1 )
@@ -190,87 +171,118 @@ describe('React', () => {
190171 innerStore . dispatch ( { type : 'INC' } )
191172 expect ( innerMapStateToProps ) . toHaveBeenCalledTimes ( 2 )
192173 } )
193- } )
194174
195- it ( 'should pass state consistently to mapState' , ( ) => {
196- function stringBuilder ( prev = '' , action ) {
197- return action . type === 'APPEND'
198- ? prev + action . body
199- : prev
200- }
201175
202- const store = createStore ( stringBuilder )
176+ it ( 'should pass state consistently to mapState' , ( ) => {
177+ function stringBuilder ( prev = '' , action ) {
178+ return action . type === 'APPEND'
179+ ? prev + action . body
180+ : prev
181+ }
182+
183+ const store = createStore ( stringBuilder )
203184
204- store . dispatch ( { type : 'APPEND' , body : 'a' } )
205- let childMapStateInvokes = 0
185+ store . dispatch ( { type : 'APPEND' , body : 'a' } )
186+ let childMapStateInvokes = 0
206187
207- @connect ( state => ( { state } ) , null , null , { withRef : true } )
208- class Container extends Component {
209- emitChange ( ) {
210- store . dispatch ( { type : 'APPEND' , body : 'b' } )
211- }
188+ @connect ( state => ( { state } ) , null , null , { withRef : true } )
189+ class Container extends Component {
190+ emitChange ( ) {
191+ store . dispatch ( { type : 'APPEND' , body : 'b' } )
192+ }
212193
213- render ( ) {
214- return (
215- < div >
216- < button onClick = { this . emitChange . bind ( this ) } > change</ button >
217- < ChildContainer parentState = { this . props . state } />
218- </ div >
219- )
194+ render ( ) {
195+ return (
196+ < div >
197+ < button onClick = { this . emitChange . bind ( this ) } > change</ button >
198+ < ChildContainer parentState = { this . props . state } />
199+ </ div >
200+ )
201+ }
220202 }
221- }
222203
223- @connect ( ( state , parentProps ) => {
224- childMapStateInvokes ++
225- // The state from parent props should always be consistent with the current state
226- expect ( state ) . toEqual ( parentProps . parentState )
227- return { }
228- } )
229- class ChildContainer extends Component {
230- render ( ) {
231- return < div />
204+ @connect ( ( state , parentProps ) => {
205+ childMapStateInvokes ++
206+ // The state from parent props should always be consistent with the current state
207+ expect ( state ) . toEqual ( parentProps . parentState )
208+ return { }
209+ } )
210+ class ChildContainer extends Component {
211+ render ( ) {
212+ return < div />
213+ }
232214 }
233- }
234215
235- const tester = rtl . render (
236- < Provider store = { store } >
237- < Container />
238- </ Provider >
239- )
216+ const tester = rtl . render (
217+ < Provider store = { store } >
218+ < Container />
219+ </ Provider >
220+ )
221+
222+ expect ( childMapStateInvokes ) . toBe ( 1 )
240223
241- expect ( childMapStateInvokes ) . toBe ( 1 )
224+ // The store state stays consistent when setState calls are batched
225+ store . dispatch ( { type : 'APPEND' , body : 'c' } )
226+ expect ( childMapStateInvokes ) . toBe ( 2 )
242227
243- // The store state stays consistent when setState calls are batched
244- store . dispatch ( { type : 'APPEND' , body : 'c' } )
245- expect ( childMapStateInvokes ) . toBe ( 2 )
228+ // setState calls DOM handlers are batched
229+ const button = tester . getByText ( 'change' )
230+ rtl . fireEvent . click ( button )
231+ expect ( childMapStateInvokes ) . toBe ( 3 )
246232
247- // setState calls DOM handlers are batched
248- const button = tester . getByText ( 'change' )
249- rtl . fireEvent . click ( button )
250- expect ( childMapStateInvokes ) . toBe ( 3 )
233+ // Provider uses unstable_batchedUpdates() under the hood
234+ store . dispatch ( { type : 'APPEND' , body : 'd' } )
235+ expect ( childMapStateInvokes ) . toBe ( 4 )
236+ } )
251237
252- // Provider uses unstable_batchedUpdates() under the hood
253- store . dispatch ( { type : 'APPEND' , body : 'd' } )
254- expect ( childMapStateInvokes ) . toBe ( 4 )
255- } )
256238
239+ it . skip ( 'works in <StrictMode> without warnings (React 16.3+)' , ( ) => {
240+ if ( ! React . StrictMode ) {
241+ return
242+ }
243+ const spy = jest . spyOn ( console , 'error' ) . mockImplementation ( ( ) => { } )
244+ const store = createStore ( ( ) => ( { } ) )
257245
258- it . skip ( 'works in <StrictMode> without warnings (React 16.3+)' , ( ) => {
259- if ( ! React . StrictMode ) {
260- return
261- }
262- const spy = jest . spyOn ( console , 'error' ) . mockImplementation ( ( ) => { } )
263- const store = createStore ( ( ) => ( { } ) )
246+ rtl . render (
247+ < React . StrictMode >
248+ < Provider store = { store } >
249+ < div />
250+ </ Provider >
251+ </ React . StrictMode >
252+ )
264253
265- rtl . render (
266- < React . StrictMode >
254+ expect ( spy ) . not . toHaveBeenCalled ( )
255+ } )
256+
257+
258+ it ( 'should unsubscribe before unmounting' , ( ) => {
259+ const store = createStore ( createExampleTextReducer ( ) )
260+ const subscribe = store . subscribe
261+
262+ // Keep track of unsubscribe by wrapping subscribe()
263+ const spy = jest . fn ( ( ) => ( { } ) )
264+ store . subscribe = ( listener ) => {
265+ const unsubscribe = subscribe ( listener )
266+ return ( ) => {
267+ spy ( )
268+ return unsubscribe ( )
269+ }
270+ }
271+
272+ const div = document . createElement ( 'div' )
273+ ReactDOM . render (
267274 < Provider store = { store } >
268275 < div />
269- </ Provider >
270- </ React . StrictMode >
271- )
276+ </ Provider > ,
277+ div
278+ )
272279
273- expect ( spy ) . not . toHaveBeenCalled ( )
280+ expect ( spy ) . toHaveBeenCalledTimes ( 0 )
281+ ReactDOM . unmountComponentAtNode ( div )
282+ expect ( spy ) . toHaveBeenCalledTimes ( 1 )
283+ } )
274284 } )
275285
286+
287+
276288} )
0 commit comments