diff --git a/packages/optimizely-sdk/lib/core/decision_service/index.tests.js b/packages/optimizely-sdk/lib/core/decision_service/index.tests.js index c8cb21a62..00124fcea 100644 --- a/packages/optimizely-sdk/lib/core/decision_service/index.tests.js +++ b/packages/optimizely-sdk/lib/core/decision_service/index.tests.js @@ -743,6 +743,29 @@ describe('lib/core/decision_service', function() { ], 'featureEnabled': true, 'key': 'control' + }, + { + 'id': '594099', + 'variables': [ + { + 'id': '4792309476491264', + 'value': '40' + }, + { + 'id': '5073784453201920', + 'value': 'true' + }, + { + 'id': '5636734406623232', + 'value': 'Buy me Later' + }, + { + 'id': '6199684360044544', + 'value': '99.99' + } + ], + 'featureEnabled': false, + 'key': 'variation2' } ], 'audienceIds': [], @@ -798,6 +821,29 @@ describe('lib/core/decision_service', function() { 'featureEnabled': true, 'key': 'variation' }, + variation2: { + 'id': '594099', + 'variables': [ + { + 'id': '4792309476491264', + 'value': '40' + }, + { + 'id': '5073784453201920', + 'value': 'true' + }, + { + 'id': '5636734406623232', + 'value': 'Buy me Later' + }, + { + 'id': '6199684360044544', + 'value': '99.99' + } + ], + 'featureEnabled': false, + 'key': 'variation2' + } }, }, variation: { diff --git a/packages/optimizely-sdk/lib/optimizely/index.js b/packages/optimizely-sdk/lib/optimizely/index.js index f3cd6476a..1212dc149 100644 --- a/packages/optimizely-sdk/lib/optimizely/index.js +++ b/packages/optimizely-sdk/lib/optimizely/index.js @@ -632,35 +632,46 @@ Optimizely.prototype._getFeatureVariableForType = function(featureKey, variableK return null; } - var decision = this.decisionService.getVariationForFeature(this.configObj, featureFlag, userId, attributes); var variableValue; + var featureEnabled = false; + var decision = this.decisionService.getVariationForFeature(this.configObj, featureFlag, userId, attributes); + if (decision.variation !== null) { - variableValue = projectConfig.getVariableValueForVariation( - this.configObj, - variable, - decision.variation, - this.logger - ); - this.logger.log( - LOG_LEVEL.INFO, - sprintf( - LOG_MESSAGES.USER_RECEIVED_VARIABLE_VALUE, - MODULE_NAME, - variableKey, - featureFlag.key, - variableValue, - userId - ) - ); + featureEnabled = decision.variation.featureEnabled; + variableValue = projectConfig.getVariableValueForVariation(this.configObj, variable, decision.variation, this.logger); + this.logger.log(LOG_LEVEL.INFO, sprintf(LOG_MESSAGES.USER_RECEIVED_VARIABLE_VALUE, MODULE_NAME, variableKey, featureFlag.key, variableValue, userId)); } else { variableValue = variable.defaultValue; - this.logger.log( - LOG_LEVEL.INFO, - sprintf(LOG_MESSAGES.USER_RECEIVED_DEFAULT_VARIABLE_VALUE, MODULE_NAME, userId, variableKey, featureFlag.key) - ); + this.logger.log(LOG_LEVEL.INFO, sprintf(LOG_MESSAGES.USER_RECEIVED_DEFAULT_VARIABLE_VALUE, MODULE_NAME, userId, variableKey, featureFlag.key)); } - return projectConfig.getTypeCastValue(variableValue, variableType, this.logger); + var experimentKey = null; + var variationKey = null; + if (decision.decisionSource === DECISION_SOURCES.EXPERIMENT) { + experimentKey = decision.experiment.key; + variationKey = decision.variation.key; + } + + var typeCastedValue = projectConfig.getTypeCastValue(variableValue, variableType, this.logger); + this.notificationCenter.sendNotifications( + enums.NOTIFICATION_TYPES.DECISION, + { + type: DECISION_INFO_TYPES.FEATURE_VARIABLE, + userId: userId, + attributes: attributes || {}, + decisionInfo: { + featureKey: featureKey, + featureEnabled: featureEnabled, + variableKey: variableKey, + variableValue: typeCastedValue, + variableType: variableType, + source: decision.decisionSource, + sourceExperimentKey: experimentKey, + sourceVariationKey: variationKey + } + } + ); + return typeCastedValue; }; /** diff --git a/packages/optimizely-sdk/lib/optimizely/index.tests.js b/packages/optimizely-sdk/lib/optimizely/index.tests.js index 1e466acf1..2168cd16d 100644 --- a/packages/optimizely-sdk/lib/optimizely/index.tests.js +++ b/packages/optimizely-sdk/lib/optimizely/index.tests.js @@ -41,6 +41,7 @@ var LOG_LEVEL = enums.LOG_LEVEL; var LOG_MESSAGES = enums.LOG_MESSAGES; var DECISION_SOURCES = enums.DECISION_SOURCES; var DECISION_INFO_TYPES = enums.DECISION_INFO_TYPES; +var FEATURE_VARIABLE_TYPES = enums.FEATURE_VARIABLE_TYPES; describe('lib/optimizely', function() { describe('constructor', function() { @@ -2438,7 +2439,7 @@ describe('lib/optimizely', function() { }); }); }); - + describe('feature management', function() { var sandbox = sinon.sandbox.create(); @@ -2446,9 +2447,7 @@ describe('lib/optimizely', function() { optlyInstance = new Optimizely({ clientEngine: 'node-sdk', datafile: testData.getTestProjectConfigWithFeatures(), - eventBuilder: eventBuilder, errorHandler: errorHandler, - eventDispatcher: eventDispatcher, jsonSchemaValidator: jsonSchemaValidator, logger: createdLogger, isValidInstance: true, @@ -2572,7 +2571,7 @@ describe('lib/optimizely', function() { }); }); - it('returns false and send notification', function() { + it('should return false and send notification', function() { var result = optlyInstance.isFeatureEnabled('test_feature', 'user1', { test_attribute: 'test_value', }); @@ -2605,7 +2604,7 @@ describe('lib/optimizely', function() { }); }); - it('returns false and send notification', function() { + it('should return false and send notification', function() { var result = optlyInstance.isFeatureEnabled('test_feature', 'user1'); assert.strictEqual(result, false); sinon.assert.calledWith(decisionListener, { @@ -2623,6 +2622,470 @@ describe('lib/optimizely', function() { }); }); }); + + describe('feature variable APIs', function() { + describe('bucketed into variation of an experiment with variable values', function() { + describe('when the variation is toggled ON', function() { + beforeEach(function() { + var experiment = projectConfig.getExperimentFromKey(optlyInstance.configObj, 'testing_my_feature'); + var variation = experiment.variations[0]; + sandbox.stub(optlyInstance.decisionService, 'getVariationForFeature').returns({ + experiment: experiment, + variation: variation, + decisionSource: DECISION_SOURCES.EXPERIMENT, + }); + }); + + it('returns the right value from getFeatureVariableBoolean and send notification with featureEnabled true', function() { + var result = optlyInstance.getFeatureVariableBoolean('test_feature_for_experiment', 'is_button_animated', 'user1', { test_attribute: 'test_value' }); + assert.strictEqual(result, true); + sinon.assert.calledWith(decisionListener, { + type: DECISION_INFO_TYPES.FEATURE_VARIABLE, + userId: 'user1', + attributes: { test_attribute: 'test_value' }, + decisionInfo: { + featureKey: 'test_feature_for_experiment', + featureEnabled: true, + variableKey: 'is_button_animated', + variableValue: true, + variableType: FEATURE_VARIABLE_TYPES.BOOLEAN, + source: DECISION_SOURCES.EXPERIMENT, + sourceExperimentKey: 'testing_my_feature', + sourceVariationKey: 'variation' + } + }); + }); + + it('returns the right value from getFeatureVariableDouble and send notification with featureEnabled true', function() { + var result = optlyInstance.getFeatureVariableDouble('test_feature_for_experiment', 'button_width', 'user1', { test_attribute: 'test_value' }); + assert.strictEqual(result, 20.25); + sinon.assert.calledWith(decisionListener, { + type: DECISION_INFO_TYPES.FEATURE_VARIABLE, + userId: 'user1', + attributes: { test_attribute: 'test_value' }, + decisionInfo: { + featureKey: 'test_feature_for_experiment', + featureEnabled: true, + variableKey: 'button_width', + variableValue: 20.25, + variableType: FEATURE_VARIABLE_TYPES.DOUBLE, + source: DECISION_SOURCES.EXPERIMENT, + sourceExperimentKey: 'testing_my_feature', + sourceVariationKey: 'variation' + } + }); + }); + + it('returns the right value from getFeatureVariableInteger and send notification with featureEnabled true', function() { + var result = optlyInstance.getFeatureVariableInteger('test_feature_for_experiment', 'num_buttons', 'user1', { test_attribute: 'test_value' }); + assert.strictEqual(result, 2); + sinon.assert.calledWith(decisionListener, { + type: DECISION_INFO_TYPES.FEATURE_VARIABLE, + userId: 'user1', + attributes: { test_attribute: 'test_value' }, + decisionInfo: { + featureKey: 'test_feature_for_experiment', + featureEnabled: true, + variableKey: 'num_buttons', + variableValue: 2, + variableType: FEATURE_VARIABLE_TYPES.INTEGER, + source: DECISION_SOURCES.EXPERIMENT, + sourceExperimentKey: 'testing_my_feature', + sourceVariationKey: 'variation' + } + }); + }); + + it('returns the right value from getFeatureVariableString and send notification with featureEnabled true', function() { + var result = optlyInstance.getFeatureVariableString('test_feature_for_experiment', 'button_txt', 'user1', { test_attribute: 'test_value' }); + assert.strictEqual(result, 'Buy me NOW'); + sinon.assert.calledWith(decisionListener, { + type: DECISION_INFO_TYPES.FEATURE_VARIABLE, + userId: 'user1', + attributes: { test_attribute: 'test_value' }, + decisionInfo: { + featureKey: 'test_feature_for_experiment', + featureEnabled: true, + variableKey: 'button_txt', + variableValue: 'Buy me NOW', + variableType: FEATURE_VARIABLE_TYPES.STRING, + source: DECISION_SOURCES.EXPERIMENT, + sourceExperimentKey: 'testing_my_feature', + sourceVariationKey: 'variation' + } + }); + }); + }); + + describe('when the variation is toggled OFF', function() { + beforeEach(function() { + var experiment = projectConfig.getExperimentFromKey(optlyInstance.configObj, 'testing_my_feature'); + var variation = experiment.variations[2]; + sandbox.stub(optlyInstance.decisionService, 'getVariationForFeature').returns({ + experiment: experiment, + variation: variation, + decisionSource: DECISION_SOURCES.EXPERIMENT, + }); + }); + + it('returns the right value from getFeatureVariableBoolean and send notification with featureEnabled false', function() { + var result = optlyInstance.getFeatureVariableBoolean('test_feature_for_experiment', 'is_button_animated', 'user1', { test_attribute: 'test_value' }); + assert.strictEqual(result, true); + sinon.assert.calledWith(decisionListener, { + type: DECISION_INFO_TYPES.FEATURE_VARIABLE, + userId: 'user1', + attributes: { test_attribute: 'test_value' }, + decisionInfo: { + featureKey: 'test_feature_for_experiment', + featureEnabled: false, + variableKey: 'is_button_animated', + variableValue: true, + variableType: FEATURE_VARIABLE_TYPES.BOOLEAN, + source: DECISION_SOURCES.EXPERIMENT, + sourceExperimentKey: 'testing_my_feature', + sourceVariationKey: 'variation2' + } + }); + }); + + it('returns the right value from getFeatureVariableDouble and send notification with featureEnabled false', function() { + var result = optlyInstance.getFeatureVariableDouble('test_feature_for_experiment', 'button_width', 'user1', { test_attribute: 'test_value' }); + assert.strictEqual(result, 99.99); + sinon.assert.calledWith(decisionListener, { + type: DECISION_INFO_TYPES.FEATURE_VARIABLE, + userId: 'user1', + attributes: { test_attribute: 'test_value' }, + decisionInfo: { + featureKey: 'test_feature_for_experiment', + featureEnabled: false, + variableKey: 'button_width', + variableValue: 99.99, + variableType: FEATURE_VARIABLE_TYPES.DOUBLE, + source: DECISION_SOURCES.EXPERIMENT, + sourceExperimentKey: 'testing_my_feature', + sourceVariationKey: 'variation2' + } + }); + }); + + it('returns the right value from getFeatureVariableInteger and send notification with featureEnabled false', function() { + var result = optlyInstance.getFeatureVariableInteger('test_feature_for_experiment', 'num_buttons', 'user1', { test_attribute: 'test_value' }); + assert.strictEqual(result, 40); + sinon.assert.calledWith(decisionListener, { + type: DECISION_INFO_TYPES.FEATURE_VARIABLE, + userId: 'user1', + attributes: { test_attribute: 'test_value' }, + decisionInfo: { + featureKey: 'test_feature_for_experiment', + featureEnabled: false, + variableKey: 'num_buttons', + variableValue: 40, + variableType: FEATURE_VARIABLE_TYPES.INTEGER, + source: DECISION_SOURCES.EXPERIMENT, + sourceExperimentKey: 'testing_my_feature', + sourceVariationKey: 'variation2' + } + }); + }); + + it('returns the right value from getFeatureVariableString and send notification with featureEnabled false', function() { + var result = optlyInstance.getFeatureVariableString('test_feature_for_experiment', 'button_txt', 'user1', { test_attribute: 'test_value' }); + assert.strictEqual(result, 'Buy me Later'); + sinon.assert.calledWith(decisionListener, { + type: DECISION_INFO_TYPES.FEATURE_VARIABLE, + userId: 'user1', + attributes: { test_attribute: 'test_value' }, + decisionInfo: { + featureKey: 'test_feature_for_experiment', + featureEnabled: false, + variableKey: 'button_txt', + variableValue: 'Buy me Later', + variableType: FEATURE_VARIABLE_TYPES.STRING, + source: DECISION_SOURCES.EXPERIMENT, + sourceExperimentKey: 'testing_my_feature', + sourceVariationKey: 'variation2' + } + }); + }); + }); + }); + + describe('bucketed into variation of a rollout with variable values', function() { + describe('when the variation is toggled ON', function() { + beforeEach(function() { + var experiment = projectConfig.getExperimentFromKey(optlyInstance.configObj, '594031'); + var variation = experiment.variations[0]; + sandbox.stub(optlyInstance.decisionService, 'getVariationForFeature').returns({ + experiment: experiment, + variation: variation, + decisionSource: DECISION_SOURCES.ROLLOUT, + }); + }); + + it('should return the right value from getFeatureVariableBoolean and send notification with featureEnabled true', function() { + var result = optlyInstance.getFeatureVariableBoolean('test_feature', 'new_content', 'user1', { test_attribute: 'test_value' }); + assert.strictEqual(result, true); + sinon.assert.calledWith(decisionListener, { + type: DECISION_INFO_TYPES.FEATURE_VARIABLE, + userId: 'user1', + attributes: { test_attribute: 'test_value' }, + decisionInfo: { + featureKey: 'test_feature', + featureEnabled: true, + variableKey: 'new_content', + variableValue: true, + variableType: FEATURE_VARIABLE_TYPES.BOOLEAN, + source: DECISION_SOURCES.ROLLOUT, + sourceExperimentKey: null, + sourceVariationKey: null + } + }); + }); + + it('should return the right value from getFeatureVariableDouble and send notification with featureEnabled true', function() { + var result = optlyInstance.getFeatureVariableDouble('test_feature', 'price', 'user1', { test_attribute: 'test_value' }); + assert.strictEqual(result, 4.99); + sinon.assert.calledWith(decisionListener, { + type: DECISION_INFO_TYPES.FEATURE_VARIABLE, + userId: 'user1', + attributes: { test_attribute: 'test_value' }, + decisionInfo: { + featureKey: 'test_feature', + featureEnabled: true, + variableKey: 'price', + variableValue: 4.99, + variableType: FEATURE_VARIABLE_TYPES.DOUBLE, + source: DECISION_SOURCES.ROLLOUT, + sourceExperimentKey: null, + sourceVariationKey: null + } + }); + }); + + it('should return the right value from getFeatureVariableInteger and send notification with featureEnabled true', function() { + var result = optlyInstance.getFeatureVariableInteger('test_feature', 'lasers', 'user1', { test_attribute: 'test_value' }); + assert.strictEqual(result, 395); + sinon.assert.calledWith(decisionListener, { + type: DECISION_INFO_TYPES.FEATURE_VARIABLE, + userId: 'user1', + attributes: { test_attribute: 'test_value' }, + decisionInfo: { + featureKey: 'test_feature', + featureEnabled: true, + variableKey: 'lasers', + variableValue: 395, + variableType: FEATURE_VARIABLE_TYPES.INTEGER, + source: DECISION_SOURCES.ROLLOUT, + sourceExperimentKey: null, + sourceVariationKey: null + } + }); + }); + + it('should return the right value from getFeatureVariableString and send notification with featureEnabled true', function() { + var result = optlyInstance.getFeatureVariableString('test_feature', 'message', 'user1', { test_attribute: 'test_value' }); + assert.strictEqual(result, 'Hello audience'); + sinon.assert.calledWith(decisionListener, { + type: DECISION_INFO_TYPES.FEATURE_VARIABLE, + userId: 'user1', + attributes: { test_attribute: 'test_value' }, + decisionInfo: { + featureKey: 'test_feature', + featureEnabled: true, + variableKey: 'message', + variableValue: 'Hello audience', + variableType: FEATURE_VARIABLE_TYPES.STRING, + source: DECISION_SOURCES.ROLLOUT, + sourceExperimentKey: null, + sourceVariationKey: null + } + }); + }); + }); + + describe('when the variation is toggled OFF', function() { + beforeEach(function() { + var experiment = projectConfig.getExperimentFromKey(optlyInstance.configObj, '594037'); + var variation = experiment.variations[0]; + sandbox.stub(optlyInstance.decisionService, 'getVariationForFeature').returns({ + experiment: experiment, + variation: variation, + decisionSource: DECISION_SOURCES.ROLLOUT, + }); + }); + + it('should return the right value from getFeatureVariableBoolean and send notification with featureEnabled false', function() { + var result = optlyInstance.getFeatureVariableBoolean('test_feature', 'new_content', 'user1', { test_attribute: 'test_value' }); + assert.strictEqual(result, false); + sinon.assert.calledWith(decisionListener, { + type: DECISION_INFO_TYPES.FEATURE_VARIABLE, + userId: 'user1', + attributes: { test_attribute: 'test_value' }, + decisionInfo: { + featureKey: 'test_feature', + featureEnabled: false, + variableKey: 'new_content', + variableValue: false, + variableType: FEATURE_VARIABLE_TYPES.BOOLEAN, + source: DECISION_SOURCES.ROLLOUT, + sourceExperimentKey: null, + sourceVariationKey: null + } + }); + }); + + it('should return the right value from getFeatureVariableDouble and send notification with featureEnabled false', function() { + var result = optlyInstance.getFeatureVariableDouble('test_feature', 'price', 'user1', { test_attribute: 'test_value' }); + assert.strictEqual(result, 14.99); + sinon.assert.calledWith(decisionListener, { + type: DECISION_INFO_TYPES.FEATURE_VARIABLE, + userId: 'user1', + attributes: { test_attribute: 'test_value' }, + decisionInfo: { + featureKey: 'test_feature', + featureEnabled: false, + variableKey: 'price', + variableValue: 14.99, + variableType: FEATURE_VARIABLE_TYPES.DOUBLE, + source: DECISION_SOURCES.ROLLOUT, + sourceExperimentKey: null, + sourceVariationKey: null + } + }); + }); + + it('should return the default value from getFeatureVariableInteger and send notification with featureEnabled false', function() { + var result = optlyInstance.getFeatureVariableInteger('test_feature', 'lasers', 'user1', { test_attribute: 'test_value' }); + assert.strictEqual(result, 400); + sinon.assert.calledWith(decisionListener, { + type: DECISION_INFO_TYPES.FEATURE_VARIABLE, + userId: 'user1', + attributes: { test_attribute: 'test_value' }, + decisionInfo: { + featureKey: 'test_feature', + featureEnabled: false, + variableKey: 'lasers', + variableValue: 400, + variableType: FEATURE_VARIABLE_TYPES.INTEGER, + source: DECISION_SOURCES.ROLLOUT, + sourceExperimentKey: null, + sourceVariationKey: null + } + }); + }); + + it('should return the default value from getFeatureVariableString and send notification with featureEnabled false', function() { + var result = optlyInstance.getFeatureVariableString('test_feature', 'message', 'user1', { test_attribute: 'test_value' }); + assert.strictEqual(result, 'Hello'); + sinon.assert.calledWith(decisionListener, { + type: DECISION_INFO_TYPES.FEATURE_VARIABLE, + userId: 'user1', + attributes: { test_attribute: 'test_value' }, + decisionInfo: { + featureKey: 'test_feature', + featureEnabled: false, + variableKey: 'message', + variableValue: 'Hello', + variableType: FEATURE_VARIABLE_TYPES.STRING, + source: DECISION_SOURCES.ROLLOUT, + sourceExperimentKey: null, + sourceVariationKey: null + } + }); + }); + }); + }); + + describe('not bucketed into an experiment or a rollout', function() { + beforeEach(function() { + sandbox.stub(optlyInstance.decisionService, 'getVariationForFeature').returns({ + experiment: null, + variation: null, + decisionSource: DECISION_SOURCES.ROLLOUT, + }); + }); + + it('returns the variable default value from getFeatureVariableBoolean and send notification with featureEnabled false', function() { + var result = optlyInstance.getFeatureVariableBoolean('test_feature_for_experiment', 'is_button_animated', 'user1', { test_attribute: 'test_value' }); + assert.strictEqual(result, false); + sinon.assert.calledWith(decisionListener, { + type: DECISION_INFO_TYPES.FEATURE_VARIABLE, + userId: 'user1', + attributes: { test_attribute: 'test_value' }, + decisionInfo: { + featureKey: 'test_feature_for_experiment', + featureEnabled: false, + variableKey: 'is_button_animated', + variableValue: false, + variableType: FEATURE_VARIABLE_TYPES.BOOLEAN, + source: DECISION_SOURCES.ROLLOUT, + sourceExperimentKey: null, + sourceVariationKey: null + } + }); + }); + + it('returns the variable default value from getFeatureVariableDouble and send notification with featureEnabled false', function() { + var result = optlyInstance.getFeatureVariableDouble('test_feature_for_experiment', 'button_width', 'user1', { test_attribute: 'test_value' }); + assert.strictEqual(result, 50.55); + sinon.assert.calledWith(decisionListener, { + type: DECISION_INFO_TYPES.FEATURE_VARIABLE, + userId: 'user1', + attributes: { test_attribute: 'test_value' }, + decisionInfo: { + featureKey: 'test_feature_for_experiment', + featureEnabled: false, + variableKey: 'button_width', + variableValue: 50.55, + variableType: FEATURE_VARIABLE_TYPES.DOUBLE, + source: DECISION_SOURCES.ROLLOUT, + sourceExperimentKey: null, + sourceVariationKey: null + } + }); + }); + + it('returns the variable default value from getFeatureVariableInteger and send notification with featureEnabled false', function() { + var result = optlyInstance.getFeatureVariableInteger('test_feature_for_experiment', 'num_buttons', 'user1', { test_attribute: 'test_value' }); + assert.strictEqual(result, 10); + sinon.assert.calledWith(decisionListener, { + type: DECISION_INFO_TYPES.FEATURE_VARIABLE, + userId: 'user1', + attributes: { test_attribute: 'test_value' }, + decisionInfo: { + featureKey: 'test_feature_for_experiment', + featureEnabled: false, + variableKey: 'num_buttons', + variableValue: 10, + variableType: FEATURE_VARIABLE_TYPES.INTEGER, + source: DECISION_SOURCES.ROLLOUT, + sourceExperimentKey: null, + sourceVariationKey: null + } + }); + }); + + it('returns the variable default value from getFeatureVariableString and send notification with featureEnabled false', function() { + var result = optlyInstance.getFeatureVariableString('test_feature_for_experiment', 'button_txt', 'user1', { test_attribute: 'test_value' }); + assert.strictEqual(result, 'Buy me'); + sinon.assert.calledWith(decisionListener, { + type: DECISION_INFO_TYPES.FEATURE_VARIABLE, + userId: 'user1', + attributes: { test_attribute: 'test_value' }, + decisionInfo: { + featureKey: 'test_feature_for_experiment', + featureEnabled: false, + variableKey: 'button_txt', + variableValue: 'Buy me', + variableType: FEATURE_VARIABLE_TYPES.STRING, + source: DECISION_SOURCES.ROLLOUT, + sourceExperimentKey: null, + sourceVariationKey: null + } + }); + }); + }); + }); }); }); }); diff --git a/packages/optimizely-sdk/lib/tests/test_data.js b/packages/optimizely-sdk/lib/tests/test_data.js index a9a8eae92..19841d048 100644 --- a/packages/optimizely-sdk/lib/tests/test_data.js +++ b/packages/optimizely-sdk/lib/tests/test_data.js @@ -557,6 +557,29 @@ var configWithFeatures = { }, ], }, + { + key: 'variation2', + id: '594099', + featureEnabled: false, + variables: [ + { + id: '4792309476491264', + value: '40', + }, + { + id: '5073784453201920', + value: 'true', + }, + { + id: '5636734406623232', + value: 'Buy me Later', + }, + { + id: '6199684360044544', + value: '99.99', + }, + ], + }, ], status: 'Running', key: 'testing_my_feature', @@ -1422,6 +1445,24 @@ var datafileWithFeaturesExpectedData = { id: '6199684360044544', }, }, + 594099: { + 4792309476491264: { + value: '40', + id: '4792309476491264' + }, + 5073784453201920: { + value: 'true', + id: '5073784453201920' + }, + 5636734406623232: { + value: 'Buy me Later', + id: '5636734406623232' + }, + 6199684360044544: { + value: '99.99', + id: '6199684360044544' + }, + }, 595008: {}, 595009: {}, 599026: { diff --git a/packages/optimizely-sdk/lib/utils/enums/index.js b/packages/optimizely-sdk/lib/utils/enums/index.js index 726df335a..9e6395332 100644 --- a/packages/optimizely-sdk/lib/utils/enums/index.js +++ b/packages/optimizely-sdk/lib/utils/enums/index.js @@ -173,7 +173,6 @@ exports.NODE_CLIENT_VERSION = '3.1.0-beta1'; * - attributes {Object|undefined} * - eventTags {Object|undefined} * - logEvent {Object} - * * DECISION: A decision is made in the system. i.e. user activation, * feature access or feature-variable value retrieval * Callbacks will receive an object argument with the following properties: @@ -191,6 +190,7 @@ exports.NOTIFICATION_TYPES = { exports.DECISION_INFO_TYPES = { EXPERIMENT: 'experiment', FEATURE: 'feature', + FEATURE_VARIABLE: 'feature_variable', }; /*