Skip to content

Commit 10b939b

Browse files
authored
feat: Added a new getFeatureVariableJson Api (#467)
Summary: Implemented getFeatureVariableJson API Test plan: Added unit tests for getFeatureVariableJson.
1 parent 619dfbc commit 10b939b

File tree

8 files changed

+887
-144
lines changed

8 files changed

+887
-144
lines changed

packages/optimizely-sdk/lib/core/decision_service/index.tests.js

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1147,6 +1147,10 @@ describe('lib/core/decision_service', function() {
11471147
id: '6199684360044544',
11481148
value: '20.25',
11491149
},
1150+
{
1151+
id: '1547854156498475',
1152+
value: '{ "num_buttons": 1, "text": "first variation"}',
1153+
},
11501154
],
11511155
featureEnabled: true,
11521156
key: 'variation',
@@ -1170,6 +1174,10 @@ describe('lib/core/decision_service', function() {
11701174
id: '6199684360044544',
11711175
value: '50.55',
11721176
},
1177+
{
1178+
id: '1547854156498475',
1179+
value: '{ "num_buttons": 2, "text": "second variation"}',
1180+
},
11731181
],
11741182
featureEnabled: true,
11751183
key: 'control',
@@ -1193,6 +1201,10 @@ describe('lib/core/decision_service', function() {
11931201
id: '6199684360044544',
11941202
value: '99.99',
11951203
},
1204+
{
1205+
id: '1547854156498475',
1206+
value: '{ "num_buttons": 3, "text": "third variation"}',
1207+
},
11961208
],
11971209
featureEnabled: false,
11981210
key: 'variation2',
@@ -1224,6 +1236,10 @@ describe('lib/core/decision_service', function() {
12241236
id: '6199684360044544',
12251237
value: '50.55',
12261238
},
1239+
{
1240+
id: '1547854156498475',
1241+
value: '{ "num_buttons": 2, "text": "second variation"}',
1242+
},
12271243
],
12281244
featureEnabled: true,
12291245
key: 'control',
@@ -1247,6 +1263,10 @@ describe('lib/core/decision_service', function() {
12471263
id: '6199684360044544',
12481264
value: '20.25',
12491265
},
1266+
{
1267+
id: '1547854156498475',
1268+
value: '{ "num_buttons": 1, "text": "first variation"}',
1269+
},
12501270
],
12511271
featureEnabled: true,
12521272
key: 'variation',
@@ -1270,6 +1290,10 @@ describe('lib/core/decision_service', function() {
12701290
id: '6199684360044544',
12711291
value: '99.99',
12721292
},
1293+
{
1294+
id: '1547854156498475',
1295+
value: '{ "num_buttons": 3, "text": "third variation"}',
1296+
},
12731297
],
12741298
featureEnabled: false,
12751299
key: 'variation2',
@@ -1295,6 +1319,10 @@ describe('lib/core/decision_service', function() {
12951319
id: '6199684360044544',
12961320
value: '20.25',
12971321
},
1322+
{
1323+
id: '1547854156498475',
1324+
value: '{ "num_buttons": 1, "text": "first variation"}',
1325+
},
12981326
],
12991327
featureEnabled: true,
13001328
key: 'variation',
@@ -1504,6 +1532,10 @@ describe('lib/core/decision_service', function() {
15041532
id: '6327227708866560',
15051533
value: 'Hello audience',
15061534
},
1535+
{
1536+
id: "8765345281230956",
1537+
value: '{ "count": 2, "message": "Hello audience" }',
1538+
},
15071539
],
15081540
featureEnabled: true,
15091541
key: '594032',
@@ -1529,6 +1561,10 @@ describe('lib/core/decision_service', function() {
15291561
id: '6327227708866560',
15301562
value: 'Hello audience',
15311563
},
1564+
{
1565+
id: "8765345281230956",
1566+
value: '{ "count": 2, "message": "Hello audience" }',
1567+
},
15321568
],
15331569
featureEnabled: true,
15341570
key: '594032',
@@ -1557,6 +1593,10 @@ describe('lib/core/decision_service', function() {
15571593
id: '6327227708866560',
15581594
value: 'Hello audience',
15591595
},
1596+
{
1597+
id: "8765345281230956",
1598+
value: '{ "count": 2, "message": "Hello audience" }',
1599+
},
15601600
],
15611601
featureEnabled: true,
15621602
key: '594032',
@@ -1616,6 +1656,10 @@ describe('lib/core/decision_service', function() {
16161656
id: '6327227708866560',
16171657
value: 'Hello',
16181658
},
1659+
{
1660+
id: '8765345281230956',
1661+
value: '{ "count": 1, "message": "Hello" }',
1662+
},
16191663
],
16201664
featureEnabled: false,
16211665
key: '594038',
@@ -1644,6 +1688,10 @@ describe('lib/core/decision_service', function() {
16441688
id: '6327227708866560',
16451689
value: 'Hello',
16461690
},
1691+
{
1692+
id: '8765345281230956',
1693+
value: '{ "count": 1, "message": "Hello" }',
1694+
},
16471695
],
16481696
featureEnabled: false,
16491697
key: '594038',
@@ -1669,6 +1717,10 @@ describe('lib/core/decision_service', function() {
16691717
id: '6327227708866560',
16701718
value: 'Hello',
16711719
},
1720+
{
1721+
id: '8765345281230956',
1722+
value: '{ "count": 1, "message": "Hello" }',
1723+
},
16721724
],
16731725
featureEnabled: false,
16741726
key: '594038',
@@ -1761,6 +1813,10 @@ describe('lib/core/decision_service', function() {
17611813
id: '6327227708866560',
17621814
value: 'Hello',
17631815
},
1816+
{
1817+
id: '8765345281230956',
1818+
value: '{ "count": 1, "message": "Hello" }',
1819+
},
17641820
],
17651821
featureEnabled: false,
17661822
key: '594038',
@@ -1789,6 +1845,10 @@ describe('lib/core/decision_service', function() {
17891845
id: '6327227708866560',
17901846
value: 'Hello',
17911847
},
1848+
{
1849+
id: '8765345281230956',
1850+
value: '{ "count": 1, "message": "Hello" }',
1851+
},
17921852
],
17931853
featureEnabled: false,
17941854
key: '594038',
@@ -1814,6 +1874,10 @@ describe('lib/core/decision_service', function() {
18141874
id: '6327227708866560',
18151875
value: 'Hello',
18161876
},
1877+
{
1878+
id: '8765345281230956',
1879+
value: '{ "count": 1, "message": "Hello" }',
1880+
},
18171881
],
18181882
featureEnabled: false,
18191883
key: '594038',

packages/optimizely-sdk/lib/core/optimizely_config/index.tests.js

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -81,10 +81,13 @@ describe('lib/core/optimizely_config', function() {
8181
});
8282
var variablesMap = featuresMap[featureFlag.key].variablesMap;
8383
featureFlag.variables.forEach(function(variable) {
84+
// json is represented as sub type of string to support backwards compatibility in datafile.
85+
// project config treats it as a first-class type.
86+
var expectedVariableType = (variable.type === "string" && variable.subType === "json") ? "json" : variable.type;
8487
assert.include(variablesMap[variable.key], {
8588
id: variable.id,
8689
key: variable.key,
87-
type: variable.type,
90+
type: expectedVariableType,
8891
value: variable.defaultValue,
8992
});
9093
});
@@ -107,11 +110,21 @@ describe('lib/core/optimizely_config', function() {
107110
variations.forEach(function(variation) {
108111
featureFlag.variables.forEach(function(variable) {
109112
var variableToAssert = variationsMap[variation.key].variablesMap[variable.key];
110-
assert.include(variable, {
111-
id: variableToAssert.id,
112-
key: variableToAssert.key,
113-
type: variableToAssert.type,
114-
});
113+
// json is represented as sub type of string to support backwards compatibility in datafile.
114+
// project config treats it as a first-class type.
115+
var expectedVariableType = (variable.type === "string" && variable.subType === "json") ? "json" : variable.type;
116+
assert.include(
117+
{
118+
id: variable.id,
119+
key: variable.key,
120+
type: expectedVariableType,
121+
},
122+
{
123+
id: variableToAssert.id,
124+
key: variableToAssert.key,
125+
type: variableToAssert.type,
126+
}
127+
);
115128
if (!variation.featureEnabled) {
116129
assert.equal(variable.defaultValue, variableToAssert.value);
117130
}

packages/optimizely-sdk/lib/core/project_config/index.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,15 @@ export var createProjectConfig = function(datafile) {
119119

120120
projectConfig.featureKeyMap = fns.keyBy(projectConfig.featureFlags || [], 'key');
121121
objectValues(projectConfig.featureKeyMap || {}).forEach(function(feature) {
122+
// Json type is represented in datafile as a subtype of string for the sake of backwards compatibility.
123+
// Converting it to a first-class json type while creating Project Config
124+
feature.variables.forEach(function(variable) {
125+
if (variable.type === FEATURE_VARIABLE_TYPES.STRING && variable.subType === FEATURE_VARIABLE_TYPES.JSON) {
126+
variable.type = FEATURE_VARIABLE_TYPES.JSON;
127+
delete variable.subType;
128+
}
129+
});
130+
122131
feature.variableKeyMap = fns.keyBy(feature.variables, 'key');
123132
(feature.experimentIds || []).forEach(function(experimentId) {
124133
// Add this experiment in experiment-feature map.
@@ -479,6 +488,18 @@ export var getTypeCastValue = function(variableValue, variableType, logger) {
479488
}
480489
break;
481490

491+
case FEATURE_VARIABLE_TYPES.JSON:
492+
try {
493+
castValue = JSON.parse(variableValue);
494+
} catch (e) {
495+
logger.log(
496+
LOG_LEVEL.ERROR,
497+
sprintf(ERROR_MESSAGES.UNABLE_TO_CAST_VALUE, MODULE_NAME, variableValue, variableType)
498+
);
499+
castValue = null;
500+
}
501+
break;
502+
482503
default:
483504
// type is STRING
484505
castValue = variableValue;

packages/optimizely-sdk/lib/core/project_config/index.tests.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ describe('lib/core/project_config', function() {
210210
{ value: '395', id: '5482802778734592' },
211211
{ value: '4.99', id: '6045752732155904' },
212212
{ value: 'Hello audience', id: '6327227708866560' },
213+
{ value: '{ "count": 2, "message": "Hello audience" }', id: '8765345281230956' },
213214
],
214215
featureEnabled: true,
215216
key: '594032',
@@ -221,6 +222,7 @@ describe('lib/core/project_config', function() {
221222
{ value: '400', id: '5482802778734592' },
222223
{ value: '14.99', id: '6045752732155904' },
223224
{ value: 'Hello', id: '6327227708866560' },
225+
{ value: '{ "count": 1, "message": "Hello" }', id: '8765345281230956' },
224226
],
225227
featureEnabled: false,
226228
key: '594038',

packages/optimizely-sdk/lib/optimizely/index.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -933,6 +933,30 @@ Optimizely.prototype.getFeatureVariableString = function(featureKey, variableKey
933933
}
934934
};
935935

936+
/**
937+
* Returns value for the given json variable attached to the given feature
938+
* flag.
939+
* @param {string} featureKey Key of the feature whose variable's value is
940+
* being accessed
941+
* @param {string} variableKey Key of the variable whose value is being
942+
* accessed
943+
* @param {string} userId ID for the user
944+
* @param {Object} attributes Optional user attributes
945+
* @return {object|null} Object value of the variable, or null if the
946+
* feature key is invalid, the variable key is
947+
* invalid, or there is a mismatch with the type
948+
* of the variable
949+
*/
950+
Optimizely.prototype.getFeatureVariableJson = function(featureKey, variableKey, userId, attributes) {
951+
try {
952+
return this._getFeatureVariableForType(featureKey, variableKey, FEATURE_VARIABLE_TYPES.JSON, userId, attributes);
953+
} catch (e) {
954+
this.logger.log(LOG_LEVEL.ERROR, e.message);
955+
this.errorHandler.handleError(e);
956+
return null;
957+
}
958+
};
959+
936960
/**
937961
* Returns OptimizelyConfig object containing experiments and features data
938962
* @return {Object}

0 commit comments

Comments
 (0)