@@ -105,6 +105,7 @@ const verifyBucketCall = (
105
105
projectConfig : ProjectConfig ,
106
106
experiment : Experiment ,
107
107
user : OptimizelyUserContext ,
108
+ bucketIdFromAttribute = false ,
108
109
) => {
109
110
const {
110
111
experimentId,
@@ -125,7 +126,7 @@ const verifyBucketCall = (
125
126
expect ( experimentIdMap ) . toBe ( projectConfig . experimentIdMap ) ;
126
127
expect ( groupIdMap ) . toBe ( projectConfig . groupIdMap ) ;
127
128
expect ( variationIdMap ) . toBe ( projectConfig . variationIdMap ) ;
128
- expect ( bucketingId ) . toBe ( user . getAttributes ( ) [ CONTROL_ATTRIBUTES . BUCKETING_ID ] || user . getUserId ( ) ) ;
129
+ expect ( bucketingId ) . toBe ( bucketIdFromAttribute ? user . getAttributes ( ) [ CONTROL_ATTRIBUTES . BUCKETING_ID ] : user . getUserId ( ) ) ;
129
130
} ;
130
131
131
132
describe ( 'DecisionService' , ( ) => {
@@ -161,6 +162,36 @@ describe('DecisionService', () => {
161
162
verifyBucketCall ( 0 , config , experiment , user ) ;
162
163
} ) ;
163
164
165
+ it ( 'should use $opt_bucketing_id attribute as bucketing id if provided' , ( ) => {
166
+ const user = new OptimizelyUserContext ( {
167
+ optimizely : { } as any ,
168
+ userId : 'tester' ,
169
+ attributes : {
170
+ $opt_bucketing_id : 'test_bucketing_id' ,
171
+ } ,
172
+ } ) ;
173
+
174
+ const config = createProjectConfig ( cloneDeep ( testData ) ) ;
175
+
176
+ const fakeDecisionResponse = {
177
+ result : '111128' ,
178
+ reasons : [ ] ,
179
+ } ;
180
+
181
+ const experiment = config . experimentIdMap [ '111127' ] ;
182
+
183
+ mockBucket . mockReturnValue ( fakeDecisionResponse ) ; // contains variation ID of the 'control' variation from `test_data`
184
+
185
+ const { decisionService } = getDecisionService ( ) ;
186
+
187
+ const variation = decisionService . getVariation ( config , experiment , user ) ;
188
+
189
+ expect ( variation . result ) . toBe ( 'control' ) ;
190
+
191
+ expect ( mockBucket ) . toHaveBeenCalledTimes ( 1 ) ;
192
+ verifyBucketCall ( 0 , config , experiment , user , true ) ;
193
+ } ) ;
194
+
164
195
it ( 'should return the whitelisted variation if the user is whitelisted' , function ( ) {
165
196
const user = new OptimizelyUserContext ( {
166
197
optimizely : { } as any ,
@@ -977,6 +1008,61 @@ describe('DecisionService', () => {
977
1008
verifyBucketCall ( 0 , config , config . experimentIdMap [ '3002' ] , user ) ;
978
1009
} ) ;
979
1010
1011
+ it ( 'should return variation from the target delivery and use $opt_bucketing_id attribute as bucketing id' , ( ) => {
1012
+ const { decisionService } = getDecisionService ( ) ;
1013
+
1014
+ const resolveVariationSpy = vi . spyOn ( decisionService as any , 'resolveVariation' )
1015
+ . mockReturnValue ( {
1016
+ result : null ,
1017
+ reasons : [ ] ,
1018
+ } ) ;
1019
+
1020
+ const config = createProjectConfig ( getDecisionTestDatafile ( ) ) ;
1021
+
1022
+ const user = new OptimizelyUserContext ( {
1023
+ optimizely : { } as any ,
1024
+ userId : 'tester' ,
1025
+ attributes : {
1026
+ age : 55 , // this should satisfy the audience condition for the targeted delivery with key delivery_2 and delivery_3
1027
+ $opt_bucketing_id : 'test_bucketing_id' ,
1028
+ } ,
1029
+ } ) ;
1030
+
1031
+ mockBucket . mockImplementation ( ( param : BucketerParams ) => {
1032
+ const ruleKey = param . experimentKey ;
1033
+ if ( ruleKey === 'delivery_2' ) {
1034
+ return {
1035
+ result : '5005' ,
1036
+ reasons : [ ] ,
1037
+ } ;
1038
+ }
1039
+ return {
1040
+ result : null ,
1041
+ reasons : [ ] ,
1042
+ } ;
1043
+ } ) ;
1044
+
1045
+ const feature = config . featureKeyMap [ 'flag_1' ] ;
1046
+ const variation = decisionService . getVariationForFeature ( config , feature , user ) ;
1047
+
1048
+ expect ( variation . result ) . toEqual ( {
1049
+ experiment : config . experimentKeyMap [ 'delivery_2' ] ,
1050
+ variation : config . variationIdMap [ '5005' ] ,
1051
+ decisionSource : DECISION_SOURCES . ROLLOUT ,
1052
+ } ) ;
1053
+
1054
+ expect ( resolveVariationSpy ) . toHaveBeenCalledTimes ( 3 ) ;
1055
+ expect ( resolveVariationSpy ) . toHaveBeenNthCalledWith ( 1 ,
1056
+ config , config . experimentKeyMap [ 'exp_1' ] , user , false , expect . anything ( ) ) ;
1057
+ expect ( resolveVariationSpy ) . toHaveBeenNthCalledWith ( 2 ,
1058
+ config , config . experimentKeyMap [ 'exp_2' ] , user , false , expect . anything ( ) ) ;
1059
+ expect ( resolveVariationSpy ) . toHaveBeenNthCalledWith ( 3 ,
1060
+ config , config . experimentKeyMap [ 'exp_3' ] , user , false , expect . anything ( ) ) ;
1061
+
1062
+ expect ( mockBucket ) . toHaveBeenCalledTimes ( 1 ) ;
1063
+ verifyBucketCall ( 0 , config , config . experimentIdMap [ '3002' ] , user , true ) ;
1064
+ } ) ;
1065
+
980
1066
it ( 'should skip to everyone else targeting rule if the user is not bucketed \
981
1067
into the targeted delivery for which audience condition is satisfied' , ( ) => {
982
1068
const { decisionService } = getDecisionService ( ) ;
0 commit comments