1
1
// Sample test
2
- import { defaultState , environmentID , getFlagsmith , getStateToCheck , identityState } from './test-constants' ;
3
- import { promises as fs } from 'fs'
2
+ import { waitFor } from '@testing-library/react' ;
3
+ import { defaultState , getFlagsmith , getStateToCheck , identityState } from './test-constants' ;
4
+ import { promises as fs } from 'fs' ;
4
5
5
6
describe ( 'Flagsmith.init' , ( ) => {
6
-
7
7
beforeEach ( ( ) => {
8
8
// Avoid mocks, but if you need to add them here
9
9
} ) ;
10
10
test ( 'should initialize with expected values' , async ( ) => {
11
- const onChange = jest . fn ( )
12
- const { flagsmith, initConfig, AsyncStorage, mockFetch} = getFlagsmith ( { onChange} )
11
+ const onChange = jest . fn ( ) ;
12
+ const { flagsmith, initConfig, AsyncStorage, mockFetch } = getFlagsmith ( { onChange } ) ;
13
13
await flagsmith . init ( initConfig ) ;
14
14
15
15
expect ( flagsmith . environmentID ) . toBe ( initConfig . environmentID ) ;
@@ -19,14 +19,17 @@ describe('Flagsmith.init', () => {
19
19
expect ( onChange ) . toHaveBeenCalledTimes ( 1 ) ;
20
20
expect ( onChange ) . toHaveBeenCalledWith (
21
21
{ } ,
22
- { " flagsChanged" : Object . keys ( defaultState . flags ) , " isFromServer" : true , " traitsChanged" : null } ,
23
- { " error" : null , " isFetching" : false , " isLoading" : false , " source" : " SERVER" }
22
+ { flagsChanged : Object . keys ( defaultState . flags ) , isFromServer : true , traitsChanged : null } ,
23
+ { error : null , isFetching : false , isLoading : false , source : ' SERVER' } ,
24
24
) ;
25
- expect ( getStateToCheck ( flagsmith . getState ( ) ) ) . toEqual ( defaultState )
25
+ expect ( getStateToCheck ( flagsmith . getState ( ) ) ) . toEqual ( defaultState ) ;
26
26
} ) ;
27
27
test ( 'should initialize with identity' , async ( ) => {
28
- const onChange = jest . fn ( )
29
- const { flagsmith, initConfig, AsyncStorage, mockFetch} = getFlagsmith ( { onChange, identity :"test_identity" } )
28
+ const onChange = jest . fn ( ) ;
29
+ const { flagsmith, initConfig, AsyncStorage, mockFetch } = getFlagsmith ( {
30
+ onChange,
31
+ identity : 'test_identity' ,
32
+ } ) ;
30
33
await flagsmith . init ( initConfig ) ;
31
34
32
35
expect ( flagsmith . environmentID ) . toBe ( initConfig . environmentID ) ;
@@ -36,16 +39,27 @@ describe('Flagsmith.init', () => {
36
39
expect ( onChange ) . toHaveBeenCalledTimes ( 1 ) ;
37
40
expect ( onChange ) . toHaveBeenCalledWith (
38
41
{ } ,
39
- { "flagsChanged" : Object . keys ( defaultState . flags ) , "isFromServer" : true , "traitsChanged" : expect . arrayContaining ( Object . keys ( identityState . evaluationContext . identity . traits ) ) } ,
40
- { "error" : null , "isFetching" : false , "isLoading" : false , "source" : "SERVER" }
42
+ {
43
+ flagsChanged : Object . keys ( defaultState . flags ) ,
44
+ isFromServer : true ,
45
+ traitsChanged : expect . arrayContaining ( Object . keys ( identityState . evaluationContext . identity . traits ) ) ,
46
+ } ,
47
+ { error : null , isFetching : false , isLoading : false , source : 'SERVER' } ,
41
48
) ;
42
- expect ( getStateToCheck ( flagsmith . getState ( ) ) ) . toEqual ( identityState )
49
+ expect ( getStateToCheck ( flagsmith . getState ( ) ) ) . toEqual ( identityState ) ;
43
50
} ) ;
44
51
test ( 'should initialize with identity and traits' , async ( ) => {
45
- const onChange = jest . fn ( )
46
- const testIdentityWithTraits = `test_identity_with_traits`
47
- const { flagsmith, initConfig, AsyncStorage, mockFetch} = getFlagsmith ( { onChange, identity :testIdentityWithTraits , traits :{ number_trait :1 , string_trait :"Example" } } )
48
- mockFetch . mockResolvedValueOnce ( { status : 200 , text : ( ) => fs . readFile ( `./test/data/identities_${ testIdentityWithTraits } .json` , 'utf8' ) } )
52
+ const onChange = jest . fn ( ) ;
53
+ const testIdentityWithTraits = `test_identity_with_traits` ;
54
+ const { flagsmith, initConfig, AsyncStorage, mockFetch } = getFlagsmith ( {
55
+ onChange,
56
+ identity : testIdentityWithTraits ,
57
+ traits : { number_trait : 1 , string_trait : 'Example' } ,
58
+ } ) ;
59
+ mockFetch . mockResolvedValueOnce ( {
60
+ status : 200 ,
61
+ text : ( ) => fs . readFile ( `./test/data/identities_${ testIdentityWithTraits } .json` , 'utf8' ) ,
62
+ } ) ;
49
63
50
64
await flagsmith . init ( initConfig ) ;
51
65
@@ -56,97 +70,182 @@ describe('Flagsmith.init', () => {
56
70
expect ( onChange ) . toHaveBeenCalledTimes ( 1 ) ;
57
71
expect ( onChange ) . toHaveBeenCalledWith (
58
72
{ } ,
59
- { "flagsChanged" : Object . keys ( defaultState . flags ) , "isFromServer" : true , "traitsChanged" : [ "number_trait" , "string_trait" ] } ,
60
- { "error" : null , "isFetching" : false , "isLoading" : false , "source" : "SERVER" }
73
+ {
74
+ flagsChanged : Object . keys ( defaultState . flags ) ,
75
+ isFromServer : true ,
76
+ traitsChanged : [ 'number_trait' , 'string_trait' ] ,
77
+ } ,
78
+ { error : null , isFetching : false , isLoading : false , source : 'SERVER' } ,
61
79
) ;
62
80
expect ( getStateToCheck ( flagsmith . getState ( ) ) ) . toEqual ( {
63
81
...identityState ,
64
82
evaluationContext : {
65
83
...identityState . evaluationContext ,
66
84
identity : {
67
85
...identityState . evaluationContext . identity ,
68
- identifier : testIdentityWithTraits
86
+ identifier : testIdentityWithTraits ,
69
87
} ,
70
88
} ,
71
- } )
89
+ } ) ;
72
90
} ) ;
73
91
test ( 'should reject initialize with identity no key' , async ( ) => {
74
- const onChange = jest . fn ( )
75
- const { flagsmith, initConfig} = getFlagsmith ( { onChange, evaluationContext :{ environment :{ apiKey : "" } } } )
92
+ const onChange = jest . fn ( ) ;
93
+ const { flagsmith, initConfig } = getFlagsmith ( {
94
+ onChange,
95
+ evaluationContext : { environment : { apiKey : '' } } ,
96
+ } ) ;
76
97
await expect ( flagsmith . init ( initConfig ) ) . rejects . toThrow ( Error ) ;
77
98
} ) ;
78
99
test ( 'should reject initialize with identity bad key' , async ( ) => {
79
- const onChange = jest . fn ( )
80
- const { flagsmith, initConfig, mockFetch} = getFlagsmith ( { onChange, environmentID :" bad" } )
81
- mockFetch . mockResolvedValueOnce ( { status : 404 , text : async ( ) => '' } )
100
+ const onChange = jest . fn ( ) ;
101
+ const { flagsmith, initConfig, mockFetch } = getFlagsmith ( { onChange, environmentID : ' bad' } ) ;
102
+ mockFetch . mockResolvedValueOnce ( { status : 404 , text : async ( ) => '' } ) ;
82
103
await expect ( flagsmith . init ( initConfig ) ) . rejects . toThrow ( Error ) ;
83
104
} ) ;
84
105
test ( 'identifying with new identity should not carry over previous traits for different identity' , async ( ) => {
85
- const onChange = jest . fn ( )
86
- const identityA = `test_identity_a`
87
- const identityB = `test_identity_b`
88
- const { flagsmith, initConfig, mockFetch} = getFlagsmith ( { onChange, identity :identityA , traits : { a :`example` } } )
89
- mockFetch . mockResolvedValueOnce ( { status : 200 , text : ( ) => fs . readFile ( `./test/data/identities_${ identityA } .json` , 'utf8' ) } )
106
+ const onChange = jest . fn ( ) ;
107
+ const identityA = `test_identity_a` ;
108
+ const identityB = `test_identity_b` ;
109
+ const { flagsmith, initConfig, mockFetch } = getFlagsmith ( {
110
+ onChange,
111
+ identity : identityA ,
112
+ traits : { a : `example` } ,
113
+ } ) ;
114
+ mockFetch . mockResolvedValueOnce ( {
115
+ status : 200 ,
116
+ text : ( ) => fs . readFile ( `./test/data/identities_${ identityA } .json` , 'utf8' ) ,
117
+ } ) ;
90
118
await flagsmith . init ( initConfig ) ;
91
- expect ( flagsmith . getTrait ( "a" ) ) . toEqual ( `example` )
92
- mockFetch . mockResolvedValueOnce ( { status : 200 , text : ( ) => fs . readFile ( `./test/data/identities_${ identityB } .json` , 'utf8' ) } )
93
- await flagsmith . identify ( identityB )
94
- expect ( flagsmith . getTrait ( "a" ) ) . toEqual ( undefined )
95
- mockFetch . mockResolvedValueOnce ( { status : 200 , text : ( ) => fs . readFile ( `./test/data/identities_${ identityA } .json` , 'utf8' ) } )
96
- await flagsmith . identify ( identityA )
97
- expect ( flagsmith . getTrait ( "a" ) ) . toEqual ( `example` )
98
- mockFetch . mockResolvedValueOnce ( { status : 200 , text : ( ) => fs . readFile ( `./test/data/identities_${ identityB } .json` , 'utf8' ) } )
99
- await flagsmith . identify ( identityB )
100
- expect ( flagsmith . getTrait ( "a" ) ) . toEqual ( undefined )
119
+ expect ( flagsmith . getTrait ( 'a' ) ) . toEqual ( `example` ) ;
120
+ mockFetch . mockResolvedValueOnce ( {
121
+ status : 200 ,
122
+ text : ( ) => fs . readFile ( `./test/data/identities_${ identityB } .json` , 'utf8' ) ,
123
+ } ) ;
124
+ await flagsmith . identify ( identityB ) ;
125
+ expect ( flagsmith . getTrait ( 'a' ) ) . toEqual ( undefined ) ;
126
+ mockFetch . mockResolvedValueOnce ( {
127
+ status : 200 ,
128
+ text : ( ) => fs . readFile ( `./test/data/identities_${ identityA } .json` , 'utf8' ) ,
129
+ } ) ;
130
+ await flagsmith . identify ( identityA ) ;
131
+ expect ( flagsmith . getTrait ( 'a' ) ) . toEqual ( `example` ) ;
132
+ mockFetch . mockResolvedValueOnce ( {
133
+ status : 200 ,
134
+ text : ( ) => fs . readFile ( `./test/data/identities_${ identityB } .json` , 'utf8' ) ,
135
+ } ) ;
136
+ await flagsmith . identify ( identityB ) ;
137
+ expect ( flagsmith . getTrait ( 'a' ) ) . toEqual ( undefined ) ;
101
138
} ) ;
102
139
test ( 'identifying with transient identity should request the API correctly' , async ( ) => {
103
- const onChange = jest . fn ( )
104
- const testTransientIdentity = `test_transient_identity`
140
+ const onChange = jest . fn ( ) ;
141
+ const testTransientIdentity = `test_transient_identity` ;
105
142
const evaluationContext = {
106
- identity : { identifier : testTransientIdentity , transient : true }
107
- }
108
- const { flagsmith, initConfig, mockFetch} = getFlagsmith ( { onChange, evaluationContext} )
109
- mockFetch . mockResolvedValueOnce ( { status : 200 , text : ( ) => fs . readFile ( `./test/data/identities_${ testTransientIdentity } .json` , 'utf8' ) } )
143
+ identity : { identifier : testTransientIdentity , transient : true } ,
144
+ } ;
145
+ const { flagsmith, initConfig, mockFetch } = getFlagsmith ( { onChange, evaluationContext } ) ;
146
+ mockFetch . mockResolvedValueOnce ( {
147
+ status : 200 ,
148
+ text : ( ) => fs . readFile ( `./test/data/identities_${ testTransientIdentity } .json` , 'utf8' ) ,
149
+ } ) ;
110
150
await flagsmith . init ( initConfig ) ;
111
- expect ( mockFetch ) . toHaveBeenCalledWith ( `https://edge.api.flagsmith.com/api/v1/identities/?identifier=${ testTransientIdentity } &transient=true` ,
112
- expect . objectContaining ( { method : 'GET' } ) ,
113
- )
151
+ expect ( mockFetch ) . toHaveBeenCalledWith (
152
+ `https://edge.api.flagsmith.com/api/v1/identities/?identifier=${ testTransientIdentity } &transient=true` ,
153
+ expect . objectContaining ( { method : 'GET' } ) ,
154
+ ) ;
114
155
} ) ;
115
156
test ( 'identifying with transient traits should request the API correctly' , async ( ) => {
116
- const onChange = jest . fn ( )
117
- const testIdentityWithTransientTraits = `test_identity_with_transient_traits`
157
+ const onChange = jest . fn ( ) ;
158
+ const testIdentityWithTransientTraits = `test_identity_with_transient_traits` ;
118
159
const evaluationContext = {
119
160
identity : {
120
161
identifier : testIdentityWithTransientTraits ,
121
162
traits : {
122
- number_trait : { value : 1 } ,
123
- string_trait : { value : 'Example' } ,
124
- transient_trait : { value : 'Example' , transient : true } ,
125
- }
126
- }
127
- }
128
- const { flagsmith, initConfig, mockFetch} = getFlagsmith ( { onChange, evaluationContext} )
129
- mockFetch . mockResolvedValueOnce ( { status : 200 , text : ( ) => fs . readFile ( `./test/data/identities_${ testIdentityWithTransientTraits } .json` , 'utf8' ) } )
163
+ number_trait : { value : 1 } ,
164
+ string_trait : { value : 'Example' } ,
165
+ transient_trait : { value : 'Example' , transient : true } ,
166
+ } ,
167
+ } ,
168
+ } ;
169
+ const { flagsmith, initConfig, mockFetch } = getFlagsmith ( { onChange, evaluationContext } ) ;
170
+ mockFetch . mockResolvedValueOnce ( {
171
+ status : 200 ,
172
+ text : ( ) => fs . readFile ( `./test/data/identities_${ testIdentityWithTransientTraits } .json` , 'utf8' ) ,
173
+ } ) ;
130
174
await flagsmith . init ( initConfig ) ;
131
- expect ( mockFetch ) . toHaveBeenCalledWith ( 'https://edge.api.flagsmith.com/api/v1/identities/' ,
132
- expect . objectContaining ( { method : 'POST' , body : JSON . stringify ( {
133
- "identifier" : testIdentityWithTransientTraits ,
134
- "traits" : [
135
- {
136
- "trait_key" : "number_trait" ,
137
- "trait_value" : 1
138
- } ,
139
- {
140
- "trait_key" : "string_trait" ,
141
- "trait_value" : "Example"
142
- } ,
143
- {
144
- "trait_key" : "transient_trait" ,
145
- "trait_value" : "Example" ,
146
- "transient" : true
147
- }
148
- ]
149
- } ) } ) ,
150
- )
175
+ expect ( mockFetch ) . toHaveBeenCalledWith (
176
+ 'https://edge.api.flagsmith.com/api/v1/identities/' ,
177
+ expect . objectContaining ( {
178
+ method : 'POST' ,
179
+ body : JSON . stringify ( {
180
+ identifier : testIdentityWithTransientTraits ,
181
+ traits : [
182
+ {
183
+ trait_key : 'number_trait' ,
184
+ trait_value : 1 ,
185
+ } ,
186
+ {
187
+ trait_key : 'string_trait' ,
188
+ trait_value : 'Example' ,
189
+ } ,
190
+ {
191
+ trait_key : 'transient_trait' ,
192
+ trait_value : 'Example' ,
193
+ transient : true ,
194
+ } ,
195
+ ] ,
196
+ } ) ,
197
+ } ) ,
198
+ ) ;
199
+ } ) ;
200
+ test ( 'should not reject but call onError, when the API cannot be reached with the cache populated' , async ( ) => {
201
+ const onError = jest . fn ( ) ;
202
+ const { flagsmith, initConfig, AsyncStorage } = getFlagsmith ( {
203
+ cacheFlags : true ,
204
+ fetch : async ( ) => {
205
+ return Promise . resolve ( { text : ( ) => Promise . resolve ( 'Mocked fetch error' ) , ok : false , status : 401 } ) ;
206
+ } ,
207
+ onError,
208
+ } ) ;
209
+ await AsyncStorage . setItem ( 'BULLET_TRAIN_DB' , JSON . stringify ( defaultState ) ) ;
210
+ await flagsmith . init ( initConfig ) ;
211
+
212
+ expect ( getStateToCheck ( flagsmith . getState ( ) ) ) . toEqual ( defaultState ) ;
213
+
214
+ await waitFor ( ( ) => {
215
+ expect ( onError ) . toHaveBeenCalledTimes ( 1 ) ;
216
+ } ) ;
217
+ expect ( onError ) . toHaveBeenCalledWith ( new Error ( 'Mocked fetch error' ) ) ;
218
+ } ) ;
219
+ test ( 'should not reject when the API cannot be reached but default flags are set' , async ( ) => {
220
+ const { flagsmith, initConfig } = getFlagsmith ( {
221
+ defaultFlags : defaultState . flags ,
222
+ cacheFlags : true ,
223
+ fetch : async ( ) => {
224
+ return Promise . resolve ( { text : ( ) => Promise . resolve ( 'Mocked fetch error' ) , ok : false , status : 401 } ) ;
225
+ } ,
226
+ } ) ;
227
+ await flagsmith . init ( initConfig ) ;
228
+
229
+ expect ( getStateToCheck ( flagsmith . getState ( ) ) ) . toEqual ( defaultState ) ;
230
+ } ) ;
231
+ test ( 'should not reject but call onError, when the identities/ API cannot be reached with the cache populated' , async ( ) => {
232
+ const onError = jest . fn ( ) ;
233
+ const { flagsmith, initConfig, AsyncStorage } = getFlagsmith ( {
234
+ evaluationContext : identityState . evaluationContext ,
235
+ cacheFlags : true ,
236
+ fetch : async ( ) => {
237
+ return Promise . resolve ( { text : ( ) => Promise . resolve ( 'Mocked fetch error' ) , ok : false , status : 401 } ) ;
238
+ } ,
239
+ onError,
240
+ } ) ;
241
+ await AsyncStorage . setItem ( 'BULLET_TRAIN_DB' , JSON . stringify ( identityState ) ) ;
242
+ await flagsmith . init ( initConfig ) ;
243
+
244
+ expect ( getStateToCheck ( flagsmith . getState ( ) ) ) . toEqual ( identityState ) ;
245
+
246
+ await waitFor ( ( ) => {
247
+ expect ( onError ) . toHaveBeenCalledTimes ( 1 ) ;
248
+ } ) ;
249
+ expect ( onError ) . toHaveBeenCalledWith ( new Error ( 'Mocked fetch error' ) ) ;
151
250
} ) ;
152
251
} ) ;
0 commit comments