@@ -15,38 +15,89 @@ import { useSplitClient } from '../useSplitClient';
1515import { SplitClient } from '../SplitClient' ;
1616import { SplitContext } from '../SplitContext' ;
1717
18- test ( 'useSplitClient' , ( ) => {
18+ test ( 'useSplitClient must update on SDK events ' , ( ) => {
1919 const outerFactory = SplitSdk ( sdkBrowser ) ;
2020 const mainClient = outerFactory . client ( ) as any ;
2121 const user2Client = outerFactory . client ( 'user_2' ) as any ;
2222
2323 let countSplitContext = 0 , countSplitClient = 0 , countSplitClientUser2 = 0 , countUseSplitClient = 0 , countUseSplitClientUser2 = 0 ;
24+ let countSplitClientWithUpdate = 0 , countUseSplitClientWithUpdate = 0 , countSplitClientUser2WithUpdate = 0 , countUseSplitClientUser2WithUpdate = 0 ;
25+ let countNestedComponent = 0 ;
2426
2527 render (
2628 < SplitFactory factory = { outerFactory } >
2729 < >
2830 < SplitContext . Consumer >
2931 { ( ) => countSplitContext ++ }
3032 </ SplitContext . Consumer >
31- < SplitClient splitKey = { sdkBrowser . core . key } >
33+ < SplitClient splitKey = { sdkBrowser . core . key } trafficType = { sdkBrowser . core . trafficType }
34+ /* Disabling update props is ineffective because the wrapping SplitFactory has them enabled: */
35+ updateOnSdkReady = { false } updateOnSdkReadyFromCache = { false }
36+ >
3237 { ( ) => { countSplitClient ++ ; return null } }
3338 </ SplitClient >
34- < SplitClient splitKey = { 'user_2' } >
35- { ( ) => { countSplitClientUser2 ++ ; return null } }
36- </ SplitClient >
3739 { React . createElement ( ( ) => {
38- const { client } = useSplitClient ( sdkBrowser . core . key , sdkBrowser . core . trafficType , { att1 : 'att1' } ) ;
40+ // Equivalent to
41+ // - Using config key and traffic type: `const { client } = useSplitClient(sdkBrowser.core.key, sdkBrowser.core.trafficType, { att1: 'att1' });`
42+ // - Disabling update props, since the wrapping SplitFactory has them enabled: `const { client } = useSplitClient(undefined, undefined, { att1: 'att1' }, { updateOnSdkReady: false, updateOnSdkReadyFromCache: false });`
43+ const { client } = useSplitClient ( undefined , undefined , { att1 : 'att1' } ) ;
3944 expect ( client ) . toBe ( mainClient ) ; // Assert that the main client was retrieved.
4045 expect ( client ! . getAttributes ( ) ) . toEqual ( { att1 : 'att1' } ) ; // Assert that the client was retrieved with the provided attributes.
4146 countUseSplitClient ++ ;
4247 return null ;
4348 } ) }
49+ < SplitClient splitKey = { 'user_2' } >
50+ { ( ) => { countSplitClientUser2 ++ ; return null } }
51+ </ SplitClient >
4452 { React . createElement ( ( ) => {
4553 const { client } = useSplitClient ( 'user_2' ) ;
4654 expect ( client ) . toBe ( user2Client ) ;
4755 countUseSplitClientUser2 ++ ;
4856 return null ;
4957 } ) }
58+ < SplitClient splitKey = { sdkBrowser . core . key } updateOnSdkUpdate = { true } >
59+ { ( ) => { countSplitClientWithUpdate ++ ; return null } }
60+ </ SplitClient >
61+ { React . createElement ( ( ) => {
62+ useSplitClient ( sdkBrowser . core . key , sdkBrowser . core . trafficType , undefined , { updateOnSdkUpdate : true } ) . client ;
63+ countUseSplitClientWithUpdate ++ ;
64+ return null ;
65+ } ) }
66+ < SplitClient splitKey = { 'user_2' } updateOnSdkUpdate = { true } >
67+ { ( ) => { countSplitClientUser2WithUpdate ++ ; return null } }
68+ </ SplitClient >
69+ { React . createElement ( ( ) => {
70+ useSplitClient ( 'user_2' , undefined , undefined , { updateOnSdkUpdate : true } ) ;
71+ countUseSplitClientUser2WithUpdate ++ ;
72+ return null ;
73+ } ) }
74+ < SplitClient splitKey = { 'user_2' } updateOnSdkUpdate = { true } >
75+ { React . createElement ( ( ) => {
76+ const status = useSplitClient ( 'user_2' , undefined , undefined , { updateOnSdkUpdate : true } ) ;
77+ countNestedComponent ++ ;
78+
79+ expect ( status . client ) . toBe ( user2Client ) ;
80+ switch ( countNestedComponent ) {
81+ case 1 :
82+ expect ( status . isReady ) . toBe ( false ) ;
83+ expect ( status . isReadyFromCache ) . toBe ( false ) ;
84+ break ;
85+ case 2 :
86+ expect ( status . isReady ) . toBe ( false ) ;
87+ expect ( status . isReadyFromCache ) . toBe ( true ) ;
88+ break ;
89+ case 3 :
90+ expect ( status . isReady ) . toBe ( true ) ;
91+ expect ( status . isReadyFromCache ) . toBe ( true ) ;
92+ break ;
93+ case 4 :
94+ break ;
95+ default :
96+ throw new Error ( 'Unexpected render' ) ;
97+ }
98+ return null ;
99+ } ) }
100+ </ SplitClient >
50101 </ >
51102 </ SplitFactory >
52103 ) ;
@@ -70,4 +121,53 @@ test('useSplitClient', () => {
70121 // they render when the context renders and when the new client is ready and ready from cache.
71122 expect ( countSplitClientUser2 ) . toEqual ( countSplitContext + 2 ) ;
72123 expect ( countUseSplitClientUser2 ) . toEqual ( countSplitContext + 2 ) ;
124+
125+ // If SplitClient and useSplitClient retrieve the same client than the context and have updateOnSdkUpdate = true,
126+ // they render when the context renders and when the client updates.
127+ expect ( countSplitClientWithUpdate ) . toEqual ( countSplitContext + 1 ) ;
128+ expect ( countUseSplitClientWithUpdate ) . toEqual ( countSplitContext + 1 ) ;
129+
130+ // If SplitClient and useSplitClient retrieve a different client than the context and have updateOnSdkUpdate = true,
131+ // they render when the context renders and when the new client is ready, ready from cache and updates.
132+ expect ( countSplitClientUser2WithUpdate ) . toEqual ( countSplitContext + 3 ) ;
133+ expect ( countUseSplitClientUser2WithUpdate ) . toEqual ( countSplitContext + 3 ) ;
134+
135+ expect ( countNestedComponent ) . toEqual ( 4 ) ;
136+ } ) ;
137+
138+ test ( 'useSplitClient must support changes in update props' , ( ) => {
139+ const outerFactory = SplitSdk ( sdkBrowser ) ;
140+ const mainClient = outerFactory . client ( ) as any ;
141+
142+ let rendersCount = 0 ;
143+
144+ function InnerComponent ( updateOptions ) {
145+ useSplitClient ( undefined , undefined , undefined , updateOptions ) ;
146+ rendersCount ++ ;
147+ return null ;
148+ }
149+
150+ function Component ( updateOptions ) {
151+ return (
152+ < SplitFactory factory = { outerFactory } >
153+ < InnerComponent { ...updateOptions } />
154+ </ SplitFactory >
155+ )
156+ }
157+
158+ const wrapper = render ( < Component /> ) ;
159+
160+ act ( ( ) => mainClient . __emitter__ . emit ( Event . SDK_READY ) ) ; // trigger re-render
161+ act ( ( ) => mainClient . __emitter__ . emit ( Event . SDK_UPDATE ) ) ; // do not trigger re-render because updateOnSdkUpdate is false by default
162+ expect ( rendersCount ) . toBe ( 2 ) ;
163+
164+ wrapper . rerender ( < Component updateOnSdkUpdate = { true } /> ) ; // trigger re-render
165+ act ( ( ) => mainClient . __emitter__ . emit ( Event . SDK_UPDATE ) ) ; // trigger re-render because updateOnSdkUpdate is true now
166+
167+ expect ( rendersCount ) . toBe ( 4 ) ;
168+
169+ wrapper . rerender ( < Component updateOnSdkUpdate = { false } /> ) ; // trigger re-render
170+ act ( ( ) => mainClient . __emitter__ . emit ( Event . SDK_UPDATE ) ) ; // do not trigger re-render because updateOnSdkUpdate is false now
171+
172+ expect ( rendersCount ) . toBe ( 5 ) ;
73173} ) ;
0 commit comments