diff --git a/packages/optimizely-sdk/lib/core/decision_service/index.js b/packages/optimizely-sdk/lib/core/decision_service/index.js index 8736c952f..7864d6abc 100644 --- a/packages/optimizely-sdk/lib/core/decision_service/index.js +++ b/packages/optimizely-sdk/lib/core/decision_service/index.js @@ -340,7 +340,7 @@ DecisionService.prototype._getVariationForFeatureExperiment = function(configObj return { experiment: experiment, variation: variation, - decisionSource: DECISION_SOURCES.EXPERIMENT, + decisionSource: DECISION_SOURCES.FEATURE_TEST, }; }; 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 73d6efb8a..ae4b78e70 100644 --- a/packages/optimizely-sdk/lib/core/decision_service/index.tests.js +++ b/packages/optimizely-sdk/lib/core/decision_service/index.tests.js @@ -869,7 +869,7 @@ describe('lib/core/decision_service', function() { 'featureEnabled': true, 'key': 'variation' }, - decisionSource: DECISION_SOURCES.EXPERIMENT, + decisionSource: DECISION_SOURCES.FEATURE_TEST, }; assert.deepEqual(decision, expectedDecision); sinon.assert.calledWithExactly(mockLogger.log, LOG_LEVEL.DEBUG, 'DECISION_SERVICE: User user1 is in variation variation of experiment testing_my_feature on the feature test_feature_for_experiment.'); @@ -944,7 +944,7 @@ describe('lib/core/decision_service', function() { 'variables': [], 'key': 'var', }, - decisionSource: DECISION_SOURCES.EXPERIMENT, + decisionSource: DECISION_SOURCES.FEATURE_TEST, }; assert.deepEqual(decision, expectedDecision); sinon.assert.calledWithExactly(mockLogger.log, LOG_LEVEL.DEBUG, 'DECISION_SERVICE: User user1 is in variation var of experiment exp_with_group on the feature feature_with_group.'); diff --git a/packages/optimizely-sdk/lib/core/project_config/index.js b/packages/optimizely-sdk/lib/core/project_config/index.js index d0cb86ed9..2b7135001 100644 --- a/packages/optimizely-sdk/lib/core/project_config/index.js +++ b/packages/optimizely-sdk/lib/core/project_config/index.js @@ -89,10 +89,21 @@ module.exports = { projectConfig.forcedVariationMap = {}; + // Object containing experiment Ids that exist in any feature + // for checking that experiment is a feature experiment or not. + projectConfig.experimentFeatureMap = {}; + projectConfig.featureKeyMap = fns.keyBy(projectConfig.featureFlags || [], 'key'); fns.forOwn(projectConfig.featureKeyMap, function(feature) { feature.variableKeyMap = fns.keyBy(feature.variables, 'key'); fns.forEach(feature.experimentIds || [], function(experimentId) { + // Add this experiment in experiment-feature map. + if (projectConfig.experimentFeatureMap[experimentId]) { + projectConfig.experimentFeatureMap[experimentId].push(feature.id); + } else { + projectConfig.experimentFeatureMap[experimentId] = [feature.id]; + } + var experimentInFeature = projectConfig.experimentIdMap[experimentId]; if (experimentInFeature.groupId) { feature.groupId = experimentInFeature.groupId; @@ -594,4 +605,15 @@ module.exports = { eventWithKeyExists: function(projectConfig, eventKey) { return projectConfig.eventKeyMap.hasOwnProperty(eventKey); }, + + /** + * + * @param {Object} projectConfig + * @param {string} experimentId + * @returns {boolean} Returns true if experiment belongs to + * any feature, false otherwise. + */ + isFeatureExperiment: function(projectConfig, experimentId) { + return projectConfig.experimentFeatureMap.hasOwnProperty(experimentId); + } }; diff --git a/packages/optimizely-sdk/lib/optimizely/index.js b/packages/optimizely-sdk/lib/optimizely/index.js index a852a4528..48b468247 100644 --- a/packages/optimizely-sdk/lib/optimizely/index.js +++ b/packages/optimizely-sdk/lib/optimizely/index.js @@ -36,7 +36,7 @@ var LOG_MESSAGES = enums.LOG_MESSAGES; var MODULE_NAME = 'OPTIMIZELY'; var DECISION_SOURCES = enums.DECISION_SOURCES; var FEATURE_VARIABLE_TYPES = enums.FEATURE_VARIABLE_TYPES; -var DECISION_INFO_TYPES = enums.DECISION_INFO_TYPES; +var DECISION_NOTIFICATION_TYPES = enums.DECISION_NOTIFICATION_TYPES; var NOTIFICATION_TYPES = enums.NOTIFICATION_TYPES; var DEFAULT_EVENT_MAX_QUEUE_SIZE = 1; @@ -343,10 +343,13 @@ Optimizely.prototype.getVariation = function(experimentKey, userId, attributes) } var variationKey = this.decisionService.getVariation(this.configObj, experimentKey, userId, attributes); + var decisionNotificationType = projectConfig.isFeatureExperiment(this.configObj, experiment.id) ? DECISION_NOTIFICATION_TYPES.FEATURE_TEST : + DECISION_NOTIFICATION_TYPES.AB_TEST; + this.notificationCenter.sendNotifications( NOTIFICATION_TYPES.DECISION, { - type: DECISION_INFO_TYPES.EXPERIMENT, + type: decisionNotificationType, userId: userId, attributes: attributes || {}, decisionInfo: { @@ -501,16 +504,17 @@ Optimizely.prototype.isFeatureEnabled = function(featureKey, userId, attributes) } var featureEnabled = false; - var experimentKey = null; - var variationKey = null; var decision = this.decisionService.getVariationForFeature(this.configObj, feature, userId, attributes); var variation = decision.variation; - + var sourceInfo = {}; + if (!!variation) { featureEnabled = variation.featureEnabled; - if (decision.decisionSource === DECISION_SOURCES.EXPERIMENT) { - experimentKey = decision.experiment.key; - variationKey = decision.variation.key; + if (decision.decisionSource === DECISION_SOURCES.FEATURE_TEST) { + sourceInfo = { + experimentKey: decision.experiment.key, + variationKey: decision.variation.key, + } // got a variation from the exp, so we track the impression this._sendImpressionEvent(decision.experiment.key, decision.variation.key, userId, attributes); } @@ -523,19 +527,20 @@ Optimizely.prototype.isFeatureEnabled = function(featureKey, userId, attributes) featureEnabled = false; } + var featureInfo = { + featureKey: featureKey, + featureEnabled: featureEnabled, + source: decision.decisionSource, + sourceInfo: sourceInfo + }; + this.notificationCenter.sendNotifications( - enums.NOTIFICATION_TYPES.DECISION, + NOTIFICATION_TYPES.DECISION, { - type: DECISION_INFO_TYPES.FEATURE, + type: DECISION_NOTIFICATION_TYPES.FEATURE, userId: userId, attributes: attributes || {}, - decisionInfo: { - featureKey: featureKey, - featureEnabled: featureEnabled, - source: decision.decisionSource, - sourceExperimentKey: experimentKey, - sourceVariationKey: variationKey, - } + decisionInfo: featureInfo, } ); @@ -655,29 +660,29 @@ Optimizely.prototype._getFeatureVariableForType = function(featureKey, variableK variableKey, featureFlag.key)); } - var experimentKey = null; - var variationKey = null; - if (decision.decisionSource === DECISION_SOURCES.EXPERIMENT) { - experimentKey = decision.experiment.key; - variationKey = decision.variation.key; + var sourceInfo = {}; + if (decision.decisionSource === DECISION_SOURCES.FEATURE_TEST) { + sourceInfo = { + experimentKey: decision.experiment.key, + variationKey: decision.variation.key, + } } var typeCastedValue = projectConfig.getTypeCastValue(variableValue, variableType, this.logger); this.notificationCenter.sendNotifications( - enums.NOTIFICATION_TYPES.DECISION, + NOTIFICATION_TYPES.DECISION, { - type: DECISION_INFO_TYPES.FEATURE_VARIABLE, + type: DECISION_NOTIFICATION_TYPES.FEATURE_VARIABLE, userId: userId, attributes: attributes || {}, decisionInfo: { featureKey: featureKey, featureEnabled: featureEnabled, + source: decision.decisionSource, variableKey: variableKey, variableValue: typeCastedValue, variableType: variableType, - source: decision.decisionSource, - sourceExperimentKey: experimentKey, - sourceVariationKey: variationKey + sourceInfo: sourceInfo, } } ); diff --git a/packages/optimizely-sdk/lib/optimizely/index.tests.js b/packages/optimizely-sdk/lib/optimizely/index.tests.js index 07950b11f..1bb59797b 100644 --- a/packages/optimizely-sdk/lib/optimizely/index.tests.js +++ b/packages/optimizely-sdk/lib/optimizely/index.tests.js @@ -40,7 +40,7 @@ var ERROR_MESSAGES = enums.ERROR_MESSAGES; 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 DECISION_NOTIFICATION_TYPES = enums.DECISION_NOTIFICATION_TYPES; var FEATURE_VARIABLE_TYPES = enums.FEATURE_VARIABLE_TYPES; describe('lib/optimizely', function() { @@ -2365,7 +2365,7 @@ describe('lib/optimizely', function() { var variation = optlyInstance.activate('testExperiment', 'testUser'); assert.strictEqual(variation, 'variation'); sinon.assert.calledWith(decisionListener, { - type: DECISION_INFO_TYPES.EXPERIMENT, + type: DECISION_NOTIFICATION_TYPES.AB_TEST, userId: 'testUser', attributes: {}, decisionInfo: { @@ -2380,7 +2380,7 @@ describe('lib/optimizely', function() { var variation = optlyInstance.activate('testExperiment', 'testUser'); assert.isNull(variation); sinon.assert.calledWith(decisionListener, { - type: DECISION_INFO_TYPES.EXPERIMENT, + type: DECISION_NOTIFICATION_TYPES.AB_TEST, userId: 'testUser', attributes: {}, decisionInfo: { @@ -2415,7 +2415,7 @@ describe('lib/optimizely', function() { var variation = optlyInstance.getVariation('testExperiment', 'testUser'); assert.strictEqual(variation, 'variation'); sinon.assert.calledWith(decisionListener, { - type: DECISION_INFO_TYPES.EXPERIMENT, + type: DECISION_NOTIFICATION_TYPES.AB_TEST, userId: 'testUser', attributes: {}, decisionInfo: { @@ -2429,7 +2429,7 @@ describe('lib/optimizely', function() { var variation = optlyInstance.getVariation('testExperimentWithAudiences', 'testUser', {}); assert.isNull(variation); sinon.assert.calledWith(decisionListener, { - type: DECISION_INFO_TYPES.EXPERIMENT, + type: DECISION_NOTIFICATION_TYPES.AB_TEST, userId: 'testUser', attributes: {}, decisionInfo: { @@ -2438,6 +2438,37 @@ describe('lib/optimizely', function() { } }); }); + + it('should send notification with variation key and type feature-test when getVariation returns feature experiment variation', function() { + var optly = new Optimizely({ + clientEngine: 'node-sdk', + datafile: testData.getTestProjectConfigWithFeatures(), + eventBuilder: eventBuilder, + errorHandler: errorHandler, + eventDispatcher: eventDispatcher, + jsonSchemaValidator: jsonSchemaValidator, + logger: createdLogger, + isValidInstance: true, + }); + + optly.notificationCenter.addNotificationListener( + enums.NOTIFICATION_TYPES.DECISION, + decisionListener + ); + + bucketStub.returns('594099'); + var variation = optly.getVariation('testing_my_feature', 'testUser'); + assert.strictEqual(variation, 'variation2'); + sinon.assert.calledWith(decisionListener, { + type: DECISION_NOTIFICATION_TYPES.FEATURE_TEST, + userId: 'testUser', + attributes: {}, + decisionInfo: { + experimentKey: 'testing_my_feature', + variationKey: variation + } + }); + }); }); describe('feature management', function() { @@ -2475,7 +2506,7 @@ describe('lib/optimizely', function() { sandbox.stub(optlyInstance.decisionService, 'getVariationForFeature').returns({ experiment: experiment, variation: variation, - decisionSource: DECISION_SOURCES.EXPERIMENT, + decisionSource: DECISION_SOURCES.FEATURE_TEST, }); }); @@ -2483,15 +2514,17 @@ describe('lib/optimizely', function() { var result = optlyInstance.isFeatureEnabled('test_feature_for_experiment', 'user1', attributes); assert.strictEqual(result, true); sinon.assert.calledWith(decisionListener, { - type: DECISION_INFO_TYPES.FEATURE, + type: DECISION_NOTIFICATION_TYPES.FEATURE, userId: 'user1', attributes: attributes, decisionInfo: { featureKey: 'test_feature_for_experiment', featureEnabled: true, - source: DECISION_SOURCES.EXPERIMENT, - sourceExperimentKey: 'testing_my_feature', - sourceVariationKey: 'variation' + source: DECISION_SOURCES.FEATURE_TEST, + sourceInfo: { + experimentKey: 'testing_my_feature', + variationKey: 'variation' + } } }); }); @@ -2504,7 +2537,7 @@ describe('lib/optimizely', function() { sandbox.stub(optlyInstance.decisionService, 'getVariationForFeature').returns({ experiment: experiment, variation: variation, - decisionSource: DECISION_SOURCES.EXPERIMENT, + decisionSource: DECISION_SOURCES.FEATURE_TEST, }); }); @@ -2512,15 +2545,17 @@ describe('lib/optimizely', function() { var result = optlyInstance.isFeatureEnabled('shared_feature', 'user1', attributes); assert.strictEqual(result, false); sinon.assert.calledWith(decisionListener, { - type: DECISION_INFO_TYPES.FEATURE, + type: DECISION_NOTIFICATION_TYPES.FEATURE, userId: 'user1', attributes: attributes, decisionInfo: { featureKey: 'shared_feature', featureEnabled: false, - source: DECISION_SOURCES.EXPERIMENT, - sourceExperimentKey: 'test_shared_feature', - sourceVariationKey: 'control' + source: DECISION_SOURCES.FEATURE_TEST, + sourceInfo: { + experimentKey: 'test_shared_feature', + variationKey: 'control' + } } }); }); @@ -2546,15 +2581,14 @@ describe('lib/optimizely', function() { }); assert.strictEqual(result, true); sinon.assert.calledWith(decisionListener, { - type: DECISION_INFO_TYPES.FEATURE, + type: DECISION_NOTIFICATION_TYPES.FEATURE, userId: 'user1', attributes: { test_attribute: 'test_value' }, decisionInfo: { featureKey: 'test_feature', featureEnabled: true, source: DECISION_SOURCES.ROLLOUT, - sourceExperimentKey: null, - sourceVariationKey: null + sourceInfo: {} } }); }); @@ -2580,15 +2614,15 @@ describe('lib/optimizely', function() { sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.INFO, 'OPTIMIZELY: Feature test_feature is not enabled for user user1.'); var expectedArguments = { - type: DECISION_INFO_TYPES.FEATURE, + type: DECISION_NOTIFICATION_TYPES.FEATURE, userId: 'user1', attributes: { test_attribute: 'test_value' }, decisionInfo: { featureKey: 'test_feature', featureEnabled: false, source: DECISION_SOURCES.ROLLOUT, - sourceExperimentKey: null, - sourceVariationKey: null + sourceInfo: { + } } }; sinon.assert.calledWith(decisionListener, expectedArguments); @@ -2609,15 +2643,14 @@ describe('lib/optimizely', function() { var result = optlyInstance.isFeatureEnabled('test_feature', 'user1'); assert.strictEqual(result, false); sinon.assert.calledWith(decisionListener, { - type: DECISION_INFO_TYPES.FEATURE, + type: DECISION_NOTIFICATION_TYPES.FEATURE, userId: 'user1', attributes: {}, decisionInfo: { featureKey: 'test_feature', featureEnabled: false, source: DECISION_SOURCES.ROLLOUT, - sourceExperimentKey: null, - sourceVariationKey: null + sourceInfo: {} } }); }); @@ -2633,7 +2666,7 @@ describe('lib/optimizely', function() { sandbox.stub(optlyInstance.decisionService, 'getVariationForFeature').returns({ experiment: experiment, variation: variation, - decisionSource: DECISION_SOURCES.EXPERIMENT, + decisionSource: DECISION_SOURCES.FEATURE_TEST, }); }); @@ -2641,7 +2674,7 @@ describe('lib/optimizely', 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, + type: DECISION_NOTIFICATION_TYPES.FEATURE_VARIABLE, userId: 'user1', attributes: { test_attribute: 'test_value' }, decisionInfo: { @@ -2650,9 +2683,11 @@ describe('lib/optimizely', function() { variableKey: 'is_button_animated', variableValue: true, variableType: FEATURE_VARIABLE_TYPES.BOOLEAN, - source: DECISION_SOURCES.EXPERIMENT, - sourceExperimentKey: 'testing_my_feature', - sourceVariationKey: 'variation' + source: DECISION_SOURCES.FEATURE_TEST, + sourceInfo: { + experimentKey: 'testing_my_feature', + variationKey: 'variation' + } } }); }); @@ -2661,7 +2696,7 @@ describe('lib/optimizely', 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, + type: DECISION_NOTIFICATION_TYPES.FEATURE_VARIABLE, userId: 'user1', attributes: { test_attribute: 'test_value' }, decisionInfo: { @@ -2670,9 +2705,11 @@ describe('lib/optimizely', function() { variableKey: 'button_width', variableValue: 20.25, variableType: FEATURE_VARIABLE_TYPES.DOUBLE, - source: DECISION_SOURCES.EXPERIMENT, - sourceExperimentKey: 'testing_my_feature', - sourceVariationKey: 'variation' + source: DECISION_SOURCES.FEATURE_TEST, + sourceInfo: { + experimentKey: 'testing_my_feature', + variationKey: 'variation' + } } }); }); @@ -2681,7 +2718,7 @@ describe('lib/optimizely', 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, + type: DECISION_NOTIFICATION_TYPES.FEATURE_VARIABLE, userId: 'user1', attributes: { test_attribute: 'test_value' }, decisionInfo: { @@ -2690,9 +2727,11 @@ describe('lib/optimizely', function() { variableKey: 'num_buttons', variableValue: 2, variableType: FEATURE_VARIABLE_TYPES.INTEGER, - source: DECISION_SOURCES.EXPERIMENT, - sourceExperimentKey: 'testing_my_feature', - sourceVariationKey: 'variation' + source: DECISION_SOURCES.FEATURE_TEST, + sourceInfo: { + experimentKey: 'testing_my_feature', + variationKey: 'variation' + } } }); }); @@ -2701,7 +2740,7 @@ describe('lib/optimizely', 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, + type: DECISION_NOTIFICATION_TYPES.FEATURE_VARIABLE, userId: 'user1', attributes: { test_attribute: 'test_value' }, decisionInfo: { @@ -2710,9 +2749,11 @@ describe('lib/optimizely', function() { variableKey: 'button_txt', variableValue: 'Buy me NOW', variableType: FEATURE_VARIABLE_TYPES.STRING, - source: DECISION_SOURCES.EXPERIMENT, - sourceExperimentKey: 'testing_my_feature', - sourceVariationKey: 'variation' + source: DECISION_SOURCES.FEATURE_TEST, + sourceInfo: { + experimentKey: 'testing_my_feature', + variationKey: 'variation' + } } }); }); @@ -2725,7 +2766,7 @@ describe('lib/optimizely', function() { sandbox.stub(optlyInstance.decisionService, 'getVariationForFeature').returns({ experiment: experiment, variation: variation, - decisionSource: DECISION_SOURCES.EXPERIMENT, + decisionSource: DECISION_SOURCES.FEATURE_TEST, }); }); @@ -2733,7 +2774,7 @@ describe('lib/optimizely', 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, + type: DECISION_NOTIFICATION_TYPES.FEATURE_VARIABLE, userId: 'user1', attributes: { test_attribute: 'test_value' }, decisionInfo: { @@ -2742,9 +2783,11 @@ describe('lib/optimizely', function() { variableKey: 'is_button_animated', variableValue: false, variableType: FEATURE_VARIABLE_TYPES.BOOLEAN, - source: DECISION_SOURCES.EXPERIMENT, - sourceExperimentKey: 'testing_my_feature', - sourceVariationKey: 'variation2' + source: DECISION_SOURCES.FEATURE_TEST, + sourceInfo: { + experimentKey: 'testing_my_feature', + variationKey: 'variation2' + } } }); }); @@ -2753,7 +2796,7 @@ describe('lib/optimizely', 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, + type: DECISION_NOTIFICATION_TYPES.FEATURE_VARIABLE, userId: 'user1', attributes: { test_attribute: 'test_value' }, decisionInfo: { @@ -2762,9 +2805,11 @@ describe('lib/optimizely', function() { variableKey: 'button_width', variableValue: 50.55, variableType: FEATURE_VARIABLE_TYPES.DOUBLE, - source: DECISION_SOURCES.EXPERIMENT, - sourceExperimentKey: 'testing_my_feature', - sourceVariationKey: 'variation2' + source: DECISION_SOURCES.FEATURE_TEST, + sourceInfo: { + experimentKey: 'testing_my_feature', + variationKey: 'variation2' + } } }); }); @@ -2773,7 +2818,7 @@ describe('lib/optimizely', 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, + type: DECISION_NOTIFICATION_TYPES.FEATURE_VARIABLE, userId: 'user1', attributes: { test_attribute: 'test_value' }, decisionInfo: { @@ -2782,9 +2827,11 @@ describe('lib/optimizely', function() { variableKey: 'num_buttons', variableValue: 10, variableType: FEATURE_VARIABLE_TYPES.INTEGER, - source: DECISION_SOURCES.EXPERIMENT, - sourceExperimentKey: 'testing_my_feature', - sourceVariationKey: 'variation2' + source: DECISION_SOURCES.FEATURE_TEST, + sourceInfo: { + experimentKey: 'testing_my_feature', + variationKey: 'variation2' + } } }); }); @@ -2793,7 +2840,7 @@ describe('lib/optimizely', 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, + type: DECISION_NOTIFICATION_TYPES.FEATURE_VARIABLE, userId: 'user1', attributes: { test_attribute: 'test_value' }, decisionInfo: { @@ -2802,9 +2849,11 @@ describe('lib/optimizely', function() { variableKey: 'button_txt', variableValue: 'Buy me', variableType: FEATURE_VARIABLE_TYPES.STRING, - source: DECISION_SOURCES.EXPERIMENT, - sourceExperimentKey: 'testing_my_feature', - sourceVariationKey: 'variation2' + source: DECISION_SOURCES.FEATURE_TEST, + sourceInfo: { + experimentKey: 'testing_my_feature', + variationKey: 'variation2' + } } }); }); @@ -2827,7 +2876,7 @@ describe('lib/optimizely', 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, + type: DECISION_NOTIFICATION_TYPES.FEATURE_VARIABLE, userId: 'user1', attributes: { test_attribute: 'test_value' }, decisionInfo: { @@ -2837,8 +2886,7 @@ describe('lib/optimizely', function() { variableValue: true, variableType: FEATURE_VARIABLE_TYPES.BOOLEAN, source: DECISION_SOURCES.ROLLOUT, - sourceExperimentKey: null, - sourceVariationKey: null + sourceInfo: {} } }); }); @@ -2847,7 +2895,7 @@ describe('lib/optimizely', 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, + type: DECISION_NOTIFICATION_TYPES.FEATURE_VARIABLE, userId: 'user1', attributes: { test_attribute: 'test_value' }, decisionInfo: { @@ -2857,8 +2905,7 @@ describe('lib/optimizely', function() { variableValue: 4.99, variableType: FEATURE_VARIABLE_TYPES.DOUBLE, source: DECISION_SOURCES.ROLLOUT, - sourceExperimentKey: null, - sourceVariationKey: null + sourceInfo: {} } }); }); @@ -2867,7 +2914,7 @@ describe('lib/optimizely', 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, + type: DECISION_NOTIFICATION_TYPES.FEATURE_VARIABLE, userId: 'user1', attributes: { test_attribute: 'test_value' }, decisionInfo: { @@ -2877,8 +2924,7 @@ describe('lib/optimizely', function() { variableValue: 395, variableType: FEATURE_VARIABLE_TYPES.INTEGER, source: DECISION_SOURCES.ROLLOUT, - sourceExperimentKey: null, - sourceVariationKey: null + sourceInfo: {} } }); }); @@ -2887,7 +2933,7 @@ describe('lib/optimizely', 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, + type: DECISION_NOTIFICATION_TYPES.FEATURE_VARIABLE, userId: 'user1', attributes: { test_attribute: 'test_value' }, decisionInfo: { @@ -2897,8 +2943,7 @@ describe('lib/optimizely', function() { variableValue: 'Hello audience', variableType: FEATURE_VARIABLE_TYPES.STRING, source: DECISION_SOURCES.ROLLOUT, - sourceExperimentKey: null, - sourceVariationKey: null + sourceInfo: {} } }); }); @@ -2919,7 +2964,7 @@ describe('lib/optimizely', 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, + type: DECISION_NOTIFICATION_TYPES.FEATURE_VARIABLE, userId: 'user1', attributes: { test_attribute: 'test_value' }, decisionInfo: { @@ -2929,8 +2974,7 @@ describe('lib/optimizely', function() { variableValue: false, variableType: FEATURE_VARIABLE_TYPES.BOOLEAN, source: DECISION_SOURCES.ROLLOUT, - sourceExperimentKey: null, - sourceVariationKey: null + sourceInfo: {} } }); }); @@ -2939,7 +2983,7 @@ describe('lib/optimizely', 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, + type: DECISION_NOTIFICATION_TYPES.FEATURE_VARIABLE, userId: 'user1', attributes: { test_attribute: 'test_value' }, decisionInfo: { @@ -2949,8 +2993,7 @@ describe('lib/optimizely', function() { variableValue: 14.99, variableType: FEATURE_VARIABLE_TYPES.DOUBLE, source: DECISION_SOURCES.ROLLOUT, - sourceExperimentKey: null, - sourceVariationKey: null + sourceInfo: {} } }); }); @@ -2959,7 +3002,7 @@ describe('lib/optimizely', 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, + type: DECISION_NOTIFICATION_TYPES.FEATURE_VARIABLE, userId: 'user1', attributes: { test_attribute: 'test_value' }, decisionInfo: { @@ -2969,8 +3012,7 @@ describe('lib/optimizely', function() { variableValue: 400, variableType: FEATURE_VARIABLE_TYPES.INTEGER, source: DECISION_SOURCES.ROLLOUT, - sourceExperimentKey: null, - sourceVariationKey: null + sourceInfo: {} } }); }); @@ -2979,7 +3021,7 @@ describe('lib/optimizely', 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, + type: DECISION_NOTIFICATION_TYPES.FEATURE_VARIABLE, userId: 'user1', attributes: { test_attribute: 'test_value' }, decisionInfo: { @@ -2989,8 +3031,7 @@ describe('lib/optimizely', function() { variableValue: 'Hello', variableType: FEATURE_VARIABLE_TYPES.STRING, source: DECISION_SOURCES.ROLLOUT, - sourceExperimentKey: null, - sourceVariationKey: null + sourceInfo: {} } }); }); @@ -3010,7 +3051,7 @@ describe('lib/optimizely', 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, + type: DECISION_NOTIFICATION_TYPES.FEATURE_VARIABLE, userId: 'user1', attributes: { test_attribute: 'test_value' }, decisionInfo: { @@ -3020,8 +3061,7 @@ describe('lib/optimizely', function() { variableValue: false, variableType: FEATURE_VARIABLE_TYPES.BOOLEAN, source: DECISION_SOURCES.ROLLOUT, - sourceExperimentKey: null, - sourceVariationKey: null + sourceInfo: {} } }); }); @@ -3030,7 +3070,7 @@ describe('lib/optimizely', 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, + type: DECISION_NOTIFICATION_TYPES.FEATURE_VARIABLE, userId: 'user1', attributes: { test_attribute: 'test_value' }, decisionInfo: { @@ -3040,8 +3080,7 @@ describe('lib/optimizely', function() { variableValue: 50.55, variableType: FEATURE_VARIABLE_TYPES.DOUBLE, source: DECISION_SOURCES.ROLLOUT, - sourceExperimentKey: null, - sourceVariationKey: null + sourceInfo: {} } }); }); @@ -3050,7 +3089,7 @@ describe('lib/optimizely', 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, + type: DECISION_NOTIFICATION_TYPES.FEATURE_VARIABLE, userId: 'user1', attributes: { test_attribute: 'test_value' }, decisionInfo: { @@ -3060,8 +3099,7 @@ describe('lib/optimizely', function() { variableValue: 10, variableType: FEATURE_VARIABLE_TYPES.INTEGER, source: DECISION_SOURCES.ROLLOUT, - sourceExperimentKey: null, - sourceVariationKey: null + sourceInfo: {} } }); }); @@ -3070,7 +3108,7 @@ describe('lib/optimizely', 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, + type: DECISION_NOTIFICATION_TYPES.FEATURE_VARIABLE, userId: 'user1', attributes: { test_attribute: 'test_value' }, decisionInfo: { @@ -3080,8 +3118,7 @@ describe('lib/optimizely', function() { variableValue: 'Buy me', variableType: FEATURE_VARIABLE_TYPES.STRING, source: DECISION_SOURCES.ROLLOUT, - sourceExperimentKey: null, - sourceVariationKey: null + sourceInfo: {} } }); }); @@ -3221,7 +3258,7 @@ describe('lib/optimizely', function() { sandbox.stub(optlyInstance.decisionService, 'getVariationForFeature').returns({ experiment: experiment, variation: variation, - decisionSource: DECISION_SOURCES.EXPERIMENT, + decisionSource: DECISION_SOURCES.FEATURE_TEST, }); }); @@ -3391,7 +3428,7 @@ describe('lib/optimizely', function() { sandbox.stub(optlyInstance.decisionService, 'getVariationForFeature').returns({ experiment: experiment, variation: variation, - decisionSource: DECISION_SOURCES.EXPERIMENT, + decisionSource: DECISION_SOURCES.FEATURE_TEST, }); result = optlyInstance.isFeatureEnabled('shared_feature', 'user1', attributes); }); @@ -3475,7 +3512,7 @@ describe('lib/optimizely', function() { sandbox.stub(optlyInstance.decisionService, 'getVariationForFeature').returns({ experiment: experiment, variation: variation, - decisionSource: DECISION_SOURCES.EXPERIMENT, + decisionSource: DECISION_SOURCES.FEATURE_TEST, }); }); @@ -3654,87 +3691,86 @@ describe('lib/optimizely', function() { assert.deepEqual(result, ['test_feature_2', 'test_feature_for_experiment', 'shared_feature']); sinon.assert.calledWithExactly(decisionListener.getCall(0), { - type: DECISION_INFO_TYPES.FEATURE, + type: DECISION_NOTIFICATION_TYPES.FEATURE, userId: 'test_user', attributes: attributes, decisionInfo: { featureKey: 'test_feature', featureEnabled: false, source: DECISION_SOURCES.ROLLOUT, - sourceExperimentKey: null, - sourceVariationKey: null + sourceInfo: {} } }); sinon.assert.calledWithExactly(decisionListener.getCall(1), { - type: DECISION_INFO_TYPES.FEATURE, + type: DECISION_NOTIFICATION_TYPES.FEATURE, userId: 'test_user', attributes: attributes, decisionInfo: { featureKey: 'test_feature_2', featureEnabled: true, source: DECISION_SOURCES.ROLLOUT, - sourceExperimentKey: null, - sourceVariationKey: null + sourceInfo: {} } }); sinon.assert.calledWithExactly(decisionListener.getCall(2), { - type: DECISION_INFO_TYPES.FEATURE, + type: DECISION_NOTIFICATION_TYPES.FEATURE, userId: 'test_user', attributes: attributes, decisionInfo: { featureKey: 'test_feature_for_experiment', featureEnabled: true, - source: DECISION_SOURCES.EXPERIMENT, - sourceExperimentKey: 'testing_my_feature', - sourceVariationKey: 'variation' + source: DECISION_SOURCES.FEATURE_TEST, + sourceInfo: { + experimentKey: 'testing_my_feature', + variationKey: 'variation' + } } }); sinon.assert.calledWithExactly(decisionListener.getCall(3), { - type: DECISION_INFO_TYPES.FEATURE, + type: DECISION_NOTIFICATION_TYPES.FEATURE, userId: 'test_user', attributes: attributes, decisionInfo: { featureKey: 'feature_with_group', featureEnabled: false, source: DECISION_SOURCES.ROLLOUT, - sourceExperimentKey: null, - sourceVariationKey: null + sourceInfo: {} } }); sinon.assert.calledWithExactly(decisionListener.getCall(4), { - type: DECISION_INFO_TYPES.FEATURE, + type: DECISION_NOTIFICATION_TYPES.FEATURE, userId: 'test_user', attributes: attributes, decisionInfo: { featureKey: 'shared_feature', featureEnabled: true, - source: DECISION_SOURCES.EXPERIMENT, - sourceExperimentKey: 'test_shared_feature', - sourceVariationKey: 'treatment' + source: DECISION_SOURCES.FEATURE_TEST, + sourceInfo: { + experimentKey: 'test_shared_feature', + variationKey: 'treatment' + } } }); sinon.assert.calledWithExactly(decisionListener.getCall(5), { - type: DECISION_INFO_TYPES.FEATURE, + type: DECISION_NOTIFICATION_TYPES.FEATURE, userId: 'test_user', attributes: attributes, decisionInfo: { featureKey: 'unused_flag', featureEnabled: false, source: DECISION_SOURCES.ROLLOUT, - sourceExperimentKey: null, - sourceVariationKey: null + sourceInfo: {} } }); sinon.assert.calledWithExactly(decisionListener.getCall(6), { - type: DECISION_INFO_TYPES.FEATURE, + type: DECISION_NOTIFICATION_TYPES.FEATURE, userId: 'test_user', attributes: attributes, decisionInfo: { featureKey: 'feature_exp_no_traffic', featureEnabled: false, source: DECISION_SOURCES.ROLLOUT, - sourceExperimentKey: null, - sourceVariationKey: null + sourceInfo: {} } }); }); @@ -3749,7 +3785,7 @@ describe('lib/optimizely', function() { sandbox.stub(optlyInstance.decisionService, 'getVariationForFeature').returns({ experiment: experiment, variation: variation, - decisionSource: DECISION_SOURCES.EXPERIMENT, + decisionSource: DECISION_SOURCES.FEATURE_TEST, }); }); @@ -3815,7 +3851,7 @@ describe('lib/optimizely', function() { sandbox.stub(optlyInstance.decisionService, 'getVariationForFeature').returns({ experiment: experiment, variation: variation, - decisionSource: DECISION_SOURCES.EXPERIMENT, + decisionSource: DECISION_SOURCES.FEATURE_TEST, }); }); diff --git a/packages/optimizely-sdk/lib/utils/enums/index.js b/packages/optimizely-sdk/lib/utils/enums/index.js index 2f5e7a13d..4aae3c3c7 100644 --- a/packages/optimizely-sdk/lib/utils/enums/index.js +++ b/packages/optimizely-sdk/lib/utils/enums/index.js @@ -189,10 +189,11 @@ exports.NOTIFICATION_TYPES = { DECISION: 'DECISION:type, userId, attributes, decisionInfo', }; -exports.DECISION_INFO_TYPES = { - EXPERIMENT: 'experiment', +exports.DECISION_NOTIFICATION_TYPES = { + AB_TEST: 'ab-test', FEATURE: 'feature', - FEATURE_VARIABLE: 'feature_variable', + FEATURE_TEST: 'feature-test', + FEATURE_VARIABLE: 'feature-variable', }; /* @@ -202,8 +203,8 @@ exports.DECISION_INFO_TYPES = { * Optimizely. */ exports.DECISION_SOURCES = { - EXPERIMENT: 'EXPERIMENT', - ROLLOUT: 'ROLLOUT', + FEATURE_TEST: 'feature-test', + ROLLOUT: 'rollout', }; /*