From 7be77865d65aa17abaed9086fb21e0413b69e79b Mon Sep 17 00:00:00 2001 From: Derek Hammond Date: Tue, 3 Mar 2020 10:31:35 -0600 Subject: [PATCH 1/4] feat(core)[OASIS-6054]: Change Error to LOG_LEVEL.WARNING for unfound event In a similar vein as https://github.com/optimizely/java-sdk/pull/361, the JavaScript SDK would be less noisy when being used with integrations like Segment if we only logged a warning when an event key is not found in the datafile. This PR will make that change and unblock event tracking. --- packages/optimizely-sdk/lib/utils/enums/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/optimizely-sdk/lib/utils/enums/index.js b/packages/optimizely-sdk/lib/utils/enums/index.js index ea603019d..9d9b74152 100644 --- a/packages/optimizely-sdk/lib/utils/enums/index.js +++ b/packages/optimizely-sdk/lib/utils/enums/index.js @@ -40,7 +40,6 @@ exports.ERROR_MESSAGES = { INVALID_JSON: '%s: JSON object is not valid.', INVALID_ERROR_HANDLER: '%s: Provided "errorHandler" is in an invalid format.', INVALID_EVENT_DISPATCHER: '%s: Provided "eventDispatcher" is in an invalid format.', - INVALID_EVENT_KEY: '%s: Event key %s is not in datafile.', INVALID_EVENT_TAGS: '%s: Provided event tags are in an invalid format.', INVALID_EXPERIMENT_KEY: '%s: Experiment key %s is not in datafile. It is either invalid, paused, or archived.', INVALID_EXPERIMENT_ID: '%s: Experiment ID %s is not in datafile.', @@ -72,6 +71,7 @@ exports.LOG_MESSAGES = { DISPATCH_CONVERSION_EVENT: '%s: Dispatching conversion event to URL %s with params %s.', DISPATCH_IMPRESSION_EVENT: '%s: Dispatching impression event to URL %s with params %s.', DEPRECATED_EVENT_VALUE: '%s: Event value is deprecated in %s call.', + EVENT_KEY_NOT_FOUND: '%s: Event key %s is not in datafile.', EXPERIMENT_NOT_RUNNING: '%s: Experiment %s is not running.', FEATURE_ENABLED_FOR_USER: '%s: Feature %s is enabled for user %s.', FEATURE_NOT_ENABLED_FOR_USER: '%s: Feature %s is not enabled for user %s.', From 451ea67e8d8516d644c40dc60328da876d2bfbc0 Mon Sep 17 00:00:00 2001 From: Derek Hammond Date: Tue, 3 Mar 2020 11:13:37 -0600 Subject: [PATCH 2/4] somehow more prettier changes --- .../optimizely-sdk/lib/optimizely/index.js | 310 +- .../lib/optimizely/index.tests.js | 4598 ++++++++++------- 2 files changed, 3013 insertions(+), 1895 deletions(-) diff --git a/packages/optimizely-sdk/lib/optimizely/index.js b/packages/optimizely-sdk/lib/optimizely/index.js index 59300352c..0fd291933 100644 --- a/packages/optimizely-sdk/lib/optimizely/index.js +++ b/packages/optimizely-sdk/lib/optimizely/index.js @@ -57,7 +57,10 @@ var DEFAULT_ONREADY_TIMEOUT = 30000; function Optimizely(config) { var clientEngine = config.clientEngine; if (enums.VALID_CLIENT_ENGINES.indexOf(clientEngine) === -1) { - config.logger.log(LOG_LEVEL.INFO, jsSdkUtils.sprintf(LOG_MESSAGES.INVALID_CLIENT_ENGINE, MODULE_NAME, clientEngine)); + config.logger.log( + LOG_LEVEL.INFO, + jsSdkUtils.sprintf(LOG_MESSAGES.INVALID_CLIENT_ENGINE, MODULE_NAME, clientEngine) + ); clientEngine = enums.NODE_CLIENT_ENGINE; } @@ -76,10 +79,15 @@ function Optimizely(config) { skipJSONValidation: config.skipJSONValidation, }); - this.__disposeOnUpdate = this.projectConfigManager.onUpdate(function (configObj) { - this.logger.log(LOG_LEVEL.INFO, jsSdkUtils.sprintf(LOG_MESSAGES.UPDATED_OPTIMIZELY_CONFIG, MODULE_NAME, configObj.revision, configObj.projectId)); - this.notificationCenter.sendNotifications(NOTIFICATION_TYPES.OPTIMIZELY_CONFIG_UPDATE); - }.bind(this)); + this.__disposeOnUpdate = this.projectConfigManager.onUpdate( + function(configObj) { + this.logger.log( + LOG_LEVEL.INFO, + jsSdkUtils.sprintf(LOG_MESSAGES.UPDATED_OPTIMIZELY_CONFIG, MODULE_NAME, configObj.revision, configObj.projectId) + ); + this.notificationCenter.sendNotifications(NOTIFICATION_TYPES.OPTIMIZELY_CONFIG_UPDATE); + }.bind(this) + ); this.__readyPromise = this.projectConfigManager.onReady(); @@ -98,7 +106,7 @@ function Optimizely(config) { this.decisionService = decisionService.createDecisionService({ userProfileService: userProfileService, logger: this.logger, - UNSTABLE_conditionEvaluators: config.UNSTABLE_conditionEvaluators + UNSTABLE_conditionEvaluators: config.UNSTABLE_conditionEvaluators, }); this.notificationCenter = notificationCenter.createNotificationCenter({ @@ -124,7 +132,7 @@ function Optimizely(config) { * constructor was also valid. * @return {*} */ -Optimizely.prototype.__isValidInstance = function () { +Optimizely.prototype.__isValidInstance = function() { return this.__isOptimizelyConfigValid && this.projectConfigManager.getConfig(); }; @@ -135,7 +143,7 @@ Optimizely.prototype.__isValidInstance = function () { * @param {Object} attributes * @return {string|null} variation key */ -Optimizely.prototype.activate = function (experimentKey, userId, attributes) { +Optimizely.prototype.activate = function(experimentKey, userId, attributes) { try { if (!this.__isValidInstance()) { this.logger.log(LOG_LEVEL.ERROR, jsSdkUtils.sprintf(LOG_MESSAGES.INVALID_OBJECT, MODULE_NAME, 'activate')); @@ -173,7 +181,12 @@ Optimizely.prototype.activate = function (experimentKey, userId, attributes) { return variationKey; } catch (ex) { this.logger.log(LOG_LEVEL.ERROR, ex.message); - var failedActivationLogMessage = jsSdkUtils.sprintf(LOG_MESSAGES.NOT_ACTIVATING_USER, MODULE_NAME, userId, experimentKey); + var failedActivationLogMessage = jsSdkUtils.sprintf( + LOG_MESSAGES.NOT_ACTIVATING_USER, + MODULE_NAME, + userId, + experimentKey + ); this.logger.log(LOG_LEVEL.INFO, failedActivationLogMessage); this.errorHandler.handleError(ex); return null; @@ -194,7 +207,7 @@ Optimizely.prototype.activate = function (experimentKey, userId, attributes) { * @param {string} userId ID of user to whom the variation was shown * @param {Object} attributes Optional user attributes */ -Optimizely.prototype._sendImpressionEvent = function (experimentKey, variationKey, userId, attributes) { +Optimizely.prototype._sendImpressionEvent = function(experimentKey, variationKey, userId, attributes) { var configObj = this.projectConfigManager.getConfig(); if (!configObj) { return; @@ -221,17 +234,13 @@ Optimizely.prototype._sendImpressionEvent = function (experimentKey, variationKe * @param {string} userId ID of user to whom the variation was shown * @param {Object} attributes Optional user attributes */ -Optimizely.prototype.__emitNotificationCenterActivate = function (experimentKey, variationKey, userId, attributes) { +Optimizely.prototype.__emitNotificationCenterActivate = function(experimentKey, variationKey, userId, attributes) { var configObj = this.projectConfigManager.getConfig(); if (!configObj) { return; } - var variationId = projectConfig.getVariationIdFromExperimentAndVariationKey( - configObj, - experimentKey, - variationKey - ); + var variationId = projectConfig.getVariationIdFromExperimentAndVariationKey(configObj, experimentKey, variationKey); var experimentId = projectConfig.getExperimentId(configObj, experimentKey); var impressionEventOptions = { attributes: attributes, @@ -249,16 +258,13 @@ Optimizely.prototype.__emitNotificationCenterActivate = function (experimentKey, if (experiment && experiment.variationKeyMap) { variation = experiment.variationKeyMap[variationKey]; } - this.notificationCenter.sendNotifications( - NOTIFICATION_TYPES.ACTIVATE, - { - experiment: experiment, - userId: userId, - attributes: attributes, - variation: variation, - logEvent: impressionEvent - } - ); + this.notificationCenter.sendNotifications(NOTIFICATION_TYPES.ACTIVATE, { + experiment: experiment, + userId: userId, + attributes: attributes, + variation: variation, + logEvent: impressionEvent, + }); }; /** @@ -268,7 +274,7 @@ Optimizely.prototype.__emitNotificationCenterActivate = function (experimentKey, * @param {string} attributes * @param {Object} eventTags Values associated with the event. */ -Optimizely.prototype.track = function (eventKey, userId, attributes, eventTags) { +Optimizely.prototype.track = function(eventKey, userId, attributes, eventTags) { try { if (!this.__isValidInstance()) { this.logger.log(LOG_LEVEL.ERROR, jsSdkUtils.sprintf(LOG_MESSAGES.INVALID_OBJECT, MODULE_NAME, 'track')); @@ -318,7 +324,7 @@ Optimizely.prototype.track = function (eventKey, userId, attributes, eventTags) * @param {string} attributes * @param {Object} eventTags Values associated with the event. */ -Optimizely.prototype.__emitNotificationCenterTrack = function (eventKey, userId, attributes, eventTags) { +Optimizely.prototype.__emitNotificationCenterTrack = function(eventKey, userId, attributes, eventTags) { try { var configObj = this.projectConfigManager.getConfig(); if (!configObj) { @@ -357,7 +363,7 @@ Optimizely.prototype.__emitNotificationCenterTrack = function (eventKey, userId, * @param {Object} attributes * @return {string|null} variation key */ -Optimizely.prototype.getVariation = function (experimentKey, userId, attributes) { +Optimizely.prototype.getVariation = function(experimentKey, userId, attributes) { try { if (!this.__isValidInstance()) { this.logger.log(LOG_LEVEL.ERROR, jsSdkUtils.sprintf(LOG_MESSAGES.INVALID_OBJECT, MODULE_NAME, 'getVariation')); @@ -376,26 +382,27 @@ Optimizely.prototype.getVariation = function (experimentKey, userId, attributes) var experiment = configObj.experimentKeyMap[experimentKey]; if (!experiment) { - this.logger.log(LOG_LEVEL.DEBUG, jsSdkUtils.sprintf(ERROR_MESSAGES.INVALID_EXPERIMENT_KEY, MODULE_NAME, experimentKey)); + this.logger.log( + LOG_LEVEL.DEBUG, + jsSdkUtils.sprintf(ERROR_MESSAGES.INVALID_EXPERIMENT_KEY, MODULE_NAME, experimentKey) + ); return null; } var variationKey = this.decisionService.getVariation(configObj, experimentKey, userId, attributes); - var decisionNotificationType = projectConfig.isFeatureExperiment(configObj, experiment.id) ? DECISION_NOTIFICATION_TYPES.FEATURE_TEST : - DECISION_NOTIFICATION_TYPES.AB_TEST; - - this.notificationCenter.sendNotifications( - NOTIFICATION_TYPES.DECISION, - { - type: decisionNotificationType, - userId: userId, - attributes: attributes || {}, - decisionInfo: { - experimentKey: experimentKey, - variationKey: variationKey, - } - } - ); + var decisionNotificationType = projectConfig.isFeatureExperiment(configObj, experiment.id) + ? DECISION_NOTIFICATION_TYPES.FEATURE_TEST + : DECISION_NOTIFICATION_TYPES.AB_TEST; + + this.notificationCenter.sendNotifications(NOTIFICATION_TYPES.DECISION, { + type: decisionNotificationType, + userId: userId, + attributes: attributes || {}, + decisionInfo: { + experimentKey: experimentKey, + variationKey: variationKey, + }, + }); return variationKey; } catch (ex) { @@ -417,7 +424,7 @@ Optimizely.prototype.getVariation = function (experimentKey, userId, attributes) * @param {string|null} variationKey user will be forced into. If null, then clear the existing experiment-to-variation mapping. * @return boolean A boolean value that indicates if the set completed successfully. */ -Optimizely.prototype.setForcedVariation = function (experimentKey, userId, variationKey) { +Optimizely.prototype.setForcedVariation = function(experimentKey, userId, variationKey) { if (!this.__validateInputs({ experiment_key: experimentKey, user_id: userId })) { return false; } @@ -442,7 +449,7 @@ Optimizely.prototype.setForcedVariation = function (experimentKey, userId, varia * @param {string} userId * @return {string|null} The forced variation key. */ -Optimizely.prototype.getForcedVariation = function (experimentKey, userId) { +Optimizely.prototype.getForcedVariation = function(experimentKey, userId) { if (!this.__validateInputs({ experiment_key: experimentKey, user_id: userId })) { return null; } @@ -469,7 +476,7 @@ Optimizely.prototype.getForcedVariation = function (experimentKey, userId) { * @return {boolean} True if inputs are valid * */ -Optimizely.prototype.__validateInputs = function (stringInputs, userAttributes, eventTags) { +Optimizely.prototype.__validateInputs = function(stringInputs, userAttributes, eventTags) { try { // Null, undefined or non-string user Id is invalid. if (stringInputs.hasOwnProperty('user_id')) { @@ -508,8 +515,13 @@ Optimizely.prototype.__validateInputs = function (stringInputs, userAttributes, * @param userId * @return {null} */ -Optimizely.prototype.__notActivatingExperiment = function (experimentKey, userId) { - var failedActivationLogMessage = jsSdkUtils.sprintf(LOG_MESSAGES.NOT_ACTIVATING_USER, MODULE_NAME, userId, experimentKey); +Optimizely.prototype.__notActivatingExperiment = function(experimentKey, userId) { + var failedActivationLogMessage = jsSdkUtils.sprintf( + LOG_MESSAGES.NOT_ACTIVATING_USER, + MODULE_NAME, + userId, + experimentKey + ); this.logger.log(LOG_LEVEL.INFO, failedActivationLogMessage); return null; }; @@ -519,7 +531,7 @@ Optimizely.prototype.__notActivatingExperiment = function (experimentKey, userId * @param map * @returns {Object} map */ -Optimizely.prototype.__filterEmptyValues = function (map) { +Optimizely.prototype.__filterEmptyValues = function(map) { for (var key in map) { if (map.hasOwnProperty(key) && (map[key] === null || map[key] === undefined)) { delete map[key]; @@ -535,10 +547,13 @@ Optimizely.prototype.__filterEmptyValues = function (map) { * @param {Object} attributes Optional user attributes * @return {boolean} True if the feature is enabled for the user, false otherwise */ -Optimizely.prototype.isFeatureEnabled = function (featureKey, userId, attributes) { +Optimizely.prototype.isFeatureEnabled = function(featureKey, userId, attributes) { try { if (!this.__isValidInstance()) { - this.logger.log(LOG_LEVEL.ERROR, jsSdkUtils.sprintf(LOG_MESSAGES.INVALID_OBJECT, MODULE_NAME, 'isFeatureEnabled')); + this.logger.log( + LOG_LEVEL.ERROR, + jsSdkUtils.sprintf(LOG_MESSAGES.INVALID_OBJECT, MODULE_NAME, 'isFeatureEnabled') + ); return false; } @@ -567,16 +582,22 @@ Optimizely.prototype.isFeatureEnabled = function (featureKey, userId, attributes 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); } } if (featureEnabled === true) { - this.logger.log(LOG_LEVEL.INFO, jsSdkUtils.sprintf(LOG_MESSAGES.FEATURE_ENABLED_FOR_USER, MODULE_NAME, featureKey, userId)); + this.logger.log( + LOG_LEVEL.INFO, + jsSdkUtils.sprintf(LOG_MESSAGES.FEATURE_ENABLED_FOR_USER, MODULE_NAME, featureKey, userId) + ); } else { - this.logger.log(LOG_LEVEL.INFO, jsSdkUtils.sprintf(LOG_MESSAGES.FEATURE_NOT_ENABLED_FOR_USER, MODULE_NAME, featureKey, userId)); + this.logger.log( + LOG_LEVEL.INFO, + jsSdkUtils.sprintf(LOG_MESSAGES.FEATURE_NOT_ENABLED_FOR_USER, MODULE_NAME, featureKey, userId) + ); featureEnabled = false; } @@ -584,18 +605,15 @@ Optimizely.prototype.isFeatureEnabled = function (featureKey, userId, attributes featureKey: featureKey, featureEnabled: featureEnabled, source: decision.decisionSource, - sourceInfo: sourceInfo + sourceInfo: sourceInfo, }; - this.notificationCenter.sendNotifications( - NOTIFICATION_TYPES.DECISION, - { - type: DECISION_NOTIFICATION_TYPES.FEATURE, - userId: userId, - attributes: attributes || {}, - decisionInfo: featureInfo, - } - ); + this.notificationCenter.sendNotifications(NOTIFICATION_TYPES.DECISION, { + type: DECISION_NOTIFICATION_TYPES.FEATURE, + userId: userId, + attributes: attributes || {}, + decisionInfo: featureInfo, + }); return featureEnabled; } catch (e) { @@ -612,11 +630,14 @@ Optimizely.prototype.isFeatureEnabled = function (featureKey, userId, attributes * @param {Object} attributes * @return {Array} Array of feature keys (strings) */ -Optimizely.prototype.getEnabledFeatures = function (userId, attributes) { +Optimizely.prototype.getEnabledFeatures = function(userId, attributes) { try { var enabledFeatures = []; if (!this.__isValidInstance()) { - this.logger.log(LOG_LEVEL.ERROR, jsSdkUtils.sprintf(LOG_MESSAGES.INVALID_OBJECT, MODULE_NAME, 'getEnabledFeatures')); + this.logger.log( + LOG_LEVEL.ERROR, + jsSdkUtils.sprintf(LOG_MESSAGES.INVALID_OBJECT, MODULE_NAME, 'getEnabledFeatures') + ); return enabledFeatures; } @@ -629,11 +650,13 @@ Optimizely.prototype.getEnabledFeatures = function (userId, attributes) { return enabledFeatures; } - jsSdkUtils.objectValues(configObj.featureKeyMap).forEach(function (feature) { - if (this.isFeatureEnabled(feature.key, userId, attributes)) { - enabledFeatures.push(feature.key); - } - }.bind(this)); + jsSdkUtils.objectValues(configObj.featureKeyMap).forEach( + function(feature) { + if (this.isFeatureEnabled(feature.key, userId, attributes)) { + enabledFeatures.push(feature.key); + } + }.bind(this) + ); return enabledFeatures; } catch (e) { @@ -658,7 +681,7 @@ Optimizely.prototype.getEnabledFeatures = function (userId, attributes) { * the variable key is invalid */ -Optimizely.prototype.getFeatureVariable = function (featureKey, variableKey, userId, attributes) { +Optimizely.prototype.getFeatureVariable = function(featureKey, variableKey, userId, attributes) { try { return this._getFeatureVariableForType(featureKey, variableKey, null, userId, attributes); } catch (e) { @@ -690,9 +713,11 @@ Optimizely.prototype.getFeatureVariable = function (featureKey, variableKey, use * variable key is invalid, or there is a mismatch * with the type of the variable */ -Optimizely.prototype._getFeatureVariableForType = function (featureKey, variableKey, variableType, userId, attributes) { +Optimizely.prototype._getFeatureVariableForType = function(featureKey, variableKey, variableType, userId, attributes) { if (!this.__isValidInstance()) { - var apiName = (variableType) ? 'getFeatureVariable' + variableType.charAt(0).toUpperCase() + variableType.slice(1) : 'getFeatureVariable'; + var apiName = variableType + ? 'getFeatureVariable' + variableType.charAt(0).toUpperCase() + variableType.slice(1) + : 'getFeatureVariable'; this.logger.log(LOG_LEVEL.ERROR, jsSdkUtils.sprintf(LOG_MESSAGES.INVALID_OBJECT, MODULE_NAME, apiName)); return null; } @@ -736,17 +761,51 @@ Optimizely.prototype._getFeatureVariableForType = function (featureKey, variable if (value !== null) { if (featureEnabled === true) { variableValue = value; - this.logger.log(LOG_LEVEL.INFO, jsSdkUtils.sprintf(LOG_MESSAGES.USER_RECEIVED_VARIABLE_VALUE, MODULE_NAME, variableKey, featureFlag.key, variableValue, userId)); + this.logger.log( + LOG_LEVEL.INFO, + jsSdkUtils.sprintf( + LOG_MESSAGES.USER_RECEIVED_VARIABLE_VALUE, + MODULE_NAME, + variableKey, + featureFlag.key, + variableValue, + userId + ) + ); } else { - this.logger.log(LOG_LEVEL.INFO, jsSdkUtils.sprintf(LOG_MESSAGES.FEATURE_NOT_ENABLED_RETURN_DEFAULT_VARIABLE_VALUE, MODULE_NAME, - featureFlag.key, userId, variableKey)); + this.logger.log( + LOG_LEVEL.INFO, + jsSdkUtils.sprintf( + LOG_MESSAGES.FEATURE_NOT_ENABLED_RETURN_DEFAULT_VARIABLE_VALUE, + MODULE_NAME, + featureFlag.key, + userId, + variableKey + ) + ); } } else { - this.logger.log(LOG_LEVEL.INFO, jsSdkUtils.sprintf(LOG_MESSAGES.VARIABLE_NOT_USED_RETURN_DEFAULT_VARIABLE_VALUE, MODULE_NAME, variableKey, decision.variation.key)); + this.logger.log( + LOG_LEVEL.INFO, + jsSdkUtils.sprintf( + LOG_MESSAGES.VARIABLE_NOT_USED_RETURN_DEFAULT_VARIABLE_VALUE, + MODULE_NAME, + variableKey, + decision.variation.key + ) + ); } } else { - this.logger.log(LOG_LEVEL.INFO, jsSdkUtils.sprintf(LOG_MESSAGES.USER_RECEIVED_DEFAULT_VARIABLE_VALUE, MODULE_NAME, userId, - variableKey, featureFlag.key)); + this.logger.log( + LOG_LEVEL.INFO, + jsSdkUtils.sprintf( + LOG_MESSAGES.USER_RECEIVED_DEFAULT_VARIABLE_VALUE, + MODULE_NAME, + userId, + variableKey, + featureFlag.key + ) + ); } var sourceInfo = {}; @@ -754,27 +813,24 @@ Optimizely.prototype._getFeatureVariableForType = function (featureKey, variable sourceInfo = { experimentKey: decision.experiment.key, variationKey: decision.variation.key, - } + }; } var typeCastedValue = projectConfig.getTypeCastValue(variableValue, variableType, this.logger); - this.notificationCenter.sendNotifications( - NOTIFICATION_TYPES.DECISION, - { - type: DECISION_NOTIFICATION_TYPES.FEATURE_VARIABLE, - userId: userId, - attributes: attributes || {}, - decisionInfo: { - featureKey: featureKey, - featureEnabled: featureEnabled, - source: decision.decisionSource, - variableKey: variableKey, - variableValue: typeCastedValue, - variableType: variableType, - sourceInfo: sourceInfo, - } - } - ); + this.notificationCenter.sendNotifications(NOTIFICATION_TYPES.DECISION, { + type: DECISION_NOTIFICATION_TYPES.FEATURE_VARIABLE, + userId: userId, + attributes: attributes || {}, + decisionInfo: { + featureKey: featureKey, + featureEnabled: featureEnabled, + source: decision.decisionSource, + variableKey: variableKey, + variableValue: typeCastedValue, + variableType: variableType, + sourceInfo: sourceInfo, + }, + }); return typeCastedValue; }; @@ -792,7 +848,7 @@ Optimizely.prototype._getFeatureVariableForType = function (featureKey, variable * invalid, or there is a mismatch with the type * of the variable */ -Optimizely.prototype.getFeatureVariableBoolean = function (featureKey, variableKey, userId, attributes) { +Optimizely.prototype.getFeatureVariableBoolean = function(featureKey, variableKey, userId, attributes) { try { return this._getFeatureVariableForType(featureKey, variableKey, FEATURE_VARIABLE_TYPES.BOOLEAN, userId, attributes); } catch (e) { @@ -816,7 +872,7 @@ Optimizely.prototype.getFeatureVariableBoolean = function (featureKey, variableK * invalid, or there is a mismatch with the type * of the variable */ -Optimizely.prototype.getFeatureVariableDouble = function (featureKey, variableKey, userId, attributes) { +Optimizely.prototype.getFeatureVariableDouble = function(featureKey, variableKey, userId, attributes) { try { return this._getFeatureVariableForType(featureKey, variableKey, FEATURE_VARIABLE_TYPES.DOUBLE, userId, attributes); } catch (e) { @@ -840,7 +896,7 @@ Optimizely.prototype.getFeatureVariableDouble = function (featureKey, variableKe * invalid, or there is a mismatch with the type * of the variable */ -Optimizely.prototype.getFeatureVariableInteger = function (featureKey, variableKey, userId, attributes) { +Optimizely.prototype.getFeatureVariableInteger = function(featureKey, variableKey, userId, attributes) { try { return this._getFeatureVariableForType(featureKey, variableKey, FEATURE_VARIABLE_TYPES.INTEGER, userId, attributes); } catch (e) { @@ -864,7 +920,7 @@ Optimizely.prototype.getFeatureVariableInteger = function (featureKey, variableK * invalid, or there is a mismatch with the type * of the variable */ -Optimizely.prototype.getFeatureVariableString = function (featureKey, variableKey, userId, attributes) { +Optimizely.prototype.getFeatureVariableString = function(featureKey, variableKey, userId, attributes) { try { return this._getFeatureVariableForType(featureKey, variableKey, FEATURE_VARIABLE_TYPES.STRING, userId, attributes); } catch (e) { @@ -910,7 +966,7 @@ Optimizely.prototype.getFeatureVariableString = function (featureKey, variableKe * } * } */ -Optimizely.prototype.getOptimizelyConfig = function () { +Optimizely.prototype.getOptimizelyConfig = function() { try { var configObj = this.projectConfigManager.getConfig(); if (!configObj) { @@ -922,7 +978,7 @@ Optimizely.prototype.getOptimizelyConfig = function () { this.errorHandler.handleError(e); return null; } -} +}; /** * Stop background processes belonging to this instance, including: @@ -955,7 +1011,7 @@ Optimizely.prototype.getOptimizelyConfig = function () { * * @return {Promise} */ -Optimizely.prototype.close = function () { +Optimizely.prototype.close = function() { try { var eventProcessorStoppedPromise = this.eventProcessor.stop(); if (this.__disposeOnUpdate) { @@ -965,19 +1021,21 @@ Optimizely.prototype.close = function () { if (this.projectConfigManager) { this.projectConfigManager.stop(); } - Object.keys(this.__readyTimeouts).forEach(function (readyTimeoutId) { - var readyTimeoutRecord = this.__readyTimeouts[readyTimeoutId]; - clearTimeout(readyTimeoutRecord.readyTimeout); - readyTimeoutRecord.onClose(); - }.bind(this)); + Object.keys(this.__readyTimeouts).forEach( + function(readyTimeoutId) { + var readyTimeoutRecord = this.__readyTimeouts[readyTimeoutId]; + clearTimeout(readyTimeoutRecord.readyTimeout); + readyTimeoutRecord.onClose(); + }.bind(this) + ); this.__readyTimeouts = {}; return eventProcessorStoppedPromise.then( - function () { + function() { return { success: true, }; }, - function (err) { + function(err) { return { success: false, reason: String(err), @@ -1021,7 +1079,7 @@ Optimizely.prototype.close = function () { * @param {number|undefined} options.timeout * @return {Promise} */ -Optimizely.prototype.onReady = function (options) { +Optimizely.prototype.onReady = function(options) { var timeout; if (typeof options === 'object' && options !== null) { timeout = options.timeout; @@ -1031,14 +1089,14 @@ Optimizely.prototype.onReady = function (options) { } var resolveTimeoutPromise; - var timeoutPromise = new Promise(function (resolve) { + var timeoutPromise = new Promise(function(resolve) { resolveTimeoutPromise = resolve; }); var timeoutId = this.__nextReadyTimeoutId; this.__nextReadyTimeoutId++; - var onReadyTimeout = function () { + var onReadyTimeout = function() { delete this.__readyTimeouts[timeoutId]; resolveTimeoutPromise({ success: false, @@ -1046,7 +1104,7 @@ Optimizely.prototype.onReady = function (options) { }); }.bind(this); var readyTimeout = setTimeout(onReadyTimeout, timeout); - var onClose = function () { + var onClose = function() { resolveTimeoutPromise({ success: false, reason: 'Instance closed', @@ -1058,13 +1116,15 @@ Optimizely.prototype.onReady = function (options) { onClose: onClose, }; - this.__readyPromise.then(function () { - clearTimeout(readyTimeout); - delete this.__readyTimeouts[timeoutId]; - resolveTimeoutPromise({ - success: true, - }); - }.bind(this)); + this.__readyPromise.then( + function() { + clearTimeout(readyTimeout); + delete this.__readyTimeouts[timeoutId]; + resolveTimeoutPromise({ + success: true, + }); + }.bind(this) + ); return Promise.race([this.__readyPromise, timeoutPromise]); }; diff --git a/packages/optimizely-sdk/lib/optimizely/index.tests.js b/packages/optimizely-sdk/lib/optimizely/index.tests.js index 1183241db..e5efd72d8 100644 --- a/packages/optimizely-sdk/lib/optimizely/index.tests.js +++ b/packages/optimizely-sdk/lib/optimizely/index.tests.js @@ -46,11 +46,11 @@ var DECISION_SOURCES = enums.DECISION_SOURCES; var DECISION_NOTIFICATION_TYPES = enums.DECISION_NOTIFICATION_TYPES; var FEATURE_VARIABLE_TYPES = enums.FEATURE_VARIABLE_TYPES; -describe('lib/optimizely', function () { +describe('lib/optimizely', function() { var ProjectConfigManagerStub; var globalStubErrorHandler; var stubLogHandler; - beforeEach(function () { + beforeEach(function() { logging.setLogLevel('notset'); stubLogHandler = { log: sinon.stub(), @@ -60,39 +60,43 @@ describe('lib/optimizely', function () { handleError: sinon.stub(), }; logging.setErrorHandler(globalStubErrorHandler); - ProjectConfigManagerStub = sinon.stub(projectConfigManager, 'ProjectConfigManager').callsFake(function (config) { + ProjectConfigManagerStub = sinon.stub(projectConfigManager, 'ProjectConfigManager').callsFake(function(config) { var currentConfig = config.datafile ? projectConfig.createProjectConfig(config.datafile) : null; return { stop: sinon.stub(), getConfig: sinon.stub().returns(currentConfig), - onUpdate: sinon.stub().returns(function () { }), - onReady: sinon.stub().returns({ then: function () { } }) + onUpdate: sinon.stub().returns(function() {}), + onReady: sinon.stub().returns({ then: function() {} }), }; }); }); - afterEach(function () { + afterEach(function() { ProjectConfigManagerStub.restore(); logging.resetErrorHandler(); logging.resetLogger(); }); - describe('constructor', function () { - var stubErrorHandler = { handleError: function () { } }; - var stubEventDispatcher = { dispatchEvent: function () { return bluebird.resolve(null); } }; + describe('constructor', function() { + var stubErrorHandler = { handleError: function() {} }; + var stubEventDispatcher = { + dispatchEvent: function() { + return bluebird.resolve(null); + }, + }; var createdLogger = logger.createLogger({ logLevel: LOG_LEVEL.INFO }); - beforeEach(function () { + beforeEach(function() { sinon.stub(stubErrorHandler, 'handleError'); sinon.stub(createdLogger, 'log'); }); - afterEach(function () { + afterEach(function() { stubErrorHandler.handleError.restore(); createdLogger.log.restore(); }); - describe('constructor', function () { - it('should construct an instance of the Optimizely class', function () { + describe('constructor', function() { + it('should construct an instance of the Optimizely class', function() { var optlyInstance = new Optimizely({ clientEngine: 'node-sdk', datafile: testData.getTestProjectConfig(), @@ -104,7 +108,7 @@ describe('lib/optimizely', function () { assert.instanceOf(optlyInstance, Optimizely); }); - it('should construct an instance of the Optimizely class when datafile is JSON string', function () { + it('should construct an instance of the Optimizely class when datafile is JSON string', function() { var optlyInstance = new Optimizely({ clientEngine: 'node-sdk', datafile: JSON.stringify(testData.getTestProjectConfig()), @@ -116,7 +120,7 @@ describe('lib/optimizely', function () { assert.instanceOf(optlyInstance, Optimizely); }); - it('should log if the client engine passed in is invalid', function () { + it('should log if the client engine passed in is invalid', function() { new Optimizely({ datafile: testData.getTestProjectConfig(), errorHandler: stubErrorHandler, @@ -129,7 +133,7 @@ describe('lib/optimizely', function () { assert.strictEqual(logMessage, sprintf(LOG_MESSAGES.INVALID_CLIENT_ENGINE, 'OPTIMIZELY', 'undefined')); }); - it('should allow passing `react-sdk` as the clientEngine', function () { + it('should allow passing `react-sdk` as the clientEngine', function() { var instance = new Optimizely({ clientEngine: 'react-sdk', datafile: testData.getTestProjectConfig(), @@ -141,19 +145,19 @@ describe('lib/optimizely', function () { assert.strictEqual(instance.clientEngine, 'react-sdk'); }); - describe('when a user profile service is provided', function () { - beforeEach(function () { + describe('when a user profile service is provided', function() { + beforeEach(function() { sinon.stub(decisionService, 'createDecisionService'); }); - afterEach(function () { + afterEach(function() { decisionService.createDecisionService.restore(); }); - it('should validate and pass the user profile service to the decision service', function () { + it('should validate and pass the user profile service to the decision service', function() { var userProfileServiceInstance = { - lookup: function () { }, - save: function () { }, + lookup: function() {}, + save: function() {}, }; var optlyInstance = new Optimizely({ @@ -174,9 +178,9 @@ describe('lib/optimizely', function () { assert.strictEqual(logMessage, 'OPTIMIZELY: Valid user profile service provided.'); }); - it('should pass in a null user profile to the decision service if the provided user profile is invalid', function () { + it('should pass in a null user profile to the decision service if the provided user profile is invalid', function() { var invalidUserProfile = { - save: function () { }, + save: function() {}, }; var optlyInstance = new Optimizely({ @@ -194,12 +198,15 @@ describe('lib/optimizely', function () { }); var logMessage = createdLogger.log.args[0][1]; - assert.strictEqual(logMessage, 'USER_PROFILE_SERVICE_VALIDATOR: Provided user profile service instance is in an invalid format: Missing function \'lookup\'.'); + assert.strictEqual( + logMessage, + "USER_PROFILE_SERVICE_VALIDATOR: Provided user profile service instance is in an invalid format: Missing function 'lookup'." + ); }); }); - describe('when an sdkKey is provided', function () { - it('should not log an error when sdkKey is provided and datafile is not provided', function () { + describe('when an sdkKey is provided', function() { + it('should not log an error when sdkKey is provided and datafile is not provided', function() { new Optimizely({ clientEngine: 'node-sdk', eventBuilder: eventBuilder, @@ -214,7 +221,7 @@ describe('lib/optimizely', function () { sinon.assert.notCalled(stubErrorHandler.handleError); }); - it('passes datafile, datafileOptions, sdkKey, and other options to the project config manager', function () { + it('passes datafile, datafileOptions, sdkKey, and other options to the project config manager', function() { new Optimizely({ clientEngine: 'node-sdk', datafile: testData.getTestProjectConfig(), @@ -246,7 +253,7 @@ describe('lib/optimizely', function () { }); }); - describe('APIs', function () { + describe('APIs', function() { var optlyInstance; var bucketStub; var clock; @@ -254,7 +261,7 @@ describe('lib/optimizely', function () { logLevel: LOG_LEVEL.INFO, logToConsole: false, }); - beforeEach(function () { + beforeEach(function() { optlyInstance = new Optimizely({ clientEngine: 'node-sdk', datafile: testData.getTestProjectConfig(), @@ -275,7 +282,7 @@ describe('lib/optimizely', function () { clock = sinon.useFakeTimers(new Date().getTime()); }); - afterEach(function () { + afterEach(function() { bucketer.bucket.restore(); eventDispatcher.dispatchEvent.restore(); errorHandler.handleError.restore(); @@ -284,8 +291,8 @@ describe('lib/optimizely', function () { uuid.v4.restore(); }); - describe('#activate', function () { - it('should call bucketer and dispatchEvent with proper args and return variation key', function () { + describe('#activate', function() { + it('should call bucketer and dispatchEvent with proper args and return variation key', function() { bucketStub.returns('111129'); var variation = optlyInstance.activate('testExperiment', 'testUser'); assert.strictEqual(variation, 'variation'); @@ -297,39 +304,50 @@ describe('lib/optimizely', function () { url: 'https://logx.optimizely.com/v1/events', httpVerb: 'POST', params: { - 'account_id': '12001', - 'project_id': '111001', - 'visitors': [{ - 'snapshots': [{ - 'decisions': [{ - 'campaign_id': '4', - 'experiment_id': '111127', - 'variation_id': '111129' - }], - 'events': [{ - 'entity_id': '4', - 'timestamp': Math.round(new Date().getTime()), - 'key': 'campaign_activated', - 'uuid': 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c' - }] - }], - 'visitor_id': 'testUser', - 'attributes': [], - }], - 'revision': '42', - 'client_name': 'node-sdk', - 'client_version': enums.NODE_CLIENT_VERSION, - 'anonymize_ip': false, - 'enrich_decisions': true, + account_id: '12001', + project_id: '111001', + visitors: [ + { + snapshots: [ + { + decisions: [ + { + campaign_id: '4', + experiment_id: '111127', + variation_id: '111129', + }, + ], + events: [ + { + entity_id: '4', + timestamp: Math.round(new Date().getTime()), + key: 'campaign_activated', + uuid: 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c', + }, + ], + }, + ], + visitor_id: 'testUser', + attributes: [], + }, + ], + revision: '42', + client_name: 'node-sdk', + client_version: enums.NODE_CLIENT_VERSION, + anonymize_ip: false, + enrich_decisions: true, }, }; var eventDispatcherCall = eventDispatcher.dispatchEvent.args[0]; assert.deepEqual(eventDispatcherCall[0], expectedObj); }); - it('should dispatch proper params for null value attributes', function () { + it('should dispatch proper params for null value attributes', function() { bucketStub.returns('122229'); - var activate = optlyInstance.activate('testExperimentWithAudiences', 'testUser', { browser_type: 'firefox', 'test_null_attribute': null }); + var activate = optlyInstance.activate('testExperimentWithAudiences', 'testUser', { + browser_type: 'firefox', + test_null_attribute: null, + }); assert.strictEqual(activate, 'variationWithAudience'); sinon.assert.calledOnce(bucketer.bucket); @@ -339,35 +357,45 @@ describe('lib/optimizely', function () { url: 'https://logx.optimizely.com/v1/events', httpVerb: 'POST', params: { - 'account_id': '12001', - 'project_id': '111001', - 'visitors': [{ - 'snapshots': [{ - 'decisions': [{ - 'campaign_id': '5', - 'experiment_id': '122227', - 'variation_id': '122229' - }], - 'events': [{ - 'entity_id': '5', - 'timestamp': Math.round(new Date().getTime()), - 'key': 'campaign_activated', - 'uuid': 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c' - }] - }], - 'visitor_id': 'testUser', - 'attributes': [{ - 'entity_id': '111094', - 'key': 'browser_type', - 'type': 'custom', - 'value': 'firefox' - }], - }], - 'revision': '42', - 'client_name': 'node-sdk', - 'client_version': enums.NODE_CLIENT_VERSION, - 'anonymize_ip': false, - 'enrich_decisions': true, + account_id: '12001', + project_id: '111001', + visitors: [ + { + snapshots: [ + { + decisions: [ + { + campaign_id: '5', + experiment_id: '122227', + variation_id: '122229', + }, + ], + events: [ + { + entity_id: '5', + timestamp: Math.round(new Date().getTime()), + key: 'campaign_activated', + uuid: 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c', + }, + ], + }, + ], + visitor_id: 'testUser', + attributes: [ + { + entity_id: '111094', + key: 'browser_type', + type: 'custom', + value: 'firefox', + }, + ], + }, + ], + revision: '42', + client_name: 'node-sdk', + client_version: enums.NODE_CLIENT_VERSION, + anonymize_ip: false, + enrich_decisions: true, }, }; @@ -375,7 +403,7 @@ describe('lib/optimizely', function () { assert.deepEqual(eventDispatcherCall[0], expectedObj); }); - it('should call bucketer and dispatchEvent with proper args and return variation key if user is in audience', function () { + it('should call bucketer and dispatchEvent with proper args and return variation key if user is in audience', function() { bucketStub.returns('122229'); var activate = optlyInstance.activate('testExperimentWithAudiences', 'testUser', { browser_type: 'firefox' }); assert.strictEqual(activate, 'variationWithAudience'); @@ -387,35 +415,45 @@ describe('lib/optimizely', function () { url: 'https://logx.optimizely.com/v1/events', httpVerb: 'POST', params: { - 'account_id': '12001', - 'project_id': '111001', - 'visitors': [{ - 'snapshots': [{ - 'decisions': [{ - 'campaign_id': '5', - 'experiment_id': '122227', - 'variation_id': '122229' - }], - 'events': [{ - 'entity_id': '5', - 'timestamp': Math.round(new Date().getTime()), - 'key': 'campaign_activated', - 'uuid': 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c' - }] - }], - 'visitor_id': 'testUser', - 'attributes': [{ - 'entity_id': '111094', - 'key': 'browser_type', - 'type': 'custom', - 'value': 'firefox' - }], - }], - 'revision': '42', - 'client_name': 'node-sdk', - 'client_version': enums.NODE_CLIENT_VERSION, - 'anonymize_ip': false, - 'enrich_decisions': true, + account_id: '12001', + project_id: '111001', + visitors: [ + { + snapshots: [ + { + decisions: [ + { + campaign_id: '5', + experiment_id: '122227', + variation_id: '122229', + }, + ], + events: [ + { + entity_id: '5', + timestamp: Math.round(new Date().getTime()), + key: 'campaign_activated', + uuid: 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c', + }, + ], + }, + ], + visitor_id: 'testUser', + attributes: [ + { + entity_id: '111094', + key: 'browser_type', + type: 'custom', + value: 'firefox', + }, + ], + }, + ], + revision: '42', + client_name: 'node-sdk', + client_version: enums.NODE_CLIENT_VERSION, + anonymize_ip: false, + enrich_decisions: true, }, }; @@ -423,7 +461,7 @@ describe('lib/optimizely', function () { assert.deepEqual(eventDispatcherCall[0], expectedObj); }); - it('should call activate and dispatchEvent with typed attributes and return variation key', function () { + it('should call activate and dispatchEvent with typed attributes and return variation key', function() { bucketStub.returns('122229'); var activate = optlyInstance.activate('testExperimentWithAudiences', 'testUser', { browser_type: 'firefox', @@ -440,50 +478,63 @@ describe('lib/optimizely', function () { url: 'https://logx.optimizely.com/v1/events', httpVerb: 'POST', params: { - 'account_id': '12001', - 'project_id': '111001', - 'visitors': [{ - 'snapshots': [{ - 'decisions': [{ - 'campaign_id': '5', - 'experiment_id': '122227', - 'variation_id': '122229' - }], - 'events': [{ - 'entity_id': '5', - 'timestamp': Math.round(new Date().getTime()), - 'key': 'campaign_activated', - 'uuid': 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c' - }] - }], - 'visitor_id': 'testUser', - 'attributes': [{ - 'entity_id': '111094', - 'key': 'browser_type', - 'type': 'custom', - 'value': 'firefox' - }, { - 'entity_id': '323434545', - 'key': 'boolean_key', - 'type': 'custom', - 'value': true - }, { - 'entity_id': '616727838', - 'key': 'integer_key', - 'type': 'custom', - 'value': 10 - }, { - 'entity_id': '808797686', - 'key': 'double_key', - 'type': 'custom', - 'value': 3.14 - }], - }], - 'revision': '42', - 'client_name': 'node-sdk', - 'client_version': enums.NODE_CLIENT_VERSION, - 'anonymize_ip': false, - 'enrich_decisions': true, + account_id: '12001', + project_id: '111001', + visitors: [ + { + snapshots: [ + { + decisions: [ + { + campaign_id: '5', + experiment_id: '122227', + variation_id: '122229', + }, + ], + events: [ + { + entity_id: '5', + timestamp: Math.round(new Date().getTime()), + key: 'campaign_activated', + uuid: 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c', + }, + ], + }, + ], + visitor_id: 'testUser', + attributes: [ + { + entity_id: '111094', + key: 'browser_type', + type: 'custom', + value: 'firefox', + }, + { + entity_id: '323434545', + key: 'boolean_key', + type: 'custom', + value: true, + }, + { + entity_id: '616727838', + key: 'integer_key', + type: 'custom', + value: 10, + }, + { + entity_id: '808797686', + key: 'double_key', + type: 'custom', + value: 3.14, + }, + ], + }, + ], + revision: '42', + client_name: 'node-sdk', + client_version: enums.NODE_CLIENT_VERSION, + anonymize_ip: false, + enrich_decisions: true, }, }; @@ -491,8 +542,8 @@ describe('lib/optimizely', function () { assert.deepEqual(eventDispatcherCall[0], expectedObj); }); - describe('when experiment_bucket_map attribute is present', function () { - it('should call activate and respect attribute experiment_bucket_map', function () { + describe('when experiment_bucket_map attribute is present', function() { + it('should call activate and respect attribute experiment_bucket_map', function() { bucketStub.returns('111128'); // id of "control" variation var activate = optlyInstance.activate('testExperiment', 'testUser', { $opt_experiment_bucket_map: { @@ -507,7 +558,7 @@ describe('lib/optimizely', function () { }); }); - it('should call bucketer and dispatchEvent with proper args and return variation key if user is in grouped experiment', function () { + it('should call bucketer and dispatchEvent with proper args and return variation key if user is in grouped experiment', function() { bucketStub.returns('662'); var activate = optlyInstance.activate('groupExperiment2', 'testUser'); assert.strictEqual(activate, 'var2exp2'); @@ -519,30 +570,38 @@ describe('lib/optimizely', function () { url: 'https://logx.optimizely.com/v1/events', httpVerb: 'POST', params: { - 'account_id': '12001', - 'project_id': '111001', - 'visitors': [{ - 'snapshots': [{ - 'decisions': [{ - 'campaign_id': '2', - 'experiment_id': '443', - 'variation_id': '662' - }], - 'events': [{ - 'entity_id': '2', - 'timestamp': Math.round(new Date().getTime()), - 'key': 'campaign_activated', - 'uuid': 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c' - }] - }], - 'visitor_id': 'testUser', - 'attributes': [], - }], - 'revision': '42', - 'client_name': 'node-sdk', - 'client_version': enums.NODE_CLIENT_VERSION, - 'anonymize_ip': false, - 'enrich_decisions': true, + account_id: '12001', + project_id: '111001', + visitors: [ + { + snapshots: [ + { + decisions: [ + { + campaign_id: '2', + experiment_id: '443', + variation_id: '662', + }, + ], + events: [ + { + entity_id: '2', + timestamp: Math.round(new Date().getTime()), + key: 'campaign_activated', + uuid: 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c', + }, + ], + }, + ], + visitor_id: 'testUser', + attributes: [], + }, + ], + revision: '42', + client_name: 'node-sdk', + client_version: enums.NODE_CLIENT_VERSION, + anonymize_ip: false, + enrich_decisions: true, }, }; @@ -550,7 +609,7 @@ describe('lib/optimizely', function () { assert.deepEqual(eventDispatcherCall[0], expectedObj); }); - it('should call bucketer and dispatchEvent with proper args and return variation key if user is in grouped experiment and is in audience', function () { + it('should call bucketer and dispatchEvent with proper args and return variation key if user is in grouped experiment and is in audience', function() { bucketStub.returns('552'); var activate = optlyInstance.activate('groupExperiment1', 'testUser', { browser_type: 'firefox' }); assert.strictEqual(activate, 'var2exp1'); @@ -562,35 +621,45 @@ describe('lib/optimizely', function () { url: 'https://logx.optimizely.com/v1/events', httpVerb: 'POST', params: { - 'account_id': '12001', - 'project_id': '111001', - 'visitors': [{ - 'snapshots': [{ - 'decisions': [{ - 'campaign_id': '1', - 'experiment_id': '442', - 'variation_id': '552' - }], - 'events': [{ - 'entity_id': '1', - 'timestamp': Math.round(new Date().getTime()), - 'key': 'campaign_activated', - 'uuid': 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c' - }] - }], - 'visitor_id': 'testUser', - 'attributes': [{ - 'entity_id': '111094', - 'key': 'browser_type', - 'type': 'custom', - 'value': 'firefox' - }], - }], - 'revision': '42', - 'client_name': 'node-sdk', - 'client_version': enums.NODE_CLIENT_VERSION, - 'anonymize_ip': false, - 'enrich_decisions': true, + account_id: '12001', + project_id: '111001', + visitors: [ + { + snapshots: [ + { + decisions: [ + { + campaign_id: '1', + experiment_id: '442', + variation_id: '552', + }, + ], + events: [ + { + entity_id: '1', + timestamp: Math.round(new Date().getTime()), + key: 'campaign_activated', + uuid: 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c', + }, + ], + }, + ], + visitor_id: 'testUser', + attributes: [ + { + entity_id: '111094', + key: 'browser_type', + type: 'custom', + value: 'firefox', + }, + ], + }, + ], + revision: '42', + client_name: 'node-sdk', + client_version: enums.NODE_CLIENT_VERSION, + anonymize_ip: false, + enrich_decisions: true, }, }; @@ -598,24 +667,26 @@ describe('lib/optimizely', function () { assert.deepEqual(eventDispatcherCall[0], expectedObj); }); - it('should not make a dispatch event call if variation ID is null', function () { + it('should not make a dispatch event call if variation ID is null', function() { bucketStub.returns(null); assert.isNull(optlyInstance.activate('testExperiment', 'testUser')); sinon.assert.notCalled(eventDispatcher.dispatchEvent); sinon.assert.called(createdLogger.log); - sinon.assert.calledWithExactly(createdLogger.log, LOG_LEVEL.DEBUG, sprintf(LOG_MESSAGES.USER_HAS_NO_FORCED_VARIATION, - 'DECISION_SERVICE', - 'testUser')); - + sinon.assert.calledWithExactly( + createdLogger.log, + LOG_LEVEL.DEBUG, + sprintf(LOG_MESSAGES.USER_HAS_NO_FORCED_VARIATION, 'DECISION_SERVICE', 'testUser') + ); - sinon.assert.calledWithExactly(createdLogger.log, LOG_LEVEL.INFO, sprintf(LOG_MESSAGES.NOT_ACTIVATING_USER, - 'OPTIMIZELY', - 'testUser', - 'testExperiment')); + sinon.assert.calledWithExactly( + createdLogger.log, + LOG_LEVEL.INFO, + sprintf(LOG_MESSAGES.NOT_ACTIVATING_USER, 'OPTIMIZELY', 'testUser', 'testExperiment') + ); }); - it('should return null if user is not in audience and user is not in group', function () { + it('should return null if user is not in audience and user is not in group', function() { assert.isNull(optlyInstance.activate('testExperimentWithAudiences', 'testUser', { browser_type: 'chrome' })); sinon.assert.calledWithExactly( @@ -637,7 +708,7 @@ describe('lib/optimizely', function () { ); }); - it('should return null if user is not in audience and user is in group', function () { + it('should return null if user is not in audience and user is in group', function() { assert.isNull(optlyInstance.activate('groupExperiment1', 'testUser', { browser_type: 'chrome' })); sinon.assert.calledWithExactly( @@ -659,17 +730,23 @@ describe('lib/optimizely', function () { ); }); - it('should return null if experiment is not running', function () { + it('should return null if experiment is not running', function() { assert.isNull(optlyInstance.activate('testExperimentNotRunning', 'testUser')); sinon.assert.calledTwice(createdLogger.log); var logMessage1 = createdLogger.log.args[0][1]; - assert.strictEqual(logMessage1, sprintf(LOG_MESSAGES.EXPERIMENT_NOT_RUNNING, 'DECISION_SERVICE', 'testExperimentNotRunning')); + assert.strictEqual( + logMessage1, + sprintf(LOG_MESSAGES.EXPERIMENT_NOT_RUNNING, 'DECISION_SERVICE', 'testExperimentNotRunning') + ); var logMessage2 = createdLogger.log.args[1][1]; - assert.strictEqual(logMessage2, sprintf(LOG_MESSAGES.NOT_ACTIVATING_USER, 'OPTIMIZELY', 'testUser', 'testExperimentNotRunning')); + assert.strictEqual( + logMessage2, + sprintf(LOG_MESSAGES.NOT_ACTIVATING_USER, 'OPTIMIZELY', 'testUser', 'testExperimentNotRunning') + ); }); - it('should throw an error for invalid user ID', function () { + it('should throw an error for invalid user ID', function() { assert.isNull(optlyInstance.activate('testExperiment', null)); sinon.assert.notCalled(eventDispatcher.dispatchEvent); @@ -683,22 +760,31 @@ describe('lib/optimizely', function () { var logMessage1 = createdLogger.log.args[0][1]; assert.strictEqual(logMessage1, sprintf(ERROR_MESSAGES.INVALID_INPUT_FORMAT, 'OPTIMIZELY', 'user_id')); var logMessage2 = createdLogger.log.args[1][1]; - assert.strictEqual(logMessage2, sprintf(LOG_MESSAGES.NOT_ACTIVATING_USER, 'OPTIMIZELY', 'null', 'testExperiment')); + assert.strictEqual( + logMessage2, + sprintf(LOG_MESSAGES.NOT_ACTIVATING_USER, 'OPTIMIZELY', 'null', 'testExperiment') + ); }); - it('should log an error for invalid experiment key', function () { + it('should log an error for invalid experiment key', function() { assert.isNull(optlyInstance.activate('invalidExperimentKey', 'testUser')); sinon.assert.notCalled(eventDispatcher.dispatchEvent); sinon.assert.calledTwice(createdLogger.log); var logMessage1 = createdLogger.log.args[0][1]; - assert.strictEqual(logMessage1, sprintf(ERROR_MESSAGES.INVALID_EXPERIMENT_KEY, 'OPTIMIZELY', 'invalidExperimentKey')); + assert.strictEqual( + logMessage1, + sprintf(ERROR_MESSAGES.INVALID_EXPERIMENT_KEY, 'OPTIMIZELY', 'invalidExperimentKey') + ); var logMessage2 = createdLogger.log.args[1][1]; - assert.strictEqual(logMessage2, sprintf(LOG_MESSAGES.NOT_ACTIVATING_USER, 'OPTIMIZELY', 'testUser', 'invalidExperimentKey')); + assert.strictEqual( + logMessage2, + sprintf(LOG_MESSAGES.NOT_ACTIVATING_USER, 'OPTIMIZELY', 'testUser', 'invalidExperimentKey') + ); }); - it('should throw an error for invalid attributes', function () { + it('should throw an error for invalid attributes', function() { assert.isNull(optlyInstance.activate('testExperimentWithAudiences', 'testUser', [])); sinon.assert.notCalled(eventDispatcher.dispatchEvent); @@ -710,10 +796,13 @@ describe('lib/optimizely', function () { var logMessage1 = createdLogger.log.args[0][1]; assert.strictEqual(logMessage1, sprintf(ERROR_MESSAGES.INVALID_ATTRIBUTES, 'ATTRIBUTES_VALIDATOR')); var logMessage2 = createdLogger.log.args[1][1]; - assert.strictEqual(logMessage2, sprintf(LOG_MESSAGES.NOT_ACTIVATING_USER, 'OPTIMIZELY', 'testUser', 'testExperimentWithAudiences')); + assert.strictEqual( + logMessage2, + sprintf(LOG_MESSAGES.NOT_ACTIVATING_USER, 'OPTIMIZELY', 'testUser', 'testExperimentWithAudiences') + ); }); - it('should activate when logger is in DEBUG mode', function () { + it('should activate when logger is in DEBUG mode', function() { bucketStub.returns('111129'); var instance = new Optimizely({ datafile: testData.getTestProjectConfig(), @@ -733,60 +822,74 @@ describe('lib/optimizely', function () { sinon.assert.calledOnce(eventDispatcher.dispatchEvent); }); - describe('whitelisting', function () { - beforeEach(function () { + describe('whitelisting', function() { + beforeEach(function() { sinon.spy(Optimizely.prototype, '__validateInputs'); }); - afterEach(function () { + afterEach(function() { Optimizely.prototype.__validateInputs.restore(); }); - it('should return forced variation after experiment status check and before audience check', function () { + it('should return forced variation after experiment status check and before audience check', function() { var activate = optlyInstance.activate('testExperiment', 'user1'); assert.strictEqual(activate, 'control'); sinon.assert.calledTwice(Optimizely.prototype.__validateInputs); var logMessage0 = createdLogger.log.args[0][1]; - assert.strictEqual(logMessage0, sprintf(LOG_MESSAGES.USER_HAS_NO_FORCED_VARIATION, 'DECISION_SERVICE', 'user1')); + assert.strictEqual( + logMessage0, + sprintf(LOG_MESSAGES.USER_HAS_NO_FORCED_VARIATION, 'DECISION_SERVICE', 'user1') + ); var logMessage1 = createdLogger.log.args[1][1]; - assert.strictEqual(logMessage1, sprintf(LOG_MESSAGES.USER_FORCED_IN_VARIATION, 'DECISION_SERVICE', 'user1', 'control')); + assert.strictEqual( + logMessage1, + sprintf(LOG_MESSAGES.USER_FORCED_IN_VARIATION, 'DECISION_SERVICE', 'user1', 'control') + ); var expectedObj = { url: 'https://logx.optimizely.com/v1/events', httpVerb: 'POST', params: { - 'account_id': '12001', - 'project_id': '111001', - 'visitors': [{ - 'snapshots': [{ - 'decisions': [{ - 'campaign_id': '4', - 'experiment_id': '111127', - 'variation_id': '111128' - }], - 'events': [{ - 'entity_id': '4', - 'timestamp': Math.round(new Date().getTime()), - 'key': 'campaign_activated', - 'uuid': 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c' - }] - }], - 'visitor_id': 'user1', - 'attributes': [], - }], - 'revision': '42', - 'client_name': 'node-sdk', - 'client_version': enums.NODE_CLIENT_VERSION, - 'anonymize_ip': false, - 'enrich_decisions': true, + account_id: '12001', + project_id: '111001', + visitors: [ + { + snapshots: [ + { + decisions: [ + { + campaign_id: '4', + experiment_id: '111127', + variation_id: '111128', + }, + ], + events: [ + { + entity_id: '4', + timestamp: Math.round(new Date().getTime()), + key: 'campaign_activated', + uuid: 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c', + }, + ], + }, + ], + visitor_id: 'user1', + attributes: [], + }, + ], + revision: '42', + client_name: 'node-sdk', + client_version: enums.NODE_CLIENT_VERSION, + anonymize_ip: false, + enrich_decisions: true, }, }; }); }); - it('should not activate when optimizely object is not a valid instance', function () { + it('should not activate when optimizely object is not a valid instance', function() { var instance = new Optimizely({ datafile: {}, errorHandler: errorHandler, @@ -806,8 +909,8 @@ describe('lib/optimizely', function () { }); }); - describe('#track', function () { - it('should dispatch an event when no attributes are provided and the event\'s experiment is untargeted', function () { + describe('#track', function() { + it("should dispatch an event when no attributes are provided and the event's experiment is untargeted", function() { optlyInstance.track('testEvent', 'testUser'); sinon.assert.calledOnce(eventDispatcher.dispatchEvent); @@ -816,168 +919,201 @@ describe('lib/optimizely', function () { url: 'https://logx.optimizely.com/v1/events', httpVerb: 'POST', params: { - 'account_id': '12001', - 'project_id': '111001', - 'visitors': [{ - 'snapshots': [{ - 'events': [{ - 'entity_id': '111095', - 'timestamp': Math.round(new Date().getTime()), - 'uuid': 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c', - 'key': 'testEvent' - }] - }], - 'visitor_id': 'testUser', - 'attributes': [], - }], - 'revision': '42', - 'client_name': 'node-sdk', - 'client_version': enums.NODE_CLIENT_VERSION, - 'anonymize_ip': false, - 'enrich_decisions': true, + account_id: '12001', + project_id: '111001', + visitors: [ + { + snapshots: [ + { + events: [ + { + entity_id: '111095', + timestamp: Math.round(new Date().getTime()), + uuid: 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c', + key: 'testEvent', + }, + ], + }, + ], + visitor_id: 'testUser', + attributes: [], + }, + ], + revision: '42', + client_name: 'node-sdk', + client_version: enums.NODE_CLIENT_VERSION, + anonymize_ip: false, + enrich_decisions: true, }, }; var eventDispatcherCall = eventDispatcher.dispatchEvent.args[0]; assert.deepEqual(eventDispatcherCall[0], expectedObj); }); - it('should dispatch an event when empty attributes are provided and the event\'s experiment is untargeted', function () { + it("should dispatch an event when empty attributes are provided and the event's experiment is untargeted", function() { optlyInstance.track('testEvent', 'testUser', {}); sinon.assert.calledOnce(eventDispatcher.dispatchEvent); var expectedObj = { url: 'https://logx.optimizely.com/v1/events', httpVerb: 'POST', params: { - 'account_id': '12001', - 'project_id': '111001', - 'visitors': [{ - 'snapshots': [{ - 'events': [{ - 'entity_id': '111095', - 'timestamp': Math.round(new Date().getTime()), - 'uuid': 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c', - 'key': 'testEvent' - }] - }], - 'visitor_id': 'testUser', - 'attributes': [], - }], - 'revision': '42', - 'client_name': 'node-sdk', - 'client_version': enums.NODE_CLIENT_VERSION, - 'anonymize_ip': false, - 'enrich_decisions': true, + account_id: '12001', + project_id: '111001', + visitors: [ + { + snapshots: [ + { + events: [ + { + entity_id: '111095', + timestamp: Math.round(new Date().getTime()), + uuid: 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c', + key: 'testEvent', + }, + ], + }, + ], + visitor_id: 'testUser', + attributes: [], + }, + ], + revision: '42', + client_name: 'node-sdk', + client_version: enums.NODE_CLIENT_VERSION, + anonymize_ip: false, + enrich_decisions: true, }, }; var eventDispatcherCall = eventDispatcher.dispatchEvent.args[0]; assert.deepEqual(eventDispatcherCall[0], expectedObj); }); - it('should dispatch an event when attributes are provided and the event\'s experiment is untargeted', function () { + it("should dispatch an event when attributes are provided and the event's experiment is untargeted", function() { optlyInstance.track('testEvent', 'testUser', { browser_type: 'safari' }); sinon.assert.calledOnce(eventDispatcher.dispatchEvent); var expectedObj = { url: 'https://logx.optimizely.com/v1/events', httpVerb: 'POST', params: { - 'account_id': '12001', - 'project_id': '111001', - 'visitors': [{ - 'snapshots': [{ - 'events': [{ - 'entity_id': '111095', - 'timestamp': Math.round(new Date().getTime()), - 'uuid': 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c', - 'key': 'testEvent' - }] - }], - 'visitor_id': 'testUser', - 'attributes': [ - { - 'entity_id': '111094', - 'key': 'browser_type', - 'type': 'custom', - 'value': 'safari', - }, - ], - }], - 'revision': '42', - 'client_name': 'node-sdk', - 'client_version': enums.NODE_CLIENT_VERSION, - 'anonymize_ip': false, - 'enrich_decisions': true, + account_id: '12001', + project_id: '111001', + visitors: [ + { + snapshots: [ + { + events: [ + { + entity_id: '111095', + timestamp: Math.round(new Date().getTime()), + uuid: 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c', + key: 'testEvent', + }, + ], + }, + ], + visitor_id: 'testUser', + attributes: [ + { + entity_id: '111094', + key: 'browser_type', + type: 'custom', + value: 'safari', + }, + ], + }, + ], + revision: '42', + client_name: 'node-sdk', + client_version: enums.NODE_CLIENT_VERSION, + anonymize_ip: false, + enrich_decisions: true, }, }; var eventDispatcherCall = eventDispatcher.dispatchEvent.args[0]; assert.deepEqual(eventDispatcherCall[0], expectedObj); }); - it('should dispatch an event when no attributes are provided and the event\'s experiment is targeted', function () { + it("should dispatch an event when no attributes are provided and the event's experiment is targeted", function() { optlyInstance.track('testEventWithAudiences', 'testUser'); sinon.assert.calledOnce(eventDispatcher.dispatchEvent); var expectedObj = { url: 'https://logx.optimizely.com/v1/events', httpVerb: 'POST', params: { - 'account_id': '12001', - 'project_id': '111001', - 'visitors': [{ - 'snapshots': [{ - 'events': [{ - 'entity_id': '111097', - 'timestamp': Math.round(new Date().getTime()), - 'uuid': 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c', - 'key': 'testEventWithAudiences' - }] - }], - 'visitor_id': 'testUser', - 'attributes': [], - }], - 'revision': '42', - 'client_name': 'node-sdk', - 'client_version': enums.NODE_CLIENT_VERSION, - 'anonymize_ip': false, - 'enrich_decisions': true, + account_id: '12001', + project_id: '111001', + visitors: [ + { + snapshots: [ + { + events: [ + { + entity_id: '111097', + timestamp: Math.round(new Date().getTime()), + uuid: 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c', + key: 'testEventWithAudiences', + }, + ], + }, + ], + visitor_id: 'testUser', + attributes: [], + }, + ], + revision: '42', + client_name: 'node-sdk', + client_version: enums.NODE_CLIENT_VERSION, + anonymize_ip: false, + enrich_decisions: true, }, }; var eventDispatcherCall = eventDispatcher.dispatchEvent.args[0]; assert.deepEqual(eventDispatcherCall[0], expectedObj); }); - it('should dispatch an event when empty attributes are provided and the event\'s experiment is targeted', function () { + it("should dispatch an event when empty attributes are provided and the event's experiment is targeted", function() { optlyInstance.track('testEventWithAudiences', 'testUser'); sinon.assert.calledOnce(eventDispatcher.dispatchEvent); var expectedObj = { url: 'https://logx.optimizely.com/v1/events', httpVerb: 'POST', params: { - 'account_id': '12001', - 'project_id': '111001', - 'visitors': [{ - 'snapshots': [{ - 'events': [{ - 'entity_id': '111097', - 'timestamp': Math.round(new Date().getTime()), - 'uuid': 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c', - 'key': 'testEventWithAudiences' - }] - }], - 'visitor_id': 'testUser', - 'attributes': [], - }], - 'revision': '42', - 'client_name': 'node-sdk', - 'client_version': enums.NODE_CLIENT_VERSION, - 'anonymize_ip': false, - 'enrich_decisions': true, + account_id: '12001', + project_id: '111001', + visitors: [ + { + snapshots: [ + { + events: [ + { + entity_id: '111097', + timestamp: Math.round(new Date().getTime()), + uuid: 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c', + key: 'testEventWithAudiences', + }, + ], + }, + ], + visitor_id: 'testUser', + attributes: [], + }, + ], + revision: '42', + client_name: 'node-sdk', + client_version: enums.NODE_CLIENT_VERSION, + anonymize_ip: false, + enrich_decisions: true, }, }; var eventDispatcherCall = eventDispatcher.dispatchEvent.args[0]; assert.deepEqual(eventDispatcherCall[0], expectedObj); }); - it('should call dispatchEvent with proper args when including null value attributes', function () { - optlyInstance.track('testEventWithAudiences', 'testUser', { browser_type: 'firefox', 'test_null_attribute': null }); + it('should call dispatchEvent with proper args when including null value attributes', function() { + optlyInstance.track('testEventWithAudiences', 'testUser', { + browser_type: 'firefox', + test_null_attribute: null, + }); sinon.assert.calledOnce(eventDispatcher.dispatchEvent); @@ -985,37 +1121,45 @@ describe('lib/optimizely', function () { url: 'https://logx.optimizely.com/v1/events', httpVerb: 'POST', params: { - 'account_id': '12001', - 'project_id': '111001', - 'visitors': [{ - 'snapshots': [{ - 'events': [{ - 'entity_id': '111097', - 'timestamp': Math.round(new Date().getTime()), - 'uuid': 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c', - 'key': 'testEventWithAudiences' - }] - }], - 'visitor_id': 'testUser', - 'attributes': [{ - 'entity_id': '111094', - 'key': 'browser_type', - 'type': 'custom', - 'value': 'firefox' - }], - }], - 'revision': '42', - 'client_name': 'node-sdk', - 'client_version': enums.NODE_CLIENT_VERSION, - 'anonymize_ip': false, - 'enrich_decisions': true, + account_id: '12001', + project_id: '111001', + visitors: [ + { + snapshots: [ + { + events: [ + { + entity_id: '111097', + timestamp: Math.round(new Date().getTime()), + uuid: 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c', + key: 'testEventWithAudiences', + }, + ], + }, + ], + visitor_id: 'testUser', + attributes: [ + { + entity_id: '111094', + key: 'browser_type', + type: 'custom', + value: 'firefox', + }, + ], + }, + ], + revision: '42', + client_name: 'node-sdk', + client_version: enums.NODE_CLIENT_VERSION, + anonymize_ip: false, + enrich_decisions: true, }, }; var eventDispatcherCall = eventDispatcher.dispatchEvent.args[0]; assert.deepEqual(eventDispatcherCall[0], expectedObj); }); - it('should call dispatchEvent with proper args when including attributes', function () { + it('should call dispatchEvent with proper args when including attributes', function() { optlyInstance.track('testEventWithAudiences', 'testUser', { browser_type: 'firefox' }); sinon.assert.calledOnce(eventDispatcher.dispatchEvent); @@ -1024,37 +1168,45 @@ describe('lib/optimizely', function () { url: 'https://logx.optimizely.com/v1/events', httpVerb: 'POST', params: { - 'account_id': '12001', - 'project_id': '111001', - 'visitors': [{ - 'snapshots': [{ - 'events': [{ - 'entity_id': '111097', - 'timestamp': Math.round(new Date().getTime()), - 'uuid': 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c', - 'key': 'testEventWithAudiences' - }] - }], - 'visitor_id': 'testUser', - 'attributes': [{ - 'entity_id': '111094', - 'key': 'browser_type', - 'type': 'custom', - 'value': 'firefox' - }], - }], - 'revision': '42', - 'client_name': 'node-sdk', - 'client_version': enums.NODE_CLIENT_VERSION, - 'anonymize_ip': false, - 'enrich_decisions': true, + account_id: '12001', + project_id: '111001', + visitors: [ + { + snapshots: [ + { + events: [ + { + entity_id: '111097', + timestamp: Math.round(new Date().getTime()), + uuid: 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c', + key: 'testEventWithAudiences', + }, + ], + }, + ], + visitor_id: 'testUser', + attributes: [ + { + entity_id: '111094', + key: 'browser_type', + type: 'custom', + value: 'firefox', + }, + ], + }, + ], + revision: '42', + client_name: 'node-sdk', + client_version: enums.NODE_CLIENT_VERSION, + anonymize_ip: false, + enrich_decisions: true, }, }; var eventDispatcherCall = eventDispatcher.dispatchEvent.args[0]; assert.deepEqual(eventDispatcherCall[0], expectedObj); }); - it('should call bucketer and dispatchEvent with proper args when including event tags', function () { + it('should call bucketer and dispatchEvent with proper args when including event tags', function() { optlyInstance.track('testEvent', 'testUser', undefined, { eventTag: 'chill' }); sinon.assert.calledOnce(eventDispatcher.dispatchEvent); @@ -1063,35 +1215,41 @@ describe('lib/optimizely', function () { url: 'https://logx.optimizely.com/v1/events', httpVerb: 'POST', params: { - 'account_id': '12001', - 'project_id': '111001', - 'visitors': [{ - 'snapshots': [{ - 'events': [{ - 'entity_id': '111095', - 'timestamp': Math.round(new Date().getTime()), - 'uuid': 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c', - 'key': 'testEvent', - 'tags': { - 'eventTag': 'chill' - } - }] - }], - 'visitor_id': 'testUser', - 'attributes': [], - }], - 'revision': '42', - 'client_name': 'node-sdk', - 'client_version': enums.NODE_CLIENT_VERSION, - 'anonymize_ip': false, - 'enrich_decisions': true, + account_id: '12001', + project_id: '111001', + visitors: [ + { + snapshots: [ + { + events: [ + { + entity_id: '111095', + timestamp: Math.round(new Date().getTime()), + uuid: 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c', + key: 'testEvent', + tags: { + eventTag: 'chill', + }, + }, + ], + }, + ], + visitor_id: 'testUser', + attributes: [], + }, + ], + revision: '42', + client_name: 'node-sdk', + client_version: enums.NODE_CLIENT_VERSION, + anonymize_ip: false, + enrich_decisions: true, }, }; var eventDispatcherCall = eventDispatcher.dispatchEvent.args[0]; assert.deepEqual(eventDispatcherCall[0], expectedObj); }); - it('should call dispatchEvent with proper args when including event tags and revenue', function () { + it('should call dispatchEvent with proper args when including event tags and revenue', function() { optlyInstance.track('testEvent', 'testUser', undefined, { revenue: 4200, eventTag: 'chill' }); sinon.assert.calledOnce(eventDispatcher.dispatchEvent); @@ -1100,38 +1258,48 @@ describe('lib/optimizely', function () { url: 'https://logx.optimizely.com/v1/events', httpVerb: 'POST', params: { - 'account_id': '12001', - 'project_id': '111001', - 'visitors': [{ - 'snapshots': [{ - 'events': [{ - 'entity_id': '111095', - 'timestamp': Math.round(new Date().getTime()), - 'uuid': 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c', - 'key': 'testEvent', - 'revenue': 4200, - 'tags': { - 'revenue': 4200, - 'eventTag': 'chill' - } - }] - }], - 'visitor_id': 'testUser', - 'attributes': [], - }], - 'revision': '42', - 'client_name': 'node-sdk', - 'client_version': enums.NODE_CLIENT_VERSION, - 'anonymize_ip': false, - 'enrich_decisions': true, + account_id: '12001', + project_id: '111001', + visitors: [ + { + snapshots: [ + { + events: [ + { + entity_id: '111095', + timestamp: Math.round(new Date().getTime()), + uuid: 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c', + key: 'testEvent', + revenue: 4200, + tags: { + revenue: 4200, + eventTag: 'chill', + }, + }, + ], + }, + ], + visitor_id: 'testUser', + attributes: [], + }, + ], + revision: '42', + client_name: 'node-sdk', + client_version: enums.NODE_CLIENT_VERSION, + anonymize_ip: false, + enrich_decisions: true, }, }; var eventDispatcherCall = eventDispatcher.dispatchEvent.args[0]; assert.deepEqual(eventDispatcherCall[0], expectedObj); }); - it('should call dispatchEvent with proper args when including event tags and null event tag values and revenue', function () { - optlyInstance.track('testEvent', 'testUser', undefined, { revenue: 4200, eventTag: 'chill', 'testNullEventTag': null }); + it('should call dispatchEvent with proper args when including event tags and null event tag values and revenue', function() { + optlyInstance.track('testEvent', 'testUser', undefined, { + revenue: 4200, + eventTag: 'chill', + testNullEventTag: null, + }); sinon.assert.calledOnce(eventDispatcher.dispatchEvent); @@ -1139,182 +1307,216 @@ describe('lib/optimizely', function () { url: 'https://logx.optimizely.com/v1/events', httpVerb: 'POST', params: { - 'account_id': '12001', - 'project_id': '111001', - 'visitors': [{ - 'snapshots': [{ - 'events': [{ - 'entity_id': '111095', - 'timestamp': Math.round(new Date().getTime()), - 'uuid': 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c', - 'key': 'testEvent', - 'revenue': 4200, - 'tags': { - 'revenue': 4200, - 'eventTag': 'chill' - } - }] - }], - 'visitor_id': 'testUser', - 'attributes': [], - }], - 'revision': '42', - 'client_name': 'node-sdk', - 'client_version': enums.NODE_CLIENT_VERSION, - 'anonymize_ip': false, - 'enrich_decisions': true, + account_id: '12001', + project_id: '111001', + visitors: [ + { + snapshots: [ + { + events: [ + { + entity_id: '111095', + timestamp: Math.round(new Date().getTime()), + uuid: 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c', + key: 'testEvent', + revenue: 4200, + tags: { + revenue: 4200, + eventTag: 'chill', + }, + }, + ], + }, + ], + visitor_id: 'testUser', + attributes: [], + }, + ], + revision: '42', + client_name: 'node-sdk', + client_version: enums.NODE_CLIENT_VERSION, + anonymize_ip: false, + enrich_decisions: true, }, }; var eventDispatcherCall = eventDispatcher.dispatchEvent.args[0]; assert.deepEqual(eventDispatcherCall[0], expectedObj); }); - it('should not call dispatchEvent when including invalid event value', function () { + it('should not call dispatchEvent when including invalid event value', function() { optlyInstance.track('testEvent', 'testUser', undefined, '4200'); sinon.assert.notCalled(eventDispatcher.dispatchEvent); sinon.assert.calledOnce(createdLogger.log); }); - it('should track a user for an experiment not running', function () { + it('should track a user for an experiment not running', function() { optlyInstance.track('testEventWithExperimentNotRunning', 'testUser'); sinon.assert.calledOnce(eventDispatcher.dispatchEvent); var expectedObj = { url: 'https://logx.optimizely.com/v1/events', httpVerb: 'POST', params: { - 'account_id': '12001', - 'project_id': '111001', - 'visitors': [{ - 'snapshots': [{ - 'events': [{ - 'entity_id': '111099', - 'timestamp': Math.round(new Date().getTime()), - 'uuid': 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c', - 'key': 'testEventWithExperimentNotRunning', - }] - }], - 'visitor_id': 'testUser', - 'attributes': [], - }], - 'revision': '42', - 'client_name': 'node-sdk', - 'client_version': enums.NODE_CLIENT_VERSION, - 'anonymize_ip': false, - 'enrich_decisions': true, + account_id: '12001', + project_id: '111001', + visitors: [ + { + snapshots: [ + { + events: [ + { + entity_id: '111099', + timestamp: Math.round(new Date().getTime()), + uuid: 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c', + key: 'testEventWithExperimentNotRunning', + }, + ], + }, + ], + visitor_id: 'testUser', + attributes: [], + }, + ], + revision: '42', + client_name: 'node-sdk', + client_version: enums.NODE_CLIENT_VERSION, + anonymize_ip: false, + enrich_decisions: true, }, }; var eventDispatcherCall = eventDispatcher.dispatchEvent.args[0]; assert.deepEqual(eventDispatcherCall[0], expectedObj); }); - it('should track a user when user is not in the audience of the experiment', function () { + it('should track a user when user is not in the audience of the experiment', function() { optlyInstance.track('testEventWithAudiences', 'testUser', { browser_type: 'chrome' }); sinon.assert.calledOnce(eventDispatcher.dispatchEvent); var expectedObj = { url: 'https://logx.optimizely.com/v1/events', httpVerb: 'POST', params: { - 'account_id': '12001', - 'project_id': '111001', - 'visitors': [{ - 'snapshots': [{ - 'events': [{ - 'entity_id': '111097', - 'timestamp': Math.round(new Date().getTime()), - 'uuid': 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c', - 'key': 'testEventWithAudiences', - }] - }], - 'visitor_id': 'testUser', - 'attributes': [{ - 'entity_id': '111094', - 'key': 'browser_type', - 'type': 'custom', - 'value': 'chrome' - }], - }], - 'revision': '42', - 'client_name': 'node-sdk', - 'client_version': enums.NODE_CLIENT_VERSION, - 'anonymize_ip': false, - 'enrich_decisions': true, + account_id: '12001', + project_id: '111001', + visitors: [ + { + snapshots: [ + { + events: [ + { + entity_id: '111097', + timestamp: Math.round(new Date().getTime()), + uuid: 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c', + key: 'testEventWithAudiences', + }, + ], + }, + ], + visitor_id: 'testUser', + attributes: [ + { + entity_id: '111094', + key: 'browser_type', + type: 'custom', + value: 'chrome', + }, + ], + }, + ], + revision: '42', + client_name: 'node-sdk', + client_version: enums.NODE_CLIENT_VERSION, + anonymize_ip: false, + enrich_decisions: true, }, }; var eventDispatcherCall = eventDispatcher.dispatchEvent.args[0]; assert.deepEqual(eventDispatcherCall[0], expectedObj); }); - it('should track a user when the event has no associated experiments', function () { + it('should track a user when the event has no associated experiments', function() { optlyInstance.track('testEventWithoutExperiments', 'testUser'); sinon.assert.calledOnce(eventDispatcher.dispatchEvent); var expectedObj = { url: 'https://logx.optimizely.com/v1/events', httpVerb: 'POST', params: { - 'account_id': '12001', - 'project_id': '111001', - 'visitors': [{ - 'snapshots': [{ - 'events': [{ - 'entity_id': '111098', - 'timestamp': Math.round(new Date().getTime()), - 'uuid': 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c', - 'key': 'testEventWithoutExperiments', - }] - }], - 'visitor_id': 'testUser', - 'attributes': [], - }], - 'revision': '42', - 'client_name': 'node-sdk', - 'client_version': enums.NODE_CLIENT_VERSION, - 'anonymize_ip': false, - 'enrich_decisions': true, + account_id: '12001', + project_id: '111001', + visitors: [ + { + snapshots: [ + { + events: [ + { + entity_id: '111098', + timestamp: Math.round(new Date().getTime()), + uuid: 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c', + key: 'testEventWithoutExperiments', + }, + ], + }, + ], + visitor_id: 'testUser', + attributes: [], + }, + ], + revision: '42', + client_name: 'node-sdk', + client_version: enums.NODE_CLIENT_VERSION, + anonymize_ip: false, + enrich_decisions: true, }, }; var eventDispatcherCall = eventDispatcher.dispatchEvent.args[0]; assert.deepEqual(eventDispatcherCall[0], expectedObj); }); - it('should only send one conversion event when the event is attached to multiple experiments', function () { + it('should only send one conversion event when the event is attached to multiple experiments', function() { optlyInstance.track('testEventWithMultipleExperiments', 'testUser', { browser_type: 'firefox' }); sinon.assert.calledOnce(eventDispatcher.dispatchEvent); var expectedObj = { url: 'https://logx.optimizely.com/v1/events', httpVerb: 'POST', params: { - 'account_id': '12001', - 'project_id': '111001', - 'visitors': [{ - 'snapshots': [{ - 'events': [{ - 'entity_id': '111100', - 'timestamp': Math.round(new Date().getTime()), - 'uuid': 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c', - 'key': 'testEventWithMultipleExperiments', - }] - }], - 'visitor_id': 'testUser', - 'attributes': [{ - 'entity_id': '111094', - 'key': 'browser_type', - 'type': 'custom', - 'value': 'firefox' - }], - }], - 'revision': '42', - 'client_name': 'node-sdk', - 'client_version': enums.NODE_CLIENT_VERSION, - 'anonymize_ip': false, - 'enrich_decisions': true, + account_id: '12001', + project_id: '111001', + visitors: [ + { + snapshots: [ + { + events: [ + { + entity_id: '111100', + timestamp: Math.round(new Date().getTime()), + uuid: 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c', + key: 'testEventWithMultipleExperiments', + }, + ], + }, + ], + visitor_id: 'testUser', + attributes: [ + { + entity_id: '111094', + key: 'browser_type', + type: 'custom', + value: 'firefox', + }, + ], + }, + ], + revision: '42', + client_name: 'node-sdk', + client_version: enums.NODE_CLIENT_VERSION, + anonymize_ip: false, + enrich_decisions: true, }, }; var eventDispatcherCall = eventDispatcher.dispatchEvent.args[0]; assert.deepEqual(eventDispatcherCall[0], expectedObj); }); - it('should throw an error for invalid user ID', function () { + it('should throw an error for invalid user ID', function() { optlyInstance.track('testEvent', null); sinon.assert.notCalled(eventDispatcher.dispatchEvent); @@ -1328,7 +1530,7 @@ describe('lib/optimizely', function () { assert.strictEqual(logMessage, sprintf(ERROR_MESSAGES.INVALID_INPUT_FORMAT, 'OPTIMIZELY', 'user_id')); }); - it('should throw an error for invalid event key', function () { + it('should throw an error for invalid event key', function() { optlyInstance.track('invalidEventKey', 'testUser'); sinon.assert.notCalled(eventDispatcher.dispatchEvent); @@ -1345,7 +1547,7 @@ describe('lib/optimizely', function () { assert.strictEqual(logMessage2, sprintf(LOG_MESSAGES.NOT_TRACKING_USER, 'OPTIMIZELY', 'testUser')); }); - it('should throw an error for invalid attributes', function () { + it('should throw an error for invalid attributes', function() { optlyInstance.track('testEvent', 'testUser', []); sinon.assert.notCalled(eventDispatcher.dispatchEvent); @@ -1359,12 +1561,12 @@ describe('lib/optimizely', function () { assert.strictEqual(logMessage, sprintf(ERROR_MESSAGES.INVALID_ATTRIBUTES, 'ATTRIBUTES_VALIDATOR')); }); - it('should not throw an error for an event key without associated experiment IDs', function () { + it('should not throw an error for an event key without associated experiment IDs', function() { optlyInstance.track('testEventWithoutExperiments', 'testUser'); sinon.assert.notCalled(errorHandler.handleError); }); - it('should track when logger is in DEBUG mode', function () { + it('should track when logger is in DEBUG mode', function() { var instance = new Optimizely({ datafile: testData.getTestProjectConfig(), errorHandler: errorHandler, @@ -1382,7 +1584,7 @@ describe('lib/optimizely', function () { sinon.assert.calledOnce(eventDispatcher.dispatchEvent); }); - it('should not track when optimizely object is not a valid instance', function () { + it('should not track when optimizely object is not a valid instance', function() { var instance = new Optimizely({ datafile: {}, errorHandler: errorHandler, @@ -1402,8 +1604,8 @@ describe('lib/optimizely', function () { }); }); - describe('#getVariation', function () { - it('should call bucketer and return variation key', function () { + describe('#getVariation', function() { + it('should call bucketer and return variation key', function() { bucketStub.returns('111129'); var variation = optlyInstance.getVariation('testExperiment', 'testUser'); @@ -1419,11 +1621,11 @@ describe('lib/optimizely', function () { ); }); - it('should call bucketer and return variation key with attributes', function () { + it('should call bucketer and return variation key with attributes', function() { bucketStub.returns('122229'); - var getVariation = optlyInstance.getVariation('testExperimentWithAudiences', - 'testUser', - { browser_type: 'firefox' }); + var getVariation = optlyInstance.getVariation('testExperimentWithAudiences', 'testUser', { + browser_type: 'firefox', + }); assert.strictEqual(getVariation, 'variationWithAudience'); @@ -1431,7 +1633,7 @@ describe('lib/optimizely', function () { sinon.assert.called(createdLogger.log); }); - it('should return null if user is not in audience or experiment is not running', function () { + it('should return null if user is not in audience or experiment is not running', function() { var getVariationReturnsNull1 = optlyInstance.getVariation('testExperimentWithAudiences', 'testUser', {}); var getVariationReturnsNull2 = optlyInstance.getVariation('testExperimentNotRunning', 'testUser'); @@ -1460,7 +1662,7 @@ describe('lib/optimizely', function () { ); }); - it('should throw an error for invalid user ID', function () { + it('should throw an error for invalid user ID', function() { var getVariationWithError = optlyInstance.getVariation('testExperiment', null); assert.isNull(getVariationWithError); @@ -1474,16 +1676,19 @@ describe('lib/optimizely', function () { assert.strictEqual(logMessage, sprintf(ERROR_MESSAGES.INVALID_INPUT_FORMAT, 'OPTIMIZELY', 'user_id')); }); - it('should log an error for invalid experiment key', function () { + it('should log an error for invalid experiment key', function() { var getVariationWithError = optlyInstance.getVariation('invalidExperimentKey', 'testUser'); assert.isNull(getVariationWithError); sinon.assert.calledOnce(createdLogger.log); var logMessage = createdLogger.log.args[0][1]; - assert.strictEqual(logMessage, sprintf(ERROR_MESSAGES.INVALID_EXPERIMENT_KEY, 'OPTIMIZELY', 'invalidExperimentKey')); + assert.strictEqual( + logMessage, + sprintf(ERROR_MESSAGES.INVALID_EXPERIMENT_KEY, 'OPTIMIZELY', 'invalidExperimentKey') + ); }); - it('should throw an error for invalid attributes', function () { + it('should throw an error for invalid attributes', function() { var getVariationWithError = optlyInstance.getVariation('testExperimentWithAudiences', 'testUser', []); assert.isNull(getVariationWithError); @@ -1497,16 +1702,16 @@ describe('lib/optimizely', function () { assert.strictEqual(logMessage, sprintf(ERROR_MESSAGES.INVALID_ATTRIBUTES, 'ATTRIBUTES_VALIDATOR')); }); - describe('whitelisting', function () { - beforeEach(function () { + describe('whitelisting', function() { + beforeEach(function() { sinon.spy(Optimizely.prototype, '__validateInputs'); }); - afterEach(function () { + afterEach(function() { Optimizely.prototype.__validateInputs.restore(); }); - it('should return forced variation after experiment status check and before audience check', function () { + it('should return forced variation after experiment status check and before audience check', function() { var getVariation = optlyInstance.getVariation('testExperiment', 'user1'); assert.strictEqual(getVariation, 'control'); @@ -1515,13 +1720,19 @@ describe('lib/optimizely', function () { sinon.assert.calledTwice(createdLogger.log); var logMessage0 = createdLogger.log.args[0][1]; - assert.strictEqual(logMessage0, sprintf(LOG_MESSAGES.USER_HAS_NO_FORCED_VARIATION, 'DECISION_SERVICE', 'user1')); + assert.strictEqual( + logMessage0, + sprintf(LOG_MESSAGES.USER_HAS_NO_FORCED_VARIATION, 'DECISION_SERVICE', 'user1') + ); var logMessage = createdLogger.log.args[1][1]; - assert.strictEqual(logMessage, sprintf(LOG_MESSAGES.USER_FORCED_IN_VARIATION, 'DECISION_SERVICE', 'user1', 'control')); + assert.strictEqual( + logMessage, + sprintf(LOG_MESSAGES.USER_FORCED_IN_VARIATION, 'DECISION_SERVICE', 'user1', 'control') + ); }); }); - it('should not return variation when optimizely object is not a valid instance', function () { + it('should not return variation when optimizely object is not a valid instance', function() { var instance = new Optimizely({ datafile: {}, errorHandler: errorHandler, @@ -1540,8 +1751,8 @@ describe('lib/optimizely', function () { sinon.assert.notCalled(eventDispatcher.dispatchEvent); }); - describe('order of bucketing operations', function () { - it('should properly follow the order of bucketing operations', function () { + describe('order of bucketing operations', function() { + it('should properly follow the order of bucketing operations', function() { // Order of operations is preconditions > experiment is running > whitelisting > audience eval > variation bucketing bucketStub.returns('122228'); // returns the control variation @@ -1555,21 +1766,30 @@ describe('lib/optimizely', function () { assert.isNull(optlyInstance.activate('testExperimentWithAudiences', 'user3')); // valid user, experiment running, not whitelisted, meets audience conditions - assert.strictEqual(optlyInstance.activate('testExperimentWithAudiences', 'user3', { browser_type: 'firefox' }), 'controlWithAudience'); + assert.strictEqual( + optlyInstance.activate('testExperimentWithAudiences', 'user3', { browser_type: 'firefox' }), + 'controlWithAudience' + ); // valid user, running experiment, whitelisted, does not meet audience conditions // expect user to be forced into `variationWithAudience` through whitelisting - assert.strictEqual(optlyInstance.activate('testExperimentWithAudiences', 'user2', { browser_type: 'chrome' }), 'variationWithAudience'); + assert.strictEqual( + optlyInstance.activate('testExperimentWithAudiences', 'user2', { browser_type: 'chrome' }), + 'variationWithAudience' + ); // valid user, running experiment, whitelisted, meets audience conditions // expect user to be forced into `variationWithAudience (122229)` through whitelisting - assert.strictEqual(optlyInstance.activate('testExperimentWithAudiences', 'user2', { browser_type: 'firefox' }), 'variationWithAudience'); + assert.strictEqual( + optlyInstance.activate('testExperimentWithAudiences', 'user2', { browser_type: 'firefox' }), + 'variationWithAudience' + ); }); }); }); - describe('#getForcedVariation', function () { - it('should return null when set has not been called', function () { + describe('#getForcedVariation', function() { + it('should return null when set has not been called', function() { var forcedVariation = optlyInstance.getForcedVariation('testExperiment', 'user1'); assert.strictEqual(forcedVariation, null); @@ -1577,7 +1797,7 @@ describe('lib/optimizely', function () { assert.strictEqual(logMessage, sprintf(LOG_MESSAGES.USER_HAS_NO_FORCED_VARIATION, 'DECISION_SERVICE', 'user1')); }); - it('should return null with a null experimentKey', function () { + it('should return null with a null experimentKey', function() { var forcedVariation = optlyInstance.getForcedVariation(null, 'user1'); assert.strictEqual(forcedVariation, null); @@ -1585,7 +1805,7 @@ describe('lib/optimizely', function () { assert.strictEqual(logMessage, sprintf(ERROR_MESSAGES.INVALID_INPUT_FORMAT, 'OPTIMIZELY', 'experiment_key')); }); - it('should return null with an undefined experimentKey', function () { + it('should return null with an undefined experimentKey', function() { var forcedVariation = optlyInstance.getForcedVariation(undefined, 'user1'); assert.strictEqual(forcedVariation, null); @@ -1593,7 +1813,7 @@ describe('lib/optimizely', function () { assert.strictEqual(logMessage, sprintf(ERROR_MESSAGES.INVALID_INPUT_FORMAT, 'OPTIMIZELY', 'experiment_key')); }); - it('should return null with a null userId', function () { + it('should return null with a null userId', function() { var forcedVariation = optlyInstance.getForcedVariation('testExperiment', null); assert.strictEqual(forcedVariation, null); @@ -1601,7 +1821,7 @@ describe('lib/optimizely', function () { assert.strictEqual(logMessage, sprintf(ERROR_MESSAGES.INVALID_INPUT_FORMAT, 'OPTIMIZELY', 'user_id')); }); - it('should return null with an undefined userId', function () { + it('should return null with an undefined userId', function() { var forcedVariation = optlyInstance.getForcedVariation('testExperiment', undefined); assert.strictEqual(forcedVariation, null); @@ -1610,16 +1830,19 @@ describe('lib/optimizely', function () { }); }); - describe('#setForcedVariation', function () { - it('should be able to set a forced variation', function () { + describe('#setForcedVariation', function() { + it('should be able to set a forced variation', function() { var didSetVariation = optlyInstance.setForcedVariation('testExperiment', 'user1', 'control'); assert.strictEqual(didSetVariation, true); var logMessage = createdLogger.log.args[0][1]; - assert.strictEqual(logMessage, sprintf(LOG_MESSAGES.USER_MAPPED_TO_FORCED_VARIATION, 'DECISION_SERVICE', 111128, 111127, 'user1')); + assert.strictEqual( + logMessage, + sprintf(LOG_MESSAGES.USER_MAPPED_TO_FORCED_VARIATION, 'DECISION_SERVICE', 111128, 111127, 'user1') + ); }); - it('should override bucketing in optlyInstance.getVariation', function () { + it('should override bucketing in optlyInstance.getVariation', function() { var didSetVariation = optlyInstance.setForcedVariation('testExperiment', 'user1', 'control'); assert.strictEqual(didSetVariation, true); @@ -1627,7 +1850,7 @@ describe('lib/optimizely', function () { assert.strictEqual(variation, 'control'); }); - it('should be able to set and get forced variation', function () { + it('should be able to set and get forced variation', function() { var didSetVariation = optlyInstance.setForcedVariation('testExperiment', 'user1', 'control'); assert.strictEqual(didSetVariation, true); @@ -1635,7 +1858,7 @@ describe('lib/optimizely', function () { assert.strictEqual(forcedVariation, 'control'); }); - it('should be able to set, unset, and get forced variation', function () { + it('should be able to set, unset, and get forced variation', function() { var didSetVariation = optlyInstance.setForcedVariation('testExperiment', 'user1', 'control'); assert.strictEqual(didSetVariation, true); @@ -1652,14 +1875,23 @@ describe('lib/optimizely', function () { var variationIsMappedLogMessage = createdLogger.log.args[1][1]; var variationMappingRemovedLogMessage = createdLogger.log.args[2][1]; - assert.strictEqual(setVariationLogMessage, sprintf(LOG_MESSAGES.USER_MAPPED_TO_FORCED_VARIATION, 'DECISION_SERVICE', 111128, 111127, 'user1')); + assert.strictEqual( + setVariationLogMessage, + sprintf(LOG_MESSAGES.USER_MAPPED_TO_FORCED_VARIATION, 'DECISION_SERVICE', 111128, 111127, 'user1') + ); - assert.strictEqual(variationIsMappedLogMessage, sprintf(LOG_MESSAGES.USER_HAS_FORCED_VARIATION, 'DECISION_SERVICE', 'control', 'testExperiment', 'user1')); + assert.strictEqual( + variationIsMappedLogMessage, + sprintf(LOG_MESSAGES.USER_HAS_FORCED_VARIATION, 'DECISION_SERVICE', 'control', 'testExperiment', 'user1') + ); - assert.strictEqual(variationMappingRemovedLogMessage, sprintf(LOG_MESSAGES.VARIATION_REMOVED_FOR_USER, 'DECISION_SERVICE', 'testExperiment', 'user1')); + assert.strictEqual( + variationMappingRemovedLogMessage, + sprintf(LOG_MESSAGES.VARIATION_REMOVED_FOR_USER, 'DECISION_SERVICE', 'testExperiment', 'user1') + ); }); - it('should be able to set multiple experiments for one user', function () { + it('should be able to set multiple experiments for one user', function() { var didSetVariation = optlyInstance.setForcedVariation('testExperiment', 'user1', 'control'); assert.strictEqual(didSetVariation, true); @@ -1673,23 +1905,38 @@ describe('lib/optimizely', function () { assert.strictEqual(forcedVariation2, 'variationLaunched'); }); - it('should not set an invalid variation', function () { - var didSetVariation = optlyInstance.setForcedVariation('testExperiment', 'user1', 'definitely_not_valid_variation_key'); + it('should not set an invalid variation', function() { + var didSetVariation = optlyInstance.setForcedVariation( + 'testExperiment', + 'user1', + 'definitely_not_valid_variation_key' + ); assert.strictEqual(didSetVariation, false); var logMessage = createdLogger.log.args[0][1]; - assert.strictEqual(logMessage, sprintf(ERROR_MESSAGES.NO_VARIATION_FOR_EXPERIMENT_KEY, 'DECISION_SERVICE', 'definitely_not_valid_variation_key', 'testExperiment')); + assert.strictEqual( + logMessage, + sprintf( + ERROR_MESSAGES.NO_VARIATION_FOR_EXPERIMENT_KEY, + 'DECISION_SERVICE', + 'definitely_not_valid_variation_key', + 'testExperiment' + ) + ); }); - it('should not set an invalid experiment', function () { + it('should not set an invalid experiment', function() { var didSetVariation = optlyInstance.setForcedVariation('definitely_not_valid_exp_key', 'user1', 'control'); assert.strictEqual(didSetVariation, false); var logMessage = createdLogger.log.args[0][1]; - assert.strictEqual(logMessage, sprintf(ERROR_MESSAGES.EXPERIMENT_KEY_NOT_IN_DATAFILE, 'PROJECT_CONFIG', 'definitely_not_valid_exp_key')); + assert.strictEqual( + logMessage, + sprintf(ERROR_MESSAGES.EXPERIMENT_KEY_NOT_IN_DATAFILE, 'PROJECT_CONFIG', 'definitely_not_valid_exp_key') + ); }); - it('should return null for user has no forced variation for experiment', function () { + it('should return null for user has no forced variation for experiment', function() { var didSetVariation = optlyInstance.setForcedVariation('testExperiment', 'user1', 'control'); assert.strictEqual(didSetVariation, true); @@ -1697,97 +1944,139 @@ describe('lib/optimizely', function () { assert.strictEqual(forcedVariation, null); var setVariationLogMessage = createdLogger.log.args[0][1]; - assert.strictEqual(setVariationLogMessage, sprintf(LOG_MESSAGES.USER_MAPPED_TO_FORCED_VARIATION, 'DECISION_SERVICE', 111128, 111127, 'user1')); + assert.strictEqual( + setVariationLogMessage, + sprintf(LOG_MESSAGES.USER_MAPPED_TO_FORCED_VARIATION, 'DECISION_SERVICE', 111128, 111127, 'user1') + ); var noVariationToGetLogMessage = createdLogger.log.args[1][1]; - assert.strictEqual(noVariationToGetLogMessage, sprintf(LOG_MESSAGES.USER_HAS_NO_FORCED_VARIATION_FOR_EXPERIMENT, 'DECISION_SERVICE', 'testExperimentLaunched', 'user1')); + assert.strictEqual( + noVariationToGetLogMessage, + sprintf( + LOG_MESSAGES.USER_HAS_NO_FORCED_VARIATION_FOR_EXPERIMENT, + 'DECISION_SERVICE', + 'testExperimentLaunched', + 'user1' + ) + ); }); - it('should return false for a null experimentKey', function () { + it('should return false for a null experimentKey', function() { var didSetVariation = optlyInstance.setForcedVariation(null, 'user1', 'control'); assert.strictEqual(didSetVariation, false); var setVariationLogMessage = createdLogger.log.args[0][1]; - assert.strictEqual(setVariationLogMessage, sprintf(ERROR_MESSAGES.INVALID_INPUT_FORMAT, 'OPTIMIZELY', 'experiment_key')); + assert.strictEqual( + setVariationLogMessage, + sprintf(ERROR_MESSAGES.INVALID_INPUT_FORMAT, 'OPTIMIZELY', 'experiment_key') + ); }); - it('should return false for an undefined experimentKey', function () { + it('should return false for an undefined experimentKey', function() { var didSetVariation = optlyInstance.setForcedVariation(undefined, 'user1', 'control'); assert.strictEqual(didSetVariation, false); var setVariationLogMessage = createdLogger.log.args[0][1]; - assert.strictEqual(setVariationLogMessage, sprintf(ERROR_MESSAGES.INVALID_INPUT_FORMAT, 'OPTIMIZELY', 'experiment_key')); + assert.strictEqual( + setVariationLogMessage, + sprintf(ERROR_MESSAGES.INVALID_INPUT_FORMAT, 'OPTIMIZELY', 'experiment_key') + ); }); - it('should return false for an empty experimentKey', function () { + it('should return false for an empty experimentKey', function() { var didSetVariation = optlyInstance.setForcedVariation('', 'user1', 'control'); assert.strictEqual(didSetVariation, false); var setVariationLogMessage = createdLogger.log.args[0][1]; - assert.strictEqual(setVariationLogMessage, sprintf(ERROR_MESSAGES.INVALID_INPUT_FORMAT, 'OPTIMIZELY', 'experiment_key')); + assert.strictEqual( + setVariationLogMessage, + sprintf(ERROR_MESSAGES.INVALID_INPUT_FORMAT, 'OPTIMIZELY', 'experiment_key') + ); }); - it('should return false for a null userId', function () { + it('should return false for a null userId', function() { var didSetVariation = optlyInstance.setForcedVariation('testExperiment', null, 'control'); assert.strictEqual(didSetVariation, false); var setVariationLogMessage = createdLogger.log.args[0][1]; - assert.strictEqual(setVariationLogMessage, sprintf(ERROR_MESSAGES.INVALID_INPUT_FORMAT, 'OPTIMIZELY', 'user_id')); + assert.strictEqual( + setVariationLogMessage, + sprintf(ERROR_MESSAGES.INVALID_INPUT_FORMAT, 'OPTIMIZELY', 'user_id') + ); }); - it('should return false for an undefined userId', function () { + it('should return false for an undefined userId', function() { var didSetVariation = optlyInstance.setForcedVariation('testExperiment', undefined, 'control'); assert.strictEqual(didSetVariation, false); var setVariationLogMessage = createdLogger.log.args[0][1]; - assert.strictEqual(setVariationLogMessage, sprintf(ERROR_MESSAGES.INVALID_INPUT_FORMAT, 'OPTIMIZELY', 'user_id')); + assert.strictEqual( + setVariationLogMessage, + sprintf(ERROR_MESSAGES.INVALID_INPUT_FORMAT, 'OPTIMIZELY', 'user_id') + ); }); - it('should return true for an empty userId', function () { + it('should return true for an empty userId', function() { var didSetVariation = optlyInstance.setForcedVariation('testExperiment', '', 'control'); assert.strictEqual(didSetVariation, true); }); - it('should return false for a null variationKey', function () { + it('should return false for a null variationKey', function() { var didSetVariation = optlyInstance.setForcedVariation('testExperiment', 'user1', null); assert.strictEqual(didSetVariation, false); var setVariationLogMessage = createdLogger.log.args[0][1]; - assert.strictEqual(setVariationLogMessage, sprintf(ERROR_MESSAGES.USER_NOT_IN_FORCED_VARIATION, 'DECISION_SERVICE', 'user1')); + assert.strictEqual( + setVariationLogMessage, + sprintf(ERROR_MESSAGES.USER_NOT_IN_FORCED_VARIATION, 'DECISION_SERVICE', 'user1') + ); }); - it('should return false for an undefined variationKey', function () { + it('should return false for an undefined variationKey', function() { var didSetVariation = optlyInstance.setForcedVariation('testExperiment', 'user1', undefined); assert.strictEqual(didSetVariation, false); var setVariationLogMessage = createdLogger.log.args[0][1]; - assert.strictEqual(setVariationLogMessage, sprintf(ERROR_MESSAGES.USER_NOT_IN_FORCED_VARIATION, 'DECISION_SERVICE', 'user1')); + assert.strictEqual( + setVariationLogMessage, + sprintf(ERROR_MESSAGES.USER_NOT_IN_FORCED_VARIATION, 'DECISION_SERVICE', 'user1') + ); }); - it('should not override check for not running experiments in getVariation', function () { - var didSetVariation = optlyInstance.setForcedVariation('testExperimentNotRunning', 'user1', 'controlNotRunning'); + it('should not override check for not running experiments in getVariation', function() { + var didSetVariation = optlyInstance.setForcedVariation( + 'testExperimentNotRunning', + 'user1', + 'controlNotRunning' + ); assert.strictEqual(didSetVariation, true); var variation = optlyInstance.getVariation('testExperimentNotRunning', 'user1', {}); assert.strictEqual(variation, null); var logMessage0 = createdLogger.log.args[0][1]; - assert.strictEqual(logMessage0, sprintf(LOG_MESSAGES.USER_MAPPED_TO_FORCED_VARIATION, 'DECISION_SERVICE', 133338, 133337, 'user1')); + assert.strictEqual( + logMessage0, + sprintf(LOG_MESSAGES.USER_MAPPED_TO_FORCED_VARIATION, 'DECISION_SERVICE', 133338, 133337, 'user1') + ); var logMessage1 = createdLogger.log.args[1][1]; - assert.strictEqual(logMessage1, sprintf(LOG_MESSAGES.EXPERIMENT_NOT_RUNNING, 'DECISION_SERVICE', 'testExperimentNotRunning')); + assert.strictEqual( + logMessage1, + sprintf(LOG_MESSAGES.EXPERIMENT_NOT_RUNNING, 'DECISION_SERVICE', 'testExperimentNotRunning') + ); }); }); - describe('__validateInputs', function () { - it('should return true if user ID and attributes are valid', function () { + describe('__validateInputs', function() { + it('should return true if user ID and attributes are valid', function() { assert.isTrue(optlyInstance.__validateInputs({ user_id: 'testUser' })); assert.isTrue(optlyInstance.__validateInputs({ user_id: '' })); assert.isTrue(optlyInstance.__validateInputs({ user_id: 'testUser' }, { browser_type: 'firefox' })); sinon.assert.notCalled(createdLogger.log); }); - it('should return false and throw an error if user ID is invalid', function () { + it('should return false and throw an error if user ID is invalid', function() { var falseUserIdInput = optlyInstance.__validateInputs({ user_id: [] }); assert.isFalse(falseUserIdInput); @@ -1806,7 +2095,7 @@ describe('lib/optimizely', function () { assert.strictEqual(logMessage, sprintf(ERROR_MESSAGES.INVALID_INPUT_FORMAT, 'OPTIMIZELY', 'user_id')); }); - it('should return false and throw an error if attributes are invalid', function () { + it('should return false and throw an error if attributes are invalid', function() { var falseUserIdInput = optlyInstance.__validateInputs({ user_id: 'testUser' }, []); assert.isFalse(falseUserIdInput); @@ -1820,39 +2109,39 @@ describe('lib/optimizely', function () { }); }); - describe('should filter out null values', function () { - it('should filter out a null value', function () { - var dict = { 'test': null }; + describe('should filter out null values', function() { + it('should filter out a null value', function() { + var dict = { test: null }; var filteredValue = optlyInstance.__filterEmptyValues(dict); assert.deepEqual(filteredValue, {}); }); - it('should filter out a undefined value', function () { - var dict = { 'test': undefined }; + it('should filter out a undefined value', function() { + var dict = { test: undefined }; var filteredValue = optlyInstance.__filterEmptyValues(dict); assert.deepEqual(filteredValue, {}); }); - it('should filter out a null value, leave a non null one', function () { - var dict = { 'test': null, 'test2': 'not_null' }; + it('should filter out a null value, leave a non null one', function() { + var dict = { test: null, test2: 'not_null' }; var filteredValue = optlyInstance.__filterEmptyValues(dict); - assert.deepEqual(filteredValue, { 'test2': 'not_null' }); + assert.deepEqual(filteredValue, { test2: 'not_null' }); }); - it('should not filter out a non empty value', function () { - var dict = { 'test': 'hello' }; + it('should not filter out a non empty value', function() { + var dict = { test: 'hello' }; var filteredValue = optlyInstance.__filterEmptyValues(dict); - assert.deepEqual(filteredValue, { 'test': 'hello' }); + assert.deepEqual(filteredValue, { test: 'hello' }); }); }); - describe('notification listeners', function () { + describe('notification listeners', function() { var activateListener; var trackListener; var activateListener2; var trackListener2; - beforeEach(function () { + beforeEach(function() { activateListener = sinon.spy(); trackListener = sinon.spy(); activateListener2 = sinon.spy(); @@ -1861,31 +2150,25 @@ describe('lib/optimizely', function () { sinon.stub(fns, 'currentTimestamp').returns(1509489766569); }); - afterEach(function () { + afterEach(function() { fns.currentTimestamp.restore(); }); - it('should call a listener added for activate when activate is called', function () { - optlyInstance.notificationCenter.addNotificationListener( - enums.NOTIFICATION_TYPES.ACTIVATE, - activateListener - ); + it('should call a listener added for activate when activate is called', function() { + optlyInstance.notificationCenter.addNotificationListener(enums.NOTIFICATION_TYPES.ACTIVATE, activateListener); var variationKey = optlyInstance.activate('testExperiment', 'testUser'); assert.strictEqual(variationKey, 'variation'); sinon.assert.calledOnce(activateListener); }); - it('should call a listener added for track when track is called', function () { - optlyInstance.notificationCenter.addNotificationListener( - enums.NOTIFICATION_TYPES.TRACK, - trackListener - ); + it('should call a listener added for track when track is called', function() { + optlyInstance.notificationCenter.addNotificationListener(enums.NOTIFICATION_TYPES.TRACK, trackListener); optlyInstance.activate('testExperiment', 'testUser'); optlyInstance.track('testEvent', 'testUser'); sinon.assert.calledOnce(trackListener); }); - it('should not call a removed activate listener when activate is called', function () { + it('should not call a removed activate listener when activate is called', function() { var listenerId = optlyInstance.notificationCenter.addNotificationListener( enums.NOTIFICATION_TYPES.ACTIVATE, activateListener @@ -1896,7 +2179,7 @@ describe('lib/optimizely', function () { sinon.assert.notCalled(activateListener); }); - it('should not call a removed track listener when track is called', function () { + it('should not call a removed track listener when track is called', function() { var listenerId = optlyInstance.notificationCenter.addNotificationListener( enums.NOTIFICATION_TYPES.TRACK, trackListener @@ -1907,11 +2190,8 @@ describe('lib/optimizely', function () { sinon.assert.notCalled(trackListener); }); - it('removeNotificationListener should only remove the listener with the argument ID', function () { - optlyInstance.notificationCenter.addNotificationListener( - enums.NOTIFICATION_TYPES.ACTIVATE, - activateListener - ); + it('removeNotificationListener should only remove the listener with the argument ID', function() { + optlyInstance.notificationCenter.addNotificationListener(enums.NOTIFICATION_TYPES.ACTIVATE, activateListener); var trackListenerId = optlyInstance.notificationCenter.addNotificationListener( enums.NOTIFICATION_TYPES.TRACK, trackListener @@ -1922,15 +2202,9 @@ describe('lib/optimizely', function () { sinon.assert.calledOnce(activateListener); }); - it('should clear all notification listeners when clearAllNotificationListeners is called', function () { - optlyInstance.notificationCenter.addNotificationListener( - enums.NOTIFICATION_TYPES.ACTIVATE, - activateListener - ); - optlyInstance.notificationCenter.addNotificationListener( - enums.NOTIFICATION_TYPES.TRACK, - trackListener - ); + it('should clear all notification listeners when clearAllNotificationListeners is called', function() { + optlyInstance.notificationCenter.addNotificationListener(enums.NOTIFICATION_TYPES.ACTIVATE, activateListener); + optlyInstance.notificationCenter.addNotificationListener(enums.NOTIFICATION_TYPES.TRACK, trackListener); optlyInstance.notificationCenter.clearAllNotificationListeners(); optlyInstance.activate('testExperiment', 'testUser'); optlyInstance.track('testEvent', 'testUser'); @@ -1939,15 +2213,9 @@ describe('lib/optimizely', function () { sinon.assert.notCalled(trackListener); }); - it('should clear listeners of certain notification type when clearNotificationListeners is called', function () { - optlyInstance.notificationCenter.addNotificationListener( - enums.NOTIFICATION_TYPES.ACTIVATE, - activateListener - ); - optlyInstance.notificationCenter.addNotificationListener( - enums.NOTIFICATION_TYPES.TRACK, - trackListener - ); + it('should clear listeners of certain notification type when clearNotificationListeners is called', function() { + optlyInstance.notificationCenter.addNotificationListener(enums.NOTIFICATION_TYPES.ACTIVATE, activateListener); + optlyInstance.notificationCenter.addNotificationListener(enums.NOTIFICATION_TYPES.TRACK, trackListener); optlyInstance.notificationCenter.clearNotificationListeners(enums.NOTIFICATION_TYPES.ACTIVATE); optlyInstance.activate('testExperiment', 'testUser'); optlyInstance.track('testEvent', 'testUser'); @@ -1956,20 +2224,14 @@ describe('lib/optimizely', function () { sinon.assert.calledOnce(trackListener); }); - it('should only call the listener once after the same listener was added twice', function () { - optlyInstance.notificationCenter.addNotificationListener( - enums.NOTIFICATION_TYPES.ACTIVATE, - activateListener - ); - optlyInstance.notificationCenter.addNotificationListener( - enums.NOTIFICATION_TYPES.ACTIVATE, - activateListener - ); + it('should only call the listener once after the same listener was added twice', function() { + optlyInstance.notificationCenter.addNotificationListener(enums.NOTIFICATION_TYPES.ACTIVATE, activateListener); + optlyInstance.notificationCenter.addNotificationListener(enums.NOTIFICATION_TYPES.ACTIVATE, activateListener); optlyInstance.activate('testExperiment', 'testUser'); sinon.assert.calledOnce(activateListener); }); - it('should not add a listener with an invalid type argument', function () { + it('should not add a listener with an invalid type argument', function() { var listenerId = optlyInstance.notificationCenter.addNotificationListener( 'not a notification type', activateListener @@ -1981,40 +2243,25 @@ describe('lib/optimizely', function () { sinon.assert.notCalled(activateListener); }); - it('should call multiple notification listeners for activate when activate is called', function () { - optlyInstance.notificationCenter.addNotificationListener( - enums.NOTIFICATION_TYPES.ACTIVATE, - activateListener - ); - optlyInstance.notificationCenter.addNotificationListener( - enums.NOTIFICATION_TYPES.ACTIVATE, - activateListener2 - ); + it('should call multiple notification listeners for activate when activate is called', function() { + optlyInstance.notificationCenter.addNotificationListener(enums.NOTIFICATION_TYPES.ACTIVATE, activateListener); + optlyInstance.notificationCenter.addNotificationListener(enums.NOTIFICATION_TYPES.ACTIVATE, activateListener2); optlyInstance.activate('testExperiment', 'testUser'); sinon.assert.calledOnce(activateListener); sinon.assert.calledOnce(activateListener2); }); - it('should call multiple notification listeners for track when track is called', function () { - optlyInstance.notificationCenter.addNotificationListener( - enums.NOTIFICATION_TYPES.TRACK, - trackListener - ); - optlyInstance.notificationCenter.addNotificationListener( - enums.NOTIFICATION_TYPES.TRACK, - trackListener2 - ); + it('should call multiple notification listeners for track when track is called', function() { + optlyInstance.notificationCenter.addNotificationListener(enums.NOTIFICATION_TYPES.TRACK, trackListener); + optlyInstance.notificationCenter.addNotificationListener(enums.NOTIFICATION_TYPES.TRACK, trackListener2); optlyInstance.activate('testExperiment', 'testUser'); optlyInstance.track('testEvent', 'testUser'); sinon.assert.calledOnce(trackListener); sinon.assert.calledOnce(trackListener2); }); - it('should pass the correct arguments to an activate listener when activate is called', function () { - optlyInstance.notificationCenter.addNotificationListener( - enums.NOTIFICATION_TYPES.ACTIVATE, - activateListener - ); + it('should pass the correct arguments to an activate listener when activate is called', function() { + optlyInstance.notificationCenter.addNotificationListener(enums.NOTIFICATION_TYPES.ACTIVATE, activateListener); optlyInstance.activate('testExperiment', 'testUser'); var expectedImpressionEvent = { httpVerb: 'POST', @@ -2065,14 +2312,11 @@ describe('lib/optimizely', function () { sinon.assert.calledWith(activateListener, expectedArgument); }); - it('should pass the correct arguments to an activate listener when activate is called with attributes', function () { + it('should pass the correct arguments to an activate listener when activate is called with attributes', function() { var attributes = { browser_type: 'firefox', }; - optlyInstance.notificationCenter.addNotificationListener( - enums.NOTIFICATION_TYPES.ACTIVATE, - activateListener - ); + optlyInstance.notificationCenter.addNotificationListener(enums.NOTIFICATION_TYPES.ACTIVATE, activateListener); optlyInstance.activate('testExperiment', 'testUser', attributes); var expectedImpressionEvent = { httpVerb: 'POST', @@ -2130,11 +2374,8 @@ describe('lib/optimizely', function () { sinon.assert.calledWith(activateListener, expectedArgument); }); - it('should pass the correct arguments to a track listener when track is called', function () { - optlyInstance.notificationCenter.addNotificationListener( - enums.NOTIFICATION_TYPES.TRACK, - trackListener - ); + it('should pass the correct arguments to a track listener when track is called', function() { + optlyInstance.notificationCenter.addNotificationListener(enums.NOTIFICATION_TYPES.TRACK, trackListener); optlyInstance.activate('testExperiment', 'testUser'); optlyInstance.track('testEvent', 'testUser'); var expectedConversionEvent = { @@ -2178,14 +2419,11 @@ describe('lib/optimizely', function () { sinon.assert.calledWith(trackListener, expectedArgument); }); - it('should pass the correct arguments to a track listener when track is called with attributes', function () { + it('should pass the correct arguments to a track listener when track is called with attributes', function() { var attributes = { browser_type: 'firefox', }; - optlyInstance.notificationCenter.addNotificationListener( - enums.NOTIFICATION_TYPES.TRACK, - trackListener - ); + optlyInstance.notificationCenter.addNotificationListener(enums.NOTIFICATION_TYPES.TRACK, trackListener); optlyInstance.activate('testExperiment', 'testUser', attributes); optlyInstance.track('testEvent', 'testUser', attributes); var expectedConversionEvent = { @@ -2236,18 +2474,15 @@ describe('lib/optimizely', function () { sinon.assert.calledWith(trackListener, expectedArgument); }); - it('should pass the correct arguments to a track listener when track is called with attributes and event tags', function () { + it('should pass the correct arguments to a track listener when track is called with attributes and event tags', function() { var attributes = { browser_type: 'firefox', }; var eventTags = { value: 1.234, non_revenue: 'abc', - }; - optlyInstance.notificationCenter.addNotificationListener( - enums.NOTIFICATION_TYPES.TRACK, - trackListener - ); + }; + optlyInstance.notificationCenter.addNotificationListener(enums.NOTIFICATION_TYPES.TRACK, trackListener); optlyInstance.activate('testExperiment', 'testUser', attributes); optlyInstance.track('testEvent', 'testUser', attributes, eventTags); var expectedConversionEvent = { @@ -2303,14 +2538,14 @@ describe('lib/optimizely', function () { sinon.assert.calledWith(trackListener, expectedArgument); }); - describe('Decision Listener', function () { + describe('Decision Listener', function() { var decisionListener; - beforeEach(function () { + beforeEach(function() { decisionListener = sinon.spy(); }); - describe('activate', function () { - beforeEach(function () { + describe('activate', function() { + beforeEach(function() { optlyInstance = new Optimizely({ clientEngine: 'node-sdk', datafile: testData.getTestProjectConfig(), @@ -2328,7 +2563,7 @@ describe('lib/optimizely', function () { ); }); - it('should send notification with actual variation key when activate returns variation', function () { + it('should send notification with actual variation key when activate returns variation', function() { bucketStub.returns('111129'); var variation = optlyInstance.activate('testExperiment', 'testUser'); assert.strictEqual(variation, 'variation'); @@ -2338,12 +2573,12 @@ describe('lib/optimizely', function () { attributes: {}, decisionInfo: { experimentKey: 'testExperiment', - variationKey: variation - } + variationKey: variation, + }, }); }); - it('should send notification with null variation key when activate returns null', function () { + it('should send notification with null variation key when activate returns null', function() { bucketStub.returns(null); var variation = optlyInstance.activate('testExperiment', 'testUser'); assert.isNull(variation); @@ -2353,14 +2588,14 @@ describe('lib/optimizely', function () { attributes: {}, decisionInfo: { experimentKey: 'testExperiment', - variationKey: null - } + variationKey: null, + }, }); }); }); - describe('getVariation', function () { - beforeEach(function () { + describe('getVariation', function() { + beforeEach(function() { optlyInstance = new Optimizely({ clientEngine: 'node-sdk', datafile: testData.getTestProjectConfig(), @@ -2378,7 +2613,7 @@ describe('lib/optimizely', function () { ); }); - it('should send notification with actual variation key when getVariation returns variation', function () { + it('should send notification with actual variation key when getVariation returns variation', function() { bucketStub.returns('111129'); var variation = optlyInstance.getVariation('testExperiment', 'testUser'); assert.strictEqual(variation, 'variation'); @@ -2388,12 +2623,12 @@ describe('lib/optimizely', function () { attributes: {}, decisionInfo: { experimentKey: 'testExperiment', - variationKey: variation - } + variationKey: variation, + }, }); }); - it('should send notification with null variation key when getVariation returns null', function () { + it('should send notification with null variation key when getVariation returns null', function() { var variation = optlyInstance.getVariation('testExperimentWithAudiences', 'testUser', {}); assert.isNull(variation); sinon.assert.calledWith(decisionListener, { @@ -2402,12 +2637,12 @@ describe('lib/optimizely', function () { attributes: {}, decisionInfo: { experimentKey: 'testExperimentWithAudiences', - variationKey: null - } + variationKey: null, + }, }); }); - it('should send notification with variation key and type feature-test when getVariation returns feature experiment variation', 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(), @@ -2419,10 +2654,7 @@ describe('lib/optimizely', function () { isValidInstance: true, }); - optly.notificationCenter.addNotificationListener( - enums.NOTIFICATION_TYPES.DECISION, - decisionListener - ); + optly.notificationCenter.addNotificationListener(enums.NOTIFICATION_TYPES.DECISION, decisionListener); bucketStub.returns('594099'); var variation = optly.getVariation('testing_my_feature', 'testUser'); @@ -2433,16 +2665,16 @@ describe('lib/optimizely', function () { attributes: {}, decisionInfo: { experimentKey: 'testing_my_feature', - variationKey: variation - } + variationKey: variation, + }, }); }); }); - describe('feature management', function () { + describe('feature management', function() { var sandbox = sinon.sandbox.create(); - beforeEach(function () { + beforeEach(function() { optlyInstance = new Optimizely({ clientEngine: 'node-sdk', datafile: testData.getTestProjectConfigWithFeatures(), @@ -2459,16 +2691,16 @@ describe('lib/optimizely', function () { ); }); - afterEach(function () { + afterEach(function() { sandbox.restore(); }); - describe('isFeatureEnabled', function () { - describe('when the user bucketed into a variation of an experiment of the feature', function () { + describe('isFeatureEnabled', function() { + describe('when the user bucketed into a variation of an experiment of the feature', function() { var attributes = { test_attribute: 'test_value' }; - describe('when the variation is toggled ON', function () { - beforeEach(function () { + describe('when the variation is toggled ON', function() { + beforeEach(function() { var experiment = optlyInstance.projectConfigManager.getConfig().experimentKeyMap.testing_my_feature; var variation = experiment.variations[0]; sandbox.stub(optlyInstance.decisionService, 'getVariationForFeature').returns({ @@ -2478,7 +2710,7 @@ describe('lib/optimizely', function () { }); }); - it('should return true and send notification', function () { + it('should return true and send notification', function() { var result = optlyInstance.isFeatureEnabled('test_feature_for_experiment', 'user1', attributes); assert.strictEqual(result, true); sinon.assert.calledWith(decisionListener, { @@ -2491,15 +2723,15 @@ describe('lib/optimizely', function () { source: DECISION_SOURCES.FEATURE_TEST, sourceInfo: { experimentKey: 'testing_my_feature', - variationKey: 'variation' - } - } + variationKey: 'variation', + }, + }, }); }); }); - describe('when the variation is toggled OFF', function () { - beforeEach(function () { + describe('when the variation is toggled OFF', function() { + beforeEach(function() { var experiment = optlyInstance.projectConfigManager.getConfig().experimentKeyMap.test_shared_feature; var variation = experiment.variations[1]; sandbox.stub(optlyInstance.decisionService, 'getVariationForFeature').returns({ @@ -2509,7 +2741,7 @@ describe('lib/optimizely', function () { }); }); - it('should return false and send notification', function () { + it('should return false and send notification', function() { var result = optlyInstance.isFeatureEnabled('shared_feature', 'user1', attributes); assert.strictEqual(result, false); sinon.assert.calledWith(decisionListener, { @@ -2522,17 +2754,17 @@ describe('lib/optimizely', function () { source: DECISION_SOURCES.FEATURE_TEST, sourceInfo: { experimentKey: 'test_shared_feature', - variationKey: 'control' - } - } + variationKey: 'control', + }, + }, }); }); }); }); - describe('user bucketed into a variation of a rollout of the feature', function () { - describe('when the variation is toggled ON', function () { - beforeEach(function () { + describe('user bucketed into a variation of a rollout of the feature', function() { + describe('when the variation is toggled ON', function() { + beforeEach(function() { // This experiment is the first audience targeting rule in the rollout of feature 'test_feature' var experiment = optlyInstance.projectConfigManager.getConfig().experimentKeyMap['594031']; var variation = experiment.variations[0]; @@ -2543,7 +2775,7 @@ describe('lib/optimizely', function () { }); }); - it('should return true and send notification', function () { + it('should return true and send notification', function() { var result = optlyInstance.isFeatureEnabled('test_feature', 'user1', { test_attribute: 'test_value', }); @@ -2556,14 +2788,14 @@ describe('lib/optimizely', function () { featureKey: 'test_feature', featureEnabled: true, source: DECISION_SOURCES.ROLLOUT, - sourceInfo: {} - } + sourceInfo: {}, + }, }); }); }); - describe('when the variation is toggled OFF', function () { - beforeEach(function () { + describe('when the variation is toggled OFF', function() { + beforeEach(function() { // This experiment is the second audience targeting rule in the rollout of feature 'test_feature' var experiment = optlyInstance.projectConfigManager.getConfig().experimentKeyMap['594037']; var variation = experiment.variations[0]; @@ -2574,12 +2806,16 @@ describe('lib/optimizely', function () { }); }); - it('should return false and send notification', function () { + it('should return false and send notification', function() { var result = optlyInstance.isFeatureEnabled('test_feature', 'user1', { test_attribute: 'test_value', }); assert.strictEqual(result, false); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.INFO, 'OPTIMIZELY: Feature test_feature is not enabled for user user1.'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.INFO, + 'OPTIMIZELY: Feature test_feature is not enabled for user user1.' + ); var expectedArguments = { type: DECISION_NOTIFICATION_TYPES.FEATURE, @@ -2589,17 +2825,16 @@ describe('lib/optimizely', function () { featureKey: 'test_feature', featureEnabled: false, source: DECISION_SOURCES.ROLLOUT, - sourceInfo: { - } - } + sourceInfo: {}, + }, }; sinon.assert.calledWith(decisionListener, expectedArguments); }); }); }); - describe('user not bucketed into an experiment or a rollout', function () { - beforeEach(function () { + describe('user not bucketed into an experiment or a rollout', function() { + beforeEach(function() { sandbox.stub(optlyInstance.decisionService, 'getVariationForFeature').returns({ experiment: null, variation: null, @@ -2607,7 +2842,7 @@ describe('lib/optimizely', function () { }); }); - it('should return 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, { @@ -2618,18 +2853,21 @@ describe('lib/optimizely', function () { featureKey: 'test_feature', featureEnabled: false, source: DECISION_SOURCES.ROLLOUT, - sourceInfo: {} - } + sourceInfo: {}, + }, }); }); }); }); - 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.projectConfigManager.getConfig(), 'testing_my_feature'); + 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.projectConfigManager.getConfig(), + 'testing_my_feature' + ); var variation = experiment.variations[0]; sandbox.stub(optlyInstance.decisionService, 'getVariationForFeature').returns({ experiment: experiment, @@ -2638,8 +2876,13 @@ describe('lib/optimizely', function () { }); }); - it('returns the right value from getFeatureVariable and send notification with featureEnabled true', function () { - var result = optlyInstance.getFeatureVariable('test_feature_for_experiment', 'is_button_animated', 'user1', { test_attribute: 'test_value' }); + it('returns the right value from getFeatureVariable and send notification with featureEnabled true', function() { + var result = optlyInstance.getFeatureVariable( + 'test_feature_for_experiment', + 'is_button_animated', + 'user1', + { test_attribute: 'test_value' } + ); assert.strictEqual(result, true); sinon.assert.calledWith(decisionListener, { type: DECISION_NOTIFICATION_TYPES.FEATURE_VARIABLE, @@ -2654,14 +2897,19 @@ describe('lib/optimizely', function () { source: DECISION_SOURCES.FEATURE_TEST, sourceInfo: { experimentKey: 'testing_my_feature', - variationKey: 'variation' - } - } + variationKey: 'variation', + }, + }, }); }); - it('returns the right value from getFeatureVariable and send notification with featureEnabled true', function () { - var result = optlyInstance.getFeatureVariable('test_feature_for_experiment', 'button_width', 'user1', { test_attribute: 'test_value' }); + it('returns the right value from getFeatureVariable and send notification with featureEnabled true', function() { + var result = optlyInstance.getFeatureVariable( + 'test_feature_for_experiment', + 'button_width', + 'user1', + { test_attribute: 'test_value' } + ); assert.strictEqual(result, 20.25); sinon.assert.calledWith(decisionListener, { type: DECISION_NOTIFICATION_TYPES.FEATURE_VARIABLE, @@ -2676,14 +2924,16 @@ describe('lib/optimizely', function () { source: DECISION_SOURCES.FEATURE_TEST, sourceInfo: { experimentKey: 'testing_my_feature', - variationKey: 'variation' - } - } + variationKey: 'variation', + }, + }, }); }); - it('returns the right value from getFeatureVariable and send notification with featureEnabled true', function () { - var result = optlyInstance.getFeatureVariable('test_feature_for_experiment', 'num_buttons', 'user1', { test_attribute: 'test_value' }); + it('returns the right value from getFeatureVariable and send notification with featureEnabled true', function() { + var result = optlyInstance.getFeatureVariable('test_feature_for_experiment', 'num_buttons', 'user1', { + test_attribute: 'test_value', + }); assert.strictEqual(result, 2); sinon.assert.calledWith(decisionListener, { type: DECISION_NOTIFICATION_TYPES.FEATURE_VARIABLE, @@ -2698,14 +2948,16 @@ describe('lib/optimizely', function () { source: DECISION_SOURCES.FEATURE_TEST, sourceInfo: { experimentKey: 'testing_my_feature', - variationKey: 'variation' - } - } + variationKey: 'variation', + }, + }, }); }); - it('returns the right value from getFeatureVariable and send notification with featureEnabled true', function () { - var result = optlyInstance.getFeatureVariable('test_feature_for_experiment', 'button_txt', 'user1', { test_attribute: 'test_value' }); + it('returns the right value from getFeatureVariable and send notification with featureEnabled true', function() { + var result = optlyInstance.getFeatureVariable('test_feature_for_experiment', 'button_txt', 'user1', { + test_attribute: 'test_value', + }); assert.strictEqual(result, 'Buy me NOW'); sinon.assert.calledWith(decisionListener, { type: DECISION_NOTIFICATION_TYPES.FEATURE_VARIABLE, @@ -2720,14 +2972,19 @@ describe('lib/optimizely', function () { source: DECISION_SOURCES.FEATURE_TEST, sourceInfo: { experimentKey: 'testing_my_feature', - variationKey: 'variation' - } - } + variationKey: 'variation', + }, + }, }); }); - 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' }); + 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_NOTIFICATION_TYPES.FEATURE_VARIABLE, @@ -2742,14 +2999,19 @@ describe('lib/optimizely', function () { source: DECISION_SOURCES.FEATURE_TEST, sourceInfo: { experimentKey: 'testing_my_feature', - variationKey: 'variation' - } - } + variationKey: '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' }); + 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_NOTIFICATION_TYPES.FEATURE_VARIABLE, @@ -2764,14 +3026,19 @@ describe('lib/optimizely', function () { source: DECISION_SOURCES.FEATURE_TEST, sourceInfo: { experimentKey: 'testing_my_feature', - variationKey: 'variation' - } - } + variationKey: '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' }); + 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_NOTIFICATION_TYPES.FEATURE_VARIABLE, @@ -2786,14 +3053,19 @@ describe('lib/optimizely', function () { source: DECISION_SOURCES.FEATURE_TEST, sourceInfo: { experimentKey: 'testing_my_feature', - variationKey: 'variation' - } - } + variationKey: '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' }); + 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_NOTIFICATION_TYPES.FEATURE_VARIABLE, @@ -2808,16 +3080,19 @@ describe('lib/optimizely', function () { source: DECISION_SOURCES.FEATURE_TEST, sourceInfo: { experimentKey: 'testing_my_feature', - variationKey: 'variation' - } - } + variationKey: 'variation', + }, + }, }); }); }); - describe('when the variation is toggled OFF', function () { - beforeEach(function () { - var experiment = projectConfig.getExperimentFromKey(optlyInstance.projectConfigManager.getConfig(), 'testing_my_feature'); + describe('when the variation is toggled OFF', function() { + beforeEach(function() { + var experiment = projectConfig.getExperimentFromKey( + optlyInstance.projectConfigManager.getConfig(), + 'testing_my_feature' + ); var variation = experiment.variations[2]; sandbox.stub(optlyInstance.decisionService, 'getVariationForFeature').returns({ experiment: experiment, @@ -2826,8 +3101,13 @@ describe('lib/optimizely', function () { }); }); - it('returns the 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' }); + it('returns the 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_NOTIFICATION_TYPES.FEATURE_VARIABLE, @@ -2842,14 +3122,19 @@ describe('lib/optimizely', function () { source: DECISION_SOURCES.FEATURE_TEST, sourceInfo: { experimentKey: 'testing_my_feature', - variationKey: 'variation2' - } - } + variationKey: 'variation2', + }, + }, }); }); - it('returns the 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' }); + it('returns the 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_NOTIFICATION_TYPES.FEATURE_VARIABLE, @@ -2864,14 +3149,19 @@ describe('lib/optimizely', function () { source: DECISION_SOURCES.FEATURE_TEST, sourceInfo: { experimentKey: 'testing_my_feature', - variationKey: 'variation2' - } - } + variationKey: 'variation2', + }, + }, }); }); - it('returns the 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' }); + it('returns the 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_NOTIFICATION_TYPES.FEATURE_VARIABLE, @@ -2886,14 +3176,19 @@ describe('lib/optimizely', function () { source: DECISION_SOURCES.FEATURE_TEST, sourceInfo: { experimentKey: 'testing_my_feature', - variationKey: 'variation2' - } - } + variationKey: 'variation2', + }, + }, }); }); - it('returns the 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' }); + it('returns the 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_NOTIFICATION_TYPES.FEATURE_VARIABLE, @@ -2908,18 +3203,21 @@ describe('lib/optimizely', function () { source: DECISION_SOURCES.FEATURE_TEST, sourceInfo: { experimentKey: 'testing_my_feature', - variationKey: 'variation2' - } - } + variationKey: '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.projectConfigManager.getConfig(), '594031'); + 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.projectConfigManager.getConfig(), + '594031' + ); var variation = experiment.variations[0]; sandbox.stub(optlyInstance.decisionService, 'getVariationForFeature').returns({ experiment: experiment, @@ -2928,8 +3226,10 @@ describe('lib/optimizely', function () { }); }); - it('should return the right value from getFeatureVariable and send notification with featureEnabled true', function () { - var result = optlyInstance.getFeatureVariable('test_feature', 'new_content', 'user1', { test_attribute: 'test_value' }); + it('should return the right value from getFeatureVariable and send notification with featureEnabled true', function() { + var result = optlyInstance.getFeatureVariable('test_feature', 'new_content', 'user1', { + test_attribute: 'test_value', + }); assert.strictEqual(result, true); sinon.assert.calledWith(decisionListener, { type: DECISION_NOTIFICATION_TYPES.FEATURE_VARIABLE, @@ -2942,13 +3242,15 @@ describe('lib/optimizely', function () { variableValue: true, variableType: FEATURE_VARIABLE_TYPES.BOOLEAN, source: DECISION_SOURCES.ROLLOUT, - sourceInfo: {} - } + sourceInfo: {}, + }, }); }); - it('should return the right value from getFeatureVariable and send notification with featureEnabled true', function () { - var result = optlyInstance.getFeatureVariable('test_feature', 'price', 'user1', { test_attribute: 'test_value' }); + it('should return the right value from getFeatureVariable and send notification with featureEnabled true', function() { + var result = optlyInstance.getFeatureVariable('test_feature', 'price', 'user1', { + test_attribute: 'test_value', + }); assert.strictEqual(result, 4.99); sinon.assert.calledWith(decisionListener, { type: DECISION_NOTIFICATION_TYPES.FEATURE_VARIABLE, @@ -2961,13 +3263,15 @@ describe('lib/optimizely', function () { variableValue: 4.99, variableType: FEATURE_VARIABLE_TYPES.DOUBLE, source: DECISION_SOURCES.ROLLOUT, - sourceInfo: {} - } + sourceInfo: {}, + }, }); }); - it('should return the right value from getFeatureVariable and send notification with featureEnabled true', function () { - var result = optlyInstance.getFeatureVariable('test_feature', 'lasers', 'user1', { test_attribute: 'test_value' }); + it('should return the right value from getFeatureVariable and send notification with featureEnabled true', function() { + var result = optlyInstance.getFeatureVariable('test_feature', 'lasers', 'user1', { + test_attribute: 'test_value', + }); assert.strictEqual(result, 395); sinon.assert.calledWith(decisionListener, { type: DECISION_NOTIFICATION_TYPES.FEATURE_VARIABLE, @@ -2980,13 +3284,15 @@ describe('lib/optimizely', function () { variableValue: 395, variableType: FEATURE_VARIABLE_TYPES.INTEGER, source: DECISION_SOURCES.ROLLOUT, - sourceInfo: {} - } + sourceInfo: {}, + }, }); }); - it('should return the right value from getFeatureVariable and send notification with featureEnabled true', function () { - var result = optlyInstance.getFeatureVariable('test_feature', 'message', 'user1', { test_attribute: 'test_value' }); + it('should return the right value from getFeatureVariable and send notification with featureEnabled true', function() { + var result = optlyInstance.getFeatureVariable('test_feature', 'message', 'user1', { + test_attribute: 'test_value', + }); assert.strictEqual(result, 'Hello audience'); sinon.assert.calledWith(decisionListener, { type: DECISION_NOTIFICATION_TYPES.FEATURE_VARIABLE, @@ -2999,13 +3305,15 @@ describe('lib/optimizely', function () { variableValue: 'Hello audience', variableType: FEATURE_VARIABLE_TYPES.STRING, source: DECISION_SOURCES.ROLLOUT, - sourceInfo: {} - } + sourceInfo: {}, + }, }); }); - 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' }); + 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_NOTIFICATION_TYPES.FEATURE_VARIABLE, @@ -3018,13 +3326,15 @@ describe('lib/optimizely', function () { variableValue: true, variableType: FEATURE_VARIABLE_TYPES.BOOLEAN, source: DECISION_SOURCES.ROLLOUT, - sourceInfo: {} - } + sourceInfo: {}, + }, }); }); - 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' }); + 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_NOTIFICATION_TYPES.FEATURE_VARIABLE, @@ -3037,13 +3347,15 @@ describe('lib/optimizely', function () { variableValue: 4.99, variableType: FEATURE_VARIABLE_TYPES.DOUBLE, source: DECISION_SOURCES.ROLLOUT, - sourceInfo: {} - } + sourceInfo: {}, + }, }); }); - 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' }); + 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_NOTIFICATION_TYPES.FEATURE_VARIABLE, @@ -3056,13 +3368,15 @@ describe('lib/optimizely', function () { variableValue: 395, variableType: FEATURE_VARIABLE_TYPES.INTEGER, source: DECISION_SOURCES.ROLLOUT, - sourceInfo: {} - } + sourceInfo: {}, + }, }); }); - 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' }); + 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_NOTIFICATION_TYPES.FEATURE_VARIABLE, @@ -3075,15 +3389,18 @@ describe('lib/optimizely', function () { variableValue: 'Hello audience', variableType: FEATURE_VARIABLE_TYPES.STRING, source: DECISION_SOURCES.ROLLOUT, - sourceInfo: {} - } + sourceInfo: {}, + }, }); }); }); - describe('when the variation is toggled OFF', function () { - beforeEach(function () { - var experiment = projectConfig.getExperimentFromKey(optlyInstance.projectConfigManager.getConfig(), '594037'); + describe('when the variation is toggled OFF', function() { + beforeEach(function() { + var experiment = projectConfig.getExperimentFromKey( + optlyInstance.projectConfigManager.getConfig(), + '594037' + ); var variation = experiment.variations[0]; sandbox.stub(optlyInstance.decisionService, 'getVariationForFeature').returns({ experiment: experiment, @@ -3092,8 +3409,10 @@ describe('lib/optimizely', function () { }); }); - it('should return the default value from getFeatureVariable and send notification with featureEnabled false', function () { - var result = optlyInstance.getFeatureVariable('test_feature', 'new_content', 'user1', { test_attribute: 'test_value' }); + it('should return the default value from getFeatureVariable and send notification with featureEnabled false', function() { + var result = optlyInstance.getFeatureVariable('test_feature', 'new_content', 'user1', { + test_attribute: 'test_value', + }); assert.strictEqual(result, false); sinon.assert.calledWith(decisionListener, { type: DECISION_NOTIFICATION_TYPES.FEATURE_VARIABLE, @@ -3106,13 +3425,15 @@ describe('lib/optimizely', function () { variableValue: false, variableType: FEATURE_VARIABLE_TYPES.BOOLEAN, source: DECISION_SOURCES.ROLLOUT, - sourceInfo: {} - } + sourceInfo: {}, + }, }); }); - it('should return the default value from getFeatureVariable and send notification with featureEnabled false', function () { - var result = optlyInstance.getFeatureVariable('test_feature', 'price', 'user1', { test_attribute: 'test_value' }); + it('should return the default value from getFeatureVariable and send notification with featureEnabled false', function() { + var result = optlyInstance.getFeatureVariable('test_feature', 'price', 'user1', { + test_attribute: 'test_value', + }); assert.strictEqual(result, 14.99); sinon.assert.calledWith(decisionListener, { type: DECISION_NOTIFICATION_TYPES.FEATURE_VARIABLE, @@ -3125,13 +3446,15 @@ describe('lib/optimizely', function () { variableValue: 14.99, variableType: FEATURE_VARIABLE_TYPES.DOUBLE, source: DECISION_SOURCES.ROLLOUT, - sourceInfo: {} - } + sourceInfo: {}, + }, }); }); - it('should return the default value from getFeatureVariable and send notification with featureEnabled false', function () { - var result = optlyInstance.getFeatureVariable('test_feature', 'lasers', 'user1', { test_attribute: 'test_value' }); + it('should return the default value from getFeatureVariable and send notification with featureEnabled false', function() { + var result = optlyInstance.getFeatureVariable('test_feature', 'lasers', 'user1', { + test_attribute: 'test_value', + }); assert.strictEqual(result, 400); sinon.assert.calledWith(decisionListener, { type: DECISION_NOTIFICATION_TYPES.FEATURE_VARIABLE, @@ -3144,13 +3467,15 @@ describe('lib/optimizely', function () { variableValue: 400, variableType: FEATURE_VARIABLE_TYPES.INTEGER, source: DECISION_SOURCES.ROLLOUT, - sourceInfo: {} - } + sourceInfo: {}, + }, }); }); - it('should return the default value from getFeatureVariable and send notification with featureEnabled false', function () { - var result = optlyInstance.getFeatureVariable('test_feature', 'message', 'user1', { test_attribute: 'test_value' }); + it('should return the default value from getFeatureVariable and send notification with featureEnabled false', function() { + var result = optlyInstance.getFeatureVariable('test_feature', 'message', 'user1', { + test_attribute: 'test_value', + }); assert.strictEqual(result, 'Hello'); sinon.assert.calledWith(decisionListener, { type: DECISION_NOTIFICATION_TYPES.FEATURE_VARIABLE, @@ -3163,13 +3488,15 @@ describe('lib/optimizely', function () { variableValue: 'Hello', variableType: FEATURE_VARIABLE_TYPES.STRING, source: DECISION_SOURCES.ROLLOUT, - sourceInfo: {} - } + sourceInfo: {}, + }, }); }); - it('should return the default value from getFeatureVariableBoolean and send notification with featureEnabled false', function () { - var result = optlyInstance.getFeatureVariableBoolean('test_feature', 'new_content', 'user1', { test_attribute: 'test_value' }); + it('should return the default 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_NOTIFICATION_TYPES.FEATURE_VARIABLE, @@ -3182,13 +3509,15 @@ describe('lib/optimizely', function () { variableValue: false, variableType: FEATURE_VARIABLE_TYPES.BOOLEAN, source: DECISION_SOURCES.ROLLOUT, - sourceInfo: {} - } + sourceInfo: {}, + }, }); }); - it('should return the default value from getFeatureVariableDouble and send notification with featureEnabled false', function () { - var result = optlyInstance.getFeatureVariableDouble('test_feature', 'price', 'user1', { test_attribute: 'test_value' }); + it('should return the default 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_NOTIFICATION_TYPES.FEATURE_VARIABLE, @@ -3201,13 +3530,15 @@ describe('lib/optimizely', function () { variableValue: 14.99, variableType: FEATURE_VARIABLE_TYPES.DOUBLE, source: DECISION_SOURCES.ROLLOUT, - sourceInfo: {} - } + sourceInfo: {}, + }, }); }); - 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' }); + 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_NOTIFICATION_TYPES.FEATURE_VARIABLE, @@ -3220,13 +3551,15 @@ describe('lib/optimizely', function () { variableValue: 400, variableType: FEATURE_VARIABLE_TYPES.INTEGER, source: DECISION_SOURCES.ROLLOUT, - sourceInfo: {} - } + sourceInfo: {}, + }, }); }); - 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' }); + 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_NOTIFICATION_TYPES.FEATURE_VARIABLE, @@ -3239,15 +3572,15 @@ describe('lib/optimizely', function () { variableValue: 'Hello', variableType: FEATURE_VARIABLE_TYPES.STRING, source: DECISION_SOURCES.ROLLOUT, - sourceInfo: {} - } + sourceInfo: {}, + }, }); }); }); }); - describe('not bucketed into an experiment or a rollout', function () { - beforeEach(function () { + describe('not bucketed into an experiment or a rollout', function() { + beforeEach(function() { sandbox.stub(optlyInstance.decisionService, 'getVariationForFeature').returns({ experiment: null, variation: null, @@ -3255,8 +3588,13 @@ describe('lib/optimizely', function () { }); }); - it('returns the variable default value from getFeatureVariable and send notification with featureEnabled false', function () { - var result = optlyInstance.getFeatureVariable('test_feature_for_experiment', 'is_button_animated', 'user1', { test_attribute: 'test_value' }); + it('returns the variable default value from getFeatureVariable and send notification with featureEnabled false', function() { + var result = optlyInstance.getFeatureVariable( + 'test_feature_for_experiment', + 'is_button_animated', + 'user1', + { test_attribute: 'test_value' } + ); assert.strictEqual(result, false); sinon.assert.calledWith(decisionListener, { type: DECISION_NOTIFICATION_TYPES.FEATURE_VARIABLE, @@ -3269,13 +3607,15 @@ describe('lib/optimizely', function () { variableValue: false, variableType: FEATURE_VARIABLE_TYPES.BOOLEAN, source: DECISION_SOURCES.ROLLOUT, - sourceInfo: {} - } + sourceInfo: {}, + }, }); }); - it('returns the variable default value from getFeatureVariable and send notification with featureEnabled false', function () { - var result = optlyInstance.getFeatureVariable('test_feature_for_experiment', 'button_width', 'user1', { test_attribute: 'test_value' }); + it('returns the variable default value from getFeatureVariable and send notification with featureEnabled false', function() { + var result = optlyInstance.getFeatureVariable('test_feature_for_experiment', 'button_width', 'user1', { + test_attribute: 'test_value', + }); assert.strictEqual(result, 50.55); sinon.assert.calledWith(decisionListener, { type: DECISION_NOTIFICATION_TYPES.FEATURE_VARIABLE, @@ -3288,13 +3628,15 @@ describe('lib/optimizely', function () { variableValue: 50.55, variableType: FEATURE_VARIABLE_TYPES.DOUBLE, source: DECISION_SOURCES.ROLLOUT, - sourceInfo: {} - } + sourceInfo: {}, + }, }); }); - it('returns the variable default value from getFeatureVariable and send notification with featureEnabled false', function () { - var result = optlyInstance.getFeatureVariable('test_feature_for_experiment', 'num_buttons', 'user1', { test_attribute: 'test_value' }); + it('returns the variable default value from getFeatureVariable and send notification with featureEnabled false', function() { + var result = optlyInstance.getFeatureVariable('test_feature_for_experiment', 'num_buttons', 'user1', { + test_attribute: 'test_value', + }); assert.strictEqual(result, 10); sinon.assert.calledWith(decisionListener, { type: DECISION_NOTIFICATION_TYPES.FEATURE_VARIABLE, @@ -3307,13 +3649,15 @@ describe('lib/optimizely', function () { variableValue: 10, variableType: FEATURE_VARIABLE_TYPES.INTEGER, source: DECISION_SOURCES.ROLLOUT, - sourceInfo: {} - } + sourceInfo: {}, + }, }); }); - it('returns the variable default value from getFeatureVariable and send notification with featureEnabled false', function () { - var result = optlyInstance.getFeatureVariable('test_feature_for_experiment', 'button_txt', 'user1', { test_attribute: 'test_value' }); + it('returns the variable default value from getFeatureVariable and send notification with featureEnabled false', function() { + var result = optlyInstance.getFeatureVariable('test_feature_for_experiment', 'button_txt', 'user1', { + test_attribute: 'test_value', + }); assert.strictEqual(result, 'Buy me'); sinon.assert.calledWith(decisionListener, { type: DECISION_NOTIFICATION_TYPES.FEATURE_VARIABLE, @@ -3326,13 +3670,18 @@ describe('lib/optimizely', function () { variableValue: 'Buy me', variableType: FEATURE_VARIABLE_TYPES.STRING, source: DECISION_SOURCES.ROLLOUT, - sourceInfo: {} - } + sourceInfo: {}, + }, }); }); - 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' }); + 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_NOTIFICATION_TYPES.FEATURE_VARIABLE, @@ -3345,13 +3694,18 @@ describe('lib/optimizely', function () { variableValue: false, variableType: FEATURE_VARIABLE_TYPES.BOOLEAN, source: DECISION_SOURCES.ROLLOUT, - sourceInfo: {} - } + sourceInfo: {}, + }, }); }); - 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' }); + 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_NOTIFICATION_TYPES.FEATURE_VARIABLE, @@ -3364,13 +3718,18 @@ describe('lib/optimizely', function () { variableValue: 50.55, variableType: FEATURE_VARIABLE_TYPES.DOUBLE, source: DECISION_SOURCES.ROLLOUT, - sourceInfo: {} - } + sourceInfo: {}, + }, }); }); - 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' }); + 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_NOTIFICATION_TYPES.FEATURE_VARIABLE, @@ -3383,13 +3742,18 @@ describe('lib/optimizely', function () { variableValue: 10, variableType: FEATURE_VARIABLE_TYPES.INTEGER, source: DECISION_SOURCES.ROLLOUT, - sourceInfo: {} - } + sourceInfo: {}, + }, }); }); - 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' }); + 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_NOTIFICATION_TYPES.FEATURE_VARIABLE, @@ -3402,8 +3766,8 @@ describe('lib/optimizely', function () { variableValue: 'Buy me', variableType: FEATURE_VARIABLE_TYPES.STRING, source: DECISION_SOURCES.ROLLOUT, - sourceInfo: {} - } + sourceInfo: {}, + }, }); }); }); @@ -3414,13 +3778,13 @@ describe('lib/optimizely', function () { }); //tests separated out from APIs because of mock bucketing - describe('getVariationBucketingIdAttribute', function () { + describe('getVariationBucketingIdAttribute', function() { var optlyInstance; var createdLogger = logger.createLogger({ logLevel: LOG_LEVEL.INFO, logToConsole: false, }); - beforeEach(function () { + beforeEach(function() { optlyInstance = new Optimizely({ clientEngine: 'node-sdk', datafile: testData.getTestProjectConfig(), @@ -3434,46 +3798,40 @@ describe('lib/optimizely', function () { }); var userAttributes = { - 'browser_type': 'firefox', + browser_type: 'firefox', }; var userAttributesWithBucketingId = { - 'browser_type': 'firefox', - '$opt_bucketing_id': '123456789' + browser_type: 'firefox', + $opt_bucketing_id: '123456789', }; - it('confirm that a valid variation is bucketed without the bucketing ID', function () { - assert.strictEqual('controlWithAudience', optlyInstance.getVariation( - 'testExperimentWithAudiences', - 'testUser', - userAttributes - )); + it('confirm that a valid variation is bucketed without the bucketing ID', function() { + assert.strictEqual( + 'controlWithAudience', + optlyInstance.getVariation('testExperimentWithAudiences', 'testUser', userAttributes) + ); }); - it('confirm that an invalid audience returns null', function () { - assert.strictEqual(null, optlyInstance.getVariation( - 'testExperimentWithAudiences', - 'testUser' - )); + it('confirm that an invalid audience returns null', function() { + assert.strictEqual(null, optlyInstance.getVariation('testExperimentWithAudiences', 'testUser')); }); - it('confirm that a valid variation is bucketed with the bucketing ID', function () { - assert.strictEqual('variationWithAudience', optlyInstance.getVariation( - 'testExperimentWithAudiences', - 'testUser', - userAttributesWithBucketingId - )); + it('confirm that a valid variation is bucketed with the bucketing ID', function() { + assert.strictEqual( + 'variationWithAudience', + optlyInstance.getVariation('testExperimentWithAudiences', 'testUser', userAttributesWithBucketingId) + ); }); - it('confirm that invalid experiment with the bucketing ID returns null', function () { - assert.strictEqual(null, optlyInstance.getVariation( - 'invalidExperimentKey', - 'testUser', - userAttributesWithBucketingId - )); + it('confirm that invalid experiment with the bucketing ID returns null', function() { + assert.strictEqual( + null, + optlyInstance.getVariation('invalidExperimentKey', 'testUser', userAttributesWithBucketingId) + ); }); }); - describe('feature management', function () { + describe('feature management', function() { var sandbox = sinon.sandbox.create(); var createdLogger = logger.createLogger({ logLevel: LOG_LEVEL.INFO, @@ -3482,7 +3840,7 @@ describe('lib/optimizely', function () { var optlyInstance; var clock; - beforeEach(function () { + beforeEach(function() { optlyInstance = new Optimizely({ clientEngine: 'node-sdk', datafile: testData.getTestProjectConfigWithFeatures(), @@ -3503,24 +3861,24 @@ describe('lib/optimizely', function () { clock = sinon.useFakeTimers(new Date().getTime()); }); - afterEach(function () { + afterEach(function() { sandbox.restore(); clock.restore(); }); - describe('#isFeatureEnabled', function () { - it('returns false, and does not dispatch an impression event, for an invalid feature key', function () { + describe('#isFeatureEnabled', function() { + it('returns false, and does not dispatch an impression event, for an invalid feature key', function() { var result = optlyInstance.isFeatureEnabled('thisIsDefinitelyNotAFeatureKey', 'user1'); assert.strictEqual(result, false); sinon.assert.notCalled(eventDispatcher.dispatchEvent); }); - it('returns false if the instance is invalid', function () { + it('returns false if the instance is invalid', function() { optlyInstance = new Optimizely({ clientEngine: 'node-sdk', datafile: { lasers: 300, - message: 'this is not a valid datafile' + message: 'this is not a valid datafile', }, eventBuilder: eventBuilder, errorHandler: errorHandler, @@ -3530,14 +3888,18 @@ describe('lib/optimizely', function () { }); var result = optlyInstance.isFeatureEnabled('test_feature_for_experiment', 'user1'); assert.strictEqual(result, false); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.ERROR, 'OPTIMIZELY: Optimizely object is not valid. Failing isFeatureEnabled.'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.ERROR, + 'OPTIMIZELY: Optimizely object is not valid. Failing isFeatureEnabled.' + ); }); - describe('when the user bucketed into a variation of an experiment with the feature', function () { + describe('when the user bucketed into a variation of an experiment with the feature', function() { var attributes = { test_attribute: 'test_value' }; - describe('when the variation is toggled ON', function () { - beforeEach(function () { + describe('when the variation is toggled ON', function() { + beforeEach(function() { var experiment = optlyInstance.projectConfigManager.getConfig().experimentKeyMap.testing_my_feature; var variation = experiment.variations[0]; sandbox.stub(optlyInstance.decisionService, 'getVariationForFeature').returns({ @@ -3547,7 +3909,7 @@ describe('lib/optimizely', function () { }); }); - it('returns true and dispatches an impression event', function () { + it('returns true and dispatches an impression event', function() { var result = optlyInstance.isFeatureEnabled('test_feature_for_experiment', 'user1', attributes); assert.strictEqual(result, true); sinon.assert.calledOnce(optlyInstance.decisionService.getVariationForFeature); @@ -3562,152 +3924,193 @@ describe('lib/optimizely', function () { sinon.assert.calledOnce(eventDispatcher.dispatchEvent); var expectedImpressionEvent = { - 'httpVerb': 'POST', - 'url': 'https://logx.optimizely.com/v1/events', - 'params': { - 'account_id': '572018', - 'project_id': '594001', - 'visitors': [ + httpVerb: 'POST', + url: 'https://logx.optimizely.com/v1/events', + params: { + account_id: '572018', + project_id: '594001', + visitors: [ { - 'snapshots': [ + snapshots: [ { - 'decisions': [ + decisions: [ { - 'campaign_id': '594093', - 'experiment_id': '594098', - 'variation_id': '594096' - } + campaign_id: '594093', + experiment_id: '594098', + variation_id: '594096', + }, ], - 'events': [ + events: [ { - 'entity_id': '594093', - 'timestamp': 1509489766569, - 'key': 'campaign_activated', - 'uuid': 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c' - } - ] - } + entity_id: '594093', + timestamp: 1509489766569, + key: 'campaign_activated', + uuid: 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c', + }, + ], + }, ], - 'visitor_id': 'user1', - 'attributes': [ + visitor_id: 'user1', + attributes: [ + { + entity_id: '594014', + key: 'test_attribute', + type: 'custom', + value: 'test_value', + }, { - 'entity_id': '594014', - 'key': 'test_attribute', - 'type': 'custom', - 'value': 'test_value', - }, { - 'entity_id': '$opt_bot_filtering', - 'key': '$opt_bot_filtering', - 'type': 'custom', - 'value': true, + entity_id: '$opt_bot_filtering', + key: '$opt_bot_filtering', + type: 'custom', + value: true, }, ], - } + }, ], - 'revision': '35', - 'client_name': 'node-sdk', - 'client_version': enums.NODE_CLIENT_VERSION, - 'anonymize_ip': true, - 'enrich_decisions': true, + revision: '35', + client_name: 'node-sdk', + client_version: enums.NODE_CLIENT_VERSION, + anonymize_ip: true, + enrich_decisions: true, }, }; var callArgs = eventDispatcher.dispatchEvent.getCalls()[0].args; assert.deepEqual(callArgs[0], expectedImpressionEvent); assert.isFunction(callArgs[1]); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.INFO, 'OPTIMIZELY: Feature test_feature_for_experiment is enabled for user user1.'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.INFO, + 'OPTIMIZELY: Feature test_feature_for_experiment is enabled for user user1.' + ); }); - it('returns false and does not dispatch an impression event when feature key is null', function () { + it('returns false and does not dispatch an impression event when feature key is null', function() { var result = optlyInstance.isFeatureEnabled(null, 'user1', attributes); assert.strictEqual(result, false); sinon.assert.notCalled(eventDispatcher.dispatchEvent); - sinon.assert.calledWithExactly(createdLogger.log, LOG_LEVEL.ERROR, 'OPTIMIZELY: Provided feature_key is in an invalid format.'); + sinon.assert.calledWithExactly( + createdLogger.log, + LOG_LEVEL.ERROR, + 'OPTIMIZELY: Provided feature_key is in an invalid format.' + ); }); - it('returns false when user id is null', function () { + it('returns false when user id is null', function() { var result = optlyInstance.isFeatureEnabled('test_feature_for_experiment', null, attributes); assert.strictEqual(result, false); sinon.assert.notCalled(eventDispatcher.dispatchEvent); - sinon.assert.calledWithExactly(createdLogger.log, LOG_LEVEL.ERROR, 'OPTIMIZELY: Provided user_id is in an invalid format.'); + sinon.assert.calledWithExactly( + createdLogger.log, + LOG_LEVEL.ERROR, + 'OPTIMIZELY: Provided user_id is in an invalid format.' + ); }); - it('returns false when feature key and user id are null', function () { + it('returns false when feature key and user id are null', function() { var result = optlyInstance.isFeatureEnabled(null, null, attributes); assert.strictEqual(result, false); sinon.assert.notCalled(eventDispatcher.dispatchEvent); - sinon.assert.calledWithExactly(createdLogger.log, LOG_LEVEL.ERROR, 'OPTIMIZELY: Provided user_id is in an invalid format.'); + sinon.assert.calledWithExactly( + createdLogger.log, + LOG_LEVEL.ERROR, + 'OPTIMIZELY: Provided user_id is in an invalid format.' + ); }); - it('returns false when feature key is undefined', function () { + it('returns false when feature key is undefined', function() { var result = optlyInstance.isFeatureEnabled(undefined, 'user1', attributes); assert.strictEqual(result, false); sinon.assert.notCalled(eventDispatcher.dispatchEvent); - sinon.assert.calledWithExactly(createdLogger.log, LOG_LEVEL.ERROR, 'OPTIMIZELY: Provided feature_key is in an invalid format.'); + sinon.assert.calledWithExactly( + createdLogger.log, + LOG_LEVEL.ERROR, + 'OPTIMIZELY: Provided feature_key is in an invalid format.' + ); }); - it('returns false when user id is undefined', function () { + it('returns false when user id is undefined', function() { var result = optlyInstance.isFeatureEnabled('test_feature_for_experiment', undefined, attributes); assert.strictEqual(result, false); sinon.assert.notCalled(eventDispatcher.dispatchEvent); - sinon.assert.calledWithExactly(createdLogger.log, LOG_LEVEL.ERROR, 'OPTIMIZELY: Provided user_id is in an invalid format.'); + sinon.assert.calledWithExactly( + createdLogger.log, + LOG_LEVEL.ERROR, + 'OPTIMIZELY: Provided user_id is in an invalid format.' + ); }); - it('returns false when feature key and user id are undefined', function () { + it('returns false when feature key and user id are undefined', function() { var result = optlyInstance.isFeatureEnabled(undefined, undefined, attributes); assert.strictEqual(result, false); sinon.assert.notCalled(eventDispatcher.dispatchEvent); }); - it('returns false when no arguments are provided', function () { + it('returns false when no arguments are provided', function() { var result = optlyInstance.isFeatureEnabled(); assert.strictEqual(result, false); sinon.assert.notCalled(eventDispatcher.dispatchEvent); - sinon.assert.calledWithExactly(createdLogger.log, LOG_LEVEL.ERROR, 'OPTIMIZELY: Provided user_id is in an invalid format.'); + sinon.assert.calledWithExactly( + createdLogger.log, + LOG_LEVEL.ERROR, + 'OPTIMIZELY: Provided user_id is in an invalid format.' + ); }); - it('returns false when user id is an object', function () { + it('returns false when user id is an object', function() { var result = optlyInstance.isFeatureEnabled('test_feature_for_experiment', {}, attributes); assert.strictEqual(result, false); sinon.assert.notCalled(eventDispatcher.dispatchEvent); - sinon.assert.calledWithExactly(createdLogger.log, LOG_LEVEL.ERROR, 'OPTIMIZELY: Provided user_id is in an invalid format.'); + sinon.assert.calledWithExactly( + createdLogger.log, + LOG_LEVEL.ERROR, + 'OPTIMIZELY: Provided user_id is in an invalid format.' + ); }); - it('returns false when user id is a number', function () { + it('returns false when user id is a number', function() { var result = optlyInstance.isFeatureEnabled('test_feature_for_experiment', 72, attributes); assert.strictEqual(result, false); sinon.assert.notCalled(eventDispatcher.dispatchEvent); - sinon.assert.calledWithExactly(createdLogger.log, LOG_LEVEL.ERROR, 'OPTIMIZELY: Provided user_id is in an invalid format.'); + sinon.assert.calledWithExactly( + createdLogger.log, + LOG_LEVEL.ERROR, + 'OPTIMIZELY: Provided user_id is in an invalid format.' + ); }); - it('returns false when feature key is an array', function () { + it('returns false when feature key is an array', function() { var result = optlyInstance.isFeatureEnabled(['a', 'feature'], 'user1', attributes); assert.strictEqual(result, false); sinon.assert.notCalled(eventDispatcher.dispatchEvent); - sinon.assert.calledWithExactly(createdLogger.log, LOG_LEVEL.ERROR, 'OPTIMIZELY: Provided feature_key is in an invalid format.'); + sinon.assert.calledWithExactly( + createdLogger.log, + LOG_LEVEL.ERROR, + 'OPTIMIZELY: Provided feature_key is in an invalid format.' + ); }); - it('returns true when user id is an empty string', function () { + it('returns true when user id is an empty string', function() { var result = optlyInstance.isFeatureEnabled('test_feature_for_experiment', '', attributes); assert.strictEqual(result, true); sinon.assert.calledOnce(eventDispatcher.dispatchEvent); }); - it('returns false when feature key is an empty string', function () { + it('returns false when feature key is an empty string', function() { var result = optlyInstance.isFeatureEnabled('', 'user1', attributes); assert.strictEqual(result, false); sinon.assert.notCalled(eventDispatcher.dispatchEvent); }); - it('returns false when a feature key is provided, but a user id is not', function () { + it('returns false when a feature key is provided, but a user id is not', function() { var result = optlyInstance.isFeatureEnabled('test_feature_for_experiment'); assert.strictEqual(result, false); sinon.assert.notCalled(eventDispatcher.dispatchEvent); }); }); - describe('when the variation is toggled OFF', function () { + describe('when the variation is toggled OFF', function() { var result; - beforeEach(function () { + beforeEach(function() { var experiment = optlyInstance.projectConfigManager.getConfig().experimentKeyMap.test_shared_feature; var variation = experiment.variations[1]; sandbox.stub(optlyInstance.decisionService, 'getVariationForFeature').returns({ @@ -3718,7 +4121,7 @@ describe('lib/optimizely', function () { result = optlyInstance.isFeatureEnabled('shared_feature', 'user1', attributes); }); - it('should return false', function () { + it('should return false', function() { assert.strictEqual(result, false); sinon.assert.calledOnce(optlyInstance.decisionService.getVariationForFeature); var feature = optlyInstance.projectConfigManager.getConfig().featureKeyMap.shared_feature; @@ -3731,56 +4134,57 @@ describe('lib/optimizely', function () { ); }); - it('should dispatch an impression event', function () { + it('should dispatch an impression event', function() { sinon.assert.calledOnce(eventDispatcher.dispatchEvent); var expectedImpressionEvent = { - 'httpVerb': 'POST', - 'url': 'https://logx.optimizely.com/v1/events', - 'params': { - 'account_id': '572018', - 'project_id': '594001', - 'visitors': [ + httpVerb: 'POST', + url: 'https://logx.optimizely.com/v1/events', + params: { + account_id: '572018', + project_id: '594001', + visitors: [ { - 'snapshots': [ + snapshots: [ { - 'decisions': [ + decisions: [ { - 'campaign_id': '599023', - 'experiment_id': '599028', - 'variation_id': '599027' - } + campaign_id: '599023', + experiment_id: '599028', + variation_id: '599027', + }, ], - 'events': [ + events: [ { - 'entity_id': '599023', - 'timestamp': 1509489766569, - 'key': 'campaign_activated', - 'uuid': 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c' - } - ] - } + entity_id: '599023', + timestamp: 1509489766569, + key: 'campaign_activated', + uuid: 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c', + }, + ], + }, ], - 'visitor_id': 'user1', - 'attributes': [ + visitor_id: 'user1', + attributes: [ + { + entity_id: '594014', + key: 'test_attribute', + type: 'custom', + value: 'test_value', + }, { - 'entity_id': '594014', - 'key': 'test_attribute', - 'type': 'custom', - 'value': 'test_value', - }, { - 'entity_id': '$opt_bot_filtering', - 'key': '$opt_bot_filtering', - 'type': 'custom', - 'value': true, + entity_id: '$opt_bot_filtering', + key: '$opt_bot_filtering', + type: 'custom', + value: true, }, ], - } + }, ], - 'revision': '35', - 'client_name': 'node-sdk', - 'client_version': enums.NODE_CLIENT_VERSION, - 'anonymize_ip': true, - 'enrich_decisions': true, + revision: '35', + client_name: 'node-sdk', + client_version: enums.NODE_CLIENT_VERSION, + anonymize_ip: true, + enrich_decisions: true, }, }; var callArgs = eventDispatcher.dispatchEvent.getCalls()[0].args; @@ -3789,8 +4193,8 @@ describe('lib/optimizely', function () { }); }); - describe('when the variation is missing the toggle', function () { - beforeEach(function () { + describe('when the variation is missing the toggle', function() { + beforeEach(function() { var experiment = optlyInstance.projectConfigManager.getConfig().experimentKeyMap.test_shared_feature; var variation = fns.cloneDeep(experiment.variations[0]); delete variation['featureEnabled']; @@ -3801,7 +4205,7 @@ describe('lib/optimizely', function () { }); }); - it('should return false', function () { + it('should return false', function() { var result = optlyInstance.isFeatureEnabled('shared_feature', 'user1', attributes); assert.strictEqual(result, false); sinon.assert.calledOnce(optlyInstance.decisionService.getVariationForFeature); @@ -3817,9 +4221,9 @@ describe('lib/optimizely', function () { }); }); - describe('user bucketed into a variation of a rollout of the feature', function () { - describe('when the variation is toggled ON', function () { - beforeEach(function () { + describe('user bucketed into a variation of a rollout of the feature', function() { + describe('when the variation is toggled ON', function() { + beforeEach(function() { // This experiment is the first audience targeting rule in the rollout of feature 'test_feature' var experiment = optlyInstance.projectConfigManager.getConfig().experimentKeyMap['594031']; var variation = experiment.variations[0]; @@ -3830,18 +4234,22 @@ describe('lib/optimizely', function () { }); }); - it('returns true and does not dispatch an event', function () { + it('returns true and does not dispatch an event', function() { var result = optlyInstance.isFeatureEnabled('test_feature', 'user1', { test_attribute: 'test_value', }); assert.strictEqual(result, true); sinon.assert.notCalled(eventDispatcher.dispatchEvent); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.INFO, 'OPTIMIZELY: Feature test_feature is enabled for user user1.'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.INFO, + 'OPTIMIZELY: Feature test_feature is enabled for user user1.' + ); }); }); - describe('when the variation is toggled OFF', function () { - beforeEach(function () { + describe('when the variation is toggled OFF', function() { + beforeEach(function() { // This experiment is the second audience targeting rule in the rollout of feature 'test_feature' var experiment = optlyInstance.projectConfigManager.getConfig().experimentKeyMap['594037']; var variation = experiment.variations[0]; @@ -3852,18 +4260,22 @@ describe('lib/optimizely', function () { }); }); - it('returns false', function () { + it('returns false', function() { var result = optlyInstance.isFeatureEnabled('test_feature', 'user1', { test_attribute: 'test_value', }); assert.strictEqual(result, false); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.INFO, 'OPTIMIZELY: Feature test_feature is not enabled for user user1.'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.INFO, + 'OPTIMIZELY: Feature test_feature is not enabled for user user1.' + ); }); }); }); - describe('user not bucketed into an experiment or a rollout', function () { - beforeEach(function () { + describe('user not bucketed into an experiment or a rollout', function() { + beforeEach(function() { sandbox.stub(optlyInstance.decisionService, 'getVariationForFeature').returns({ experiment: null, variation: null, @@ -3871,28 +4283,32 @@ describe('lib/optimizely', function () { }); }); - it('returns false and does not dispatch an event', function () { + it('returns false and does not dispatch an event', function() { var result = optlyInstance.isFeatureEnabled('test_feature', 'user1'); assert.strictEqual(result, false); sinon.assert.notCalled(eventDispatcher.dispatchEvent); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.INFO, 'OPTIMIZELY: Feature test_feature is not enabled for user user1.'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.INFO, + 'OPTIMIZELY: Feature test_feature is not enabled for user user1.' + ); }); }); }); - describe('#getEnabledFeatures', function () { - beforeEach(function () { - sandbox.stub(optlyInstance, 'isFeatureEnabled').callsFake(function (featureKey) { + describe('#getEnabledFeatures', function() { + beforeEach(function() { + sandbox.stub(optlyInstance, 'isFeatureEnabled').callsFake(function(featureKey) { return featureKey === 'test_feature' || featureKey === 'test_feature_for_experiment'; }); }); - it('returns an empty array if the instance is invalid', function () { + it('returns an empty array if the instance is invalid', function() { optlyInstance = new Optimizely({ clientEngine: 'node-sdk', datafile: { lasers: 300, - message: 'this is not a valid datafile' + message: 'this is not a valid datafile', }, eventBuilder: eventBuilder, errorHandler: errorHandler, @@ -3902,61 +4318,35 @@ describe('lib/optimizely', function () { }); var result = optlyInstance.getEnabledFeatures('user1', { test_attribute: 'test_value' }); assert.deepEqual(result, []); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.ERROR, 'OPTIMIZELY: Optimizely object is not valid. Failing getEnabledFeatures.'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.ERROR, + 'OPTIMIZELY: Optimizely object is not valid. Failing getEnabledFeatures.' + ); }); - it('returns only enabled features for the specified user and attributes', function () { - var attributes = { test_attribute: 'test_value', }; + it('returns only enabled features for the specified user and attributes', function() { + var attributes = { test_attribute: 'test_value' }; var result = optlyInstance.getEnabledFeatures('user1', attributes); assert.strictEqual(result.length, 2); assert.isAbove(result.indexOf('test_feature'), -1); assert.isAbove(result.indexOf('test_feature_for_experiment'), -1); sinon.assert.callCount(optlyInstance.isFeatureEnabled, 7); - sinon.assert.calledWithExactly( - optlyInstance.isFeatureEnabled, - 'test_feature', - 'user1', - attributes - ); - sinon.assert.calledWithExactly( - optlyInstance.isFeatureEnabled, - 'test_feature_2', - 'user1', - attributes - ); + sinon.assert.calledWithExactly(optlyInstance.isFeatureEnabled, 'test_feature', 'user1', attributes); + sinon.assert.calledWithExactly(optlyInstance.isFeatureEnabled, 'test_feature_2', 'user1', attributes); sinon.assert.calledWithExactly( optlyInstance.isFeatureEnabled, 'test_feature_for_experiment', 'user1', attributes ); - sinon.assert.calledWithExactly( - optlyInstance.isFeatureEnabled, - 'feature_with_group', - 'user1', - attributes - ); - sinon.assert.calledWithExactly( - optlyInstance.isFeatureEnabled, - 'shared_feature', - 'user1', - attributes - ); - sinon.assert.calledWithExactly( - optlyInstance.isFeatureEnabled, - 'unused_flag', - 'user1', - attributes - ); - sinon.assert.calledWithExactly( - optlyInstance.isFeatureEnabled, - 'feature_exp_no_traffic', - 'user1', - attributes - ); + sinon.assert.calledWithExactly(optlyInstance.isFeatureEnabled, 'feature_with_group', 'user1', attributes); + sinon.assert.calledWithExactly(optlyInstance.isFeatureEnabled, 'shared_feature', 'user1', attributes); + sinon.assert.calledWithExactly(optlyInstance.isFeatureEnabled, 'unused_flag', 'user1', attributes); + sinon.assert.calledWithExactly(optlyInstance.isFeatureEnabled, 'feature_exp_no_traffic', 'user1', attributes); }); - it('return features that are enabled for the user and send notification for every feature', function () { + it('return features that are enabled for the user and send notification for every feature', function() { optlyInstance = new Optimizely({ clientEngine: 'node-sdk', datafile: testData.getTestProjectConfigWithFeatures(), @@ -3983,8 +4373,8 @@ describe('lib/optimizely', function () { featureKey: 'test_feature', featureEnabled: false, source: DECISION_SOURCES.ROLLOUT, - sourceInfo: {} - } + sourceInfo: {}, + }, }); sinon.assert.calledWithExactly(decisionListener.getCall(1), { type: DECISION_NOTIFICATION_TYPES.FEATURE, @@ -3994,8 +4384,8 @@ describe('lib/optimizely', function () { featureKey: 'test_feature_2', featureEnabled: true, source: DECISION_SOURCES.ROLLOUT, - sourceInfo: {} - } + sourceInfo: {}, + }, }); sinon.assert.calledWithExactly(decisionListener.getCall(2), { type: DECISION_NOTIFICATION_TYPES.FEATURE, @@ -4007,9 +4397,9 @@ describe('lib/optimizely', function () { source: DECISION_SOURCES.FEATURE_TEST, sourceInfo: { experimentKey: 'testing_my_feature', - variationKey: 'variation' - } - } + variationKey: 'variation', + }, + }, }); sinon.assert.calledWithExactly(decisionListener.getCall(3), { type: DECISION_NOTIFICATION_TYPES.FEATURE, @@ -4019,8 +4409,8 @@ describe('lib/optimizely', function () { featureKey: 'feature_with_group', featureEnabled: false, source: DECISION_SOURCES.ROLLOUT, - sourceInfo: {} - } + sourceInfo: {}, + }, }); sinon.assert.calledWithExactly(decisionListener.getCall(4), { type: DECISION_NOTIFICATION_TYPES.FEATURE, @@ -4032,9 +4422,9 @@ describe('lib/optimizely', function () { source: DECISION_SOURCES.FEATURE_TEST, sourceInfo: { experimentKey: 'test_shared_feature', - variationKey: 'treatment' - } - } + variationKey: 'treatment', + }, + }, }); sinon.assert.calledWithExactly(decisionListener.getCall(5), { type: DECISION_NOTIFICATION_TYPES.FEATURE, @@ -4044,8 +4434,8 @@ describe('lib/optimizely', function () { featureKey: 'unused_flag', featureEnabled: false, source: DECISION_SOURCES.ROLLOUT, - sourceInfo: {} - } + sourceInfo: {}, + }, }); sinon.assert.calledWithExactly(decisionListener.getCall(6), { type: DECISION_NOTIFICATION_TYPES.FEATURE, @@ -4055,17 +4445,20 @@ describe('lib/optimizely', function () { featureKey: 'feature_exp_no_traffic', featureEnabled: false, source: DECISION_SOURCES.ROLLOUT, - sourceInfo: {} - } + sourceInfo: {}, + }, }); }); }); - describe('feature variable APIs', function () { - describe('bucketed into variation in an experiment with variable values', function () { - describe('when the variation is toggled ON', function () { - beforeEach(function () { - var experiment = projectConfig.getExperimentFromKey(optlyInstance.projectConfigManager.getConfig(), 'testing_my_feature'); + describe('feature variable APIs', function() { + describe('bucketed into variation in an experiment with variable values', function() { + describe('when the variation is toggled ON', function() { + beforeEach(function() { + var experiment = projectConfig.getExperimentFromKey( + optlyInstance.projectConfigManager.getConfig(), + 'testing_my_feature' + ); var variation = experiment.variations[0]; sandbox.stub(optlyInstance.decisionService, 'getVariationForFeature').returns({ experiment: experiment, @@ -4074,112 +4467,238 @@ describe('lib/optimizely', function () { }); }); - it('returns the right value from getFeatureVariable', function () { - var result = optlyInstance.getFeatureVariable('test_feature_for_experiment', 'is_button_animated', 'user1', { test_attribute: 'test_value' }); + it('returns the right value from getFeatureVariable', function() { + var result = optlyInstance.getFeatureVariable( + 'test_feature_for_experiment', + 'is_button_animated', + 'user1', + { test_attribute: 'test_value' } + ); assert.strictEqual(result, true); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.INFO, 'OPTIMIZELY: Value for variable "is_button_animated" of feature flag "test_feature_for_experiment" is true for user "user1"'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.INFO, + 'OPTIMIZELY: Value for variable "is_button_animated" of feature flag "test_feature_for_experiment" is true for user "user1"' + ); }); - it('returns the right value from getFeatureVariable', function () { - var result = optlyInstance.getFeatureVariable('test_feature_for_experiment', 'button_width', 'user1', { test_attribute: 'test_value' }); + it('returns the right value from getFeatureVariable', function() { + var result = optlyInstance.getFeatureVariable('test_feature_for_experiment', 'button_width', 'user1', { + test_attribute: 'test_value', + }); assert.strictEqual(result, 20.25); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.INFO, 'OPTIMIZELY: Value for variable "button_width" of feature flag "test_feature_for_experiment" is 20.25 for user "user1"'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.INFO, + 'OPTIMIZELY: Value for variable "button_width" of feature flag "test_feature_for_experiment" is 20.25 for user "user1"' + ); }); - it('returns the right value from getFeatureVariable', function () { - var result = optlyInstance.getFeatureVariable('test_feature_for_experiment', 'num_buttons', 'user1', { test_attribute: 'test_value' }); + it('returns the right value from getFeatureVariable', function() { + var result = optlyInstance.getFeatureVariable('test_feature_for_experiment', 'num_buttons', 'user1', { + test_attribute: 'test_value', + }); assert.strictEqual(result, 2); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.INFO, 'OPTIMIZELY: Value for variable "num_buttons" of feature flag "test_feature_for_experiment" is 2 for user "user1"'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.INFO, + 'OPTIMIZELY: Value for variable "num_buttons" of feature flag "test_feature_for_experiment" is 2 for user "user1"' + ); }); - it('returns the right value from getFeatureVariable', function () { - var result = optlyInstance.getFeatureVariable('test_feature_for_experiment', 'button_txt', 'user1', { test_attribute: 'test_value' }); + it('returns the right value from getFeatureVariable', function() { + var result = optlyInstance.getFeatureVariable('test_feature_for_experiment', 'button_txt', 'user1', { + test_attribute: 'test_value', + }); assert.strictEqual(result, 'Buy me NOW'); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.INFO, 'OPTIMIZELY: Value for variable "button_txt" of feature flag "test_feature_for_experiment" is Buy me NOW for user "user1"'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.INFO, + 'OPTIMIZELY: Value for variable "button_txt" of feature flag "test_feature_for_experiment" is Buy me NOW for user "user1"' + ); }); - it('returns the right value from getFeatureVariableBoolean', function () { - var result = optlyInstance.getFeatureVariableBoolean('test_feature_for_experiment', 'is_button_animated', 'user1', { test_attribute: 'test_value' }); + it('returns the right value from getFeatureVariableBoolean', function() { + var result = optlyInstance.getFeatureVariableBoolean( + 'test_feature_for_experiment', + 'is_button_animated', + 'user1', + { test_attribute: 'test_value' } + ); assert.strictEqual(result, true); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.INFO, 'OPTIMIZELY: Value for variable "is_button_animated" of feature flag "test_feature_for_experiment" is true for user "user1"'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.INFO, + 'OPTIMIZELY: Value for variable "is_button_animated" of feature flag "test_feature_for_experiment" is true for user "user1"' + ); }); - it('returns the right value from getFeatureVariableDouble', function () { - var result = optlyInstance.getFeatureVariableDouble('test_feature_for_experiment', 'button_width', 'user1', { test_attribute: 'test_value' }); + it('returns the right value from getFeatureVariableDouble', function() { + var result = optlyInstance.getFeatureVariableDouble( + 'test_feature_for_experiment', + 'button_width', + 'user1', + { test_attribute: 'test_value' } + ); assert.strictEqual(result, 20.25); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.INFO, 'OPTIMIZELY: Value for variable "button_width" of feature flag "test_feature_for_experiment" is 20.25 for user "user1"'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.INFO, + 'OPTIMIZELY: Value for variable "button_width" of feature flag "test_feature_for_experiment" is 20.25 for user "user1"' + ); }); - it('returns the right value from getFeatureVariableInteger', function () { - var result = optlyInstance.getFeatureVariableInteger('test_feature_for_experiment', 'num_buttons', 'user1', { test_attribute: 'test_value' }); + it('returns the right value from getFeatureVariableInteger', function() { + var result = optlyInstance.getFeatureVariableInteger( + 'test_feature_for_experiment', + 'num_buttons', + 'user1', + { test_attribute: 'test_value' } + ); assert.strictEqual(result, 2); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.INFO, 'OPTIMIZELY: Value for variable "num_buttons" of feature flag "test_feature_for_experiment" is 2 for user "user1"'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.INFO, + 'OPTIMIZELY: Value for variable "num_buttons" of feature flag "test_feature_for_experiment" is 2 for user "user1"' + ); }); - it('returns the right value from getFeatureVariableString', function () { - var result = optlyInstance.getFeatureVariableString('test_feature_for_experiment', 'button_txt', 'user1', { test_attribute: 'test_value' }); + it('returns the right value from getFeatureVariableString', 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(createdLogger.log, LOG_LEVEL.INFO, 'OPTIMIZELY: Value for variable "button_txt" of feature flag "test_feature_for_experiment" is Buy me NOW for user "user1"'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.INFO, + 'OPTIMIZELY: Value for variable "button_txt" of feature flag "test_feature_for_experiment" is Buy me NOW for user "user1"' + ); }); - describe('when the variable is not used in the variation', function () { - beforeEach(function () { + describe('when the variable is not used in the variation', function() { + beforeEach(function() { sandbox.stub(projectConfig, 'getVariableValueForVariation').returns(null); }); - it('returns the variable default value from getFeatureVariable', function () { - var result = optlyInstance.getFeatureVariable('test_feature_for_experiment', 'is_button_animated', 'user1', { test_attribute: 'test_value' }); + it('returns the variable default value from getFeatureVariable', function() { + var result = optlyInstance.getFeatureVariable( + 'test_feature_for_experiment', + 'is_button_animated', + 'user1', + { test_attribute: 'test_value' } + ); assert.strictEqual(result, false); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.INFO, 'OPTIMIZELY: Variable "is_button_animated" is not used in variation "variation". Returning default value.'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.INFO, + 'OPTIMIZELY: Variable "is_button_animated" is not used in variation "variation". Returning default value.' + ); }); - it('returns the variable default value from getFeatureVariable', function () { - var result = optlyInstance.getFeatureVariable('test_feature_for_experiment', 'button_width', 'user1', { test_attribute: 'test_value' }); + it('returns the variable default value from getFeatureVariable', function() { + var result = optlyInstance.getFeatureVariable('test_feature_for_experiment', 'button_width', 'user1', { + test_attribute: 'test_value', + }); assert.strictEqual(result, 50.55); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.INFO, 'OPTIMIZELY: Variable "button_width" is not used in variation "variation". Returning default value.'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.INFO, + 'OPTIMIZELY: Variable "button_width" is not used in variation "variation". Returning default value.' + ); }); - it('returns the variable default value from getFeatureVariable', function () { - var result = optlyInstance.getFeatureVariable('test_feature_for_experiment', 'num_buttons', 'user1', { test_attribute: 'test_value' }); + it('returns the variable default value from getFeatureVariable', function() { + var result = optlyInstance.getFeatureVariable('test_feature_for_experiment', 'num_buttons', 'user1', { + test_attribute: 'test_value', + }); assert.strictEqual(result, 10); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.INFO, 'OPTIMIZELY: Variable "num_buttons" is not used in variation "variation". Returning default value.'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.INFO, + 'OPTIMIZELY: Variable "num_buttons" is not used in variation "variation". Returning default value.' + ); }); - it('returns the variable default value from getFeatureVariable', function () { - var result = optlyInstance.getFeatureVariable('test_feature_for_experiment', 'button_txt', 'user1', { test_attribute: 'test_value' }); + it('returns the variable default value from getFeatureVariable', function() { + var result = optlyInstance.getFeatureVariable('test_feature_for_experiment', 'button_txt', 'user1', { + test_attribute: 'test_value', + }); assert.strictEqual(result, 'Buy me'); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.INFO, 'OPTIMIZELY: Variable "button_txt" is not used in variation "variation". Returning default value.'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.INFO, + 'OPTIMIZELY: Variable "button_txt" is not used in variation "variation". Returning default value.' + ); }); - it('returns the variable default value from getFeatureVariableBoolean', function () { - var result = optlyInstance.getFeatureVariableBoolean('test_feature_for_experiment', 'is_button_animated', 'user1', { test_attribute: 'test_value' }); + it('returns the variable default value from getFeatureVariableBoolean', function() { + var result = optlyInstance.getFeatureVariableBoolean( + 'test_feature_for_experiment', + 'is_button_animated', + 'user1', + { test_attribute: 'test_value' } + ); assert.strictEqual(result, false); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.INFO, 'OPTIMIZELY: Variable "is_button_animated" is not used in variation "variation". Returning default value.'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.INFO, + 'OPTIMIZELY: Variable "is_button_animated" is not used in variation "variation". Returning default value.' + ); }); - it('returns the variable default value from getFeatureVariableDouble', function () { - var result = optlyInstance.getFeatureVariableDouble('test_feature_for_experiment', 'button_width', 'user1', { test_attribute: 'test_value' }); + it('returns the variable default value from getFeatureVariableDouble', function() { + var result = optlyInstance.getFeatureVariableDouble( + 'test_feature_for_experiment', + 'button_width', + 'user1', + { test_attribute: 'test_value' } + ); assert.strictEqual(result, 50.55); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.INFO, 'OPTIMIZELY: Variable "button_width" is not used in variation "variation". Returning default value.'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.INFO, + 'OPTIMIZELY: Variable "button_width" is not used in variation "variation". Returning default value.' + ); }); - it('returns the variable default value from getFeatureVariableInteger', function () { - var result = optlyInstance.getFeatureVariableInteger('test_feature_for_experiment', 'num_buttons', 'user1', { test_attribute: 'test_value' }); + it('returns the variable default value from getFeatureVariableInteger', function() { + var result = optlyInstance.getFeatureVariableInteger( + 'test_feature_for_experiment', + 'num_buttons', + 'user1', + { test_attribute: 'test_value' } + ); assert.strictEqual(result, 10); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.INFO, 'OPTIMIZELY: Variable "num_buttons" is not used in variation "variation". Returning default value.'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.INFO, + 'OPTIMIZELY: Variable "num_buttons" is not used in variation "variation". Returning default value.' + ); }); - it('returns the variable default value from getFeatureVariableString', function () { - var result = optlyInstance.getFeatureVariableString('test_feature_for_experiment', 'button_txt', 'user1', { test_attribute: 'test_value' }); + it('returns the variable default value from getFeatureVariableString', function() { + var result = optlyInstance.getFeatureVariableString( + 'test_feature_for_experiment', + 'button_txt', + 'user1', + { test_attribute: 'test_value' } + ); assert.strictEqual(result, 'Buy me'); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.INFO, 'OPTIMIZELY: Variable "button_txt" is not used in variation "variation". Returning default value.'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.INFO, + 'OPTIMIZELY: Variable "button_txt" is not used in variation "variation". Returning default value.' + ); }); }); }); - describe('when the variation is toggled OFF', function () { - beforeEach(function () { - var experiment = projectConfig.getExperimentFromKey(optlyInstance.projectConfigManager.getConfig(), 'testing_my_feature'); + describe('when the variation is toggled OFF', function() { + beforeEach(function() { + var experiment = projectConfig.getExperimentFromKey( + optlyInstance.projectConfigManager.getConfig(), + 'testing_my_feature' + ); var variation = experiment.variations[2]; sandbox.stub(optlyInstance.decisionService, 'getVariationForFeature').returns({ experiment: experiment, @@ -4188,60 +4707,123 @@ describe('lib/optimizely', function () { }); }); - it('returns the variable default value from getFeatureVariable', function () { - var result = optlyInstance.getFeatureVariable('test_feature_for_experiment', 'is_button_animated', 'user1', { test_attribute: 'test_value' }); + it('returns the variable default value from getFeatureVariable', function() { + var result = optlyInstance.getFeatureVariable( + 'test_feature_for_experiment', + 'is_button_animated', + 'user1', + { test_attribute: 'test_value' } + ); assert.strictEqual(result, false); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.INFO, 'OPTIMIZELY: Feature "test_feature_for_experiment" is not enabled for user user1. Returning default value for variable "is_button_animated".'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.INFO, + 'OPTIMIZELY: Feature "test_feature_for_experiment" is not enabled for user user1. Returning default value for variable "is_button_animated".' + ); }); - it('returns the variable default value from getFeatureVariable', function () { - var result = optlyInstance.getFeatureVariable('test_feature_for_experiment', 'button_width', 'user1', { test_attribute: 'test_value' }); + it('returns the variable default value from getFeatureVariable', function() { + var result = optlyInstance.getFeatureVariable('test_feature_for_experiment', 'button_width', 'user1', { + test_attribute: 'test_value', + }); assert.strictEqual(result, 50.55); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.INFO, 'OPTIMIZELY: Feature "test_feature_for_experiment" is not enabled for user user1. Returning default value for variable "button_width".'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.INFO, + 'OPTIMIZELY: Feature "test_feature_for_experiment" is not enabled for user user1. Returning default value for variable "button_width".' + ); }); - it('returns the variable default value from getFeatureVariable', function () { - var result = optlyInstance.getFeatureVariable('test_feature_for_experiment', 'num_buttons', 'user1', { test_attribute: 'test_value' }); + it('returns the variable default value from getFeatureVariable', function() { + var result = optlyInstance.getFeatureVariable('test_feature_for_experiment', 'num_buttons', 'user1', { + test_attribute: 'test_value', + }); assert.strictEqual(result, 10); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.INFO, 'OPTIMIZELY: Feature "test_feature_for_experiment" is not enabled for user user1. Returning default value for variable "num_buttons".'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.INFO, + 'OPTIMIZELY: Feature "test_feature_for_experiment" is not enabled for user user1. Returning default value for variable "num_buttons".' + ); }); - it('returns the variable default value from getFeatureVariable', function () { - var result = optlyInstance.getFeatureVariable('test_feature_for_experiment', 'button_txt', 'user1', { test_attribute: 'test_value' }); + it('returns the variable default value from getFeatureVariable', function() { + var result = optlyInstance.getFeatureVariable('test_feature_for_experiment', 'button_txt', 'user1', { + test_attribute: 'test_value', + }); assert.strictEqual(result, 'Buy me'); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.INFO, 'OPTIMIZELY: Feature "test_feature_for_experiment" is not enabled for user user1. Returning default value for variable "button_txt".'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.INFO, + 'OPTIMIZELY: Feature "test_feature_for_experiment" is not enabled for user user1. Returning default value for variable "button_txt".' + ); }); - it('returns the variable default value from getFeatureVariableBoolean', function () { - var result = optlyInstance.getFeatureVariableBoolean('test_feature_for_experiment', 'is_button_animated', 'user1', { test_attribute: 'test_value' }); + it('returns the variable default value from getFeatureVariableBoolean', function() { + var result = optlyInstance.getFeatureVariableBoolean( + 'test_feature_for_experiment', + 'is_button_animated', + 'user1', + { test_attribute: 'test_value' } + ); assert.strictEqual(result, false); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.INFO, 'OPTIMIZELY: Feature "test_feature_for_experiment" is not enabled for user user1. Returning default value for variable "is_button_animated".'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.INFO, + 'OPTIMIZELY: Feature "test_feature_for_experiment" is not enabled for user user1. Returning default value for variable "is_button_animated".' + ); }); - it('returns the variable default value from getFeatureVariableDouble', function () { - var result = optlyInstance.getFeatureVariableDouble('test_feature_for_experiment', 'button_width', 'user1', { test_attribute: 'test_value' }); + it('returns the variable default value from getFeatureVariableDouble', function() { + var result = optlyInstance.getFeatureVariableDouble( + 'test_feature_for_experiment', + 'button_width', + 'user1', + { test_attribute: 'test_value' } + ); assert.strictEqual(result, 50.55); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.INFO, 'OPTIMIZELY: Feature "test_feature_for_experiment" is not enabled for user user1. Returning default value for variable "button_width".'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.INFO, + 'OPTIMIZELY: Feature "test_feature_for_experiment" is not enabled for user user1. Returning default value for variable "button_width".' + ); }); - it('returns the variable default value from getFeatureVariableInteger', function () { - var result = optlyInstance.getFeatureVariableInteger('test_feature_for_experiment', 'num_buttons', 'user1', { test_attribute: 'test_value' }); + it('returns the variable default value from getFeatureVariableInteger', function() { + var result = optlyInstance.getFeatureVariableInteger( + 'test_feature_for_experiment', + 'num_buttons', + 'user1', + { test_attribute: 'test_value' } + ); assert.strictEqual(result, 10); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.INFO, 'OPTIMIZELY: Feature "test_feature_for_experiment" is not enabled for user user1. Returning default value for variable "num_buttons".'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.INFO, + 'OPTIMIZELY: Feature "test_feature_for_experiment" is not enabled for user user1. Returning default value for variable "num_buttons".' + ); }); - it('returns the variable default value from getFeatureVariableString', function () { - var result = optlyInstance.getFeatureVariableString('test_feature_for_experiment', 'button_txt', 'user1', { test_attribute: 'test_value' }); + it('returns the variable default value from getFeatureVariableString', function() { + var result = optlyInstance.getFeatureVariableString('test_feature_for_experiment', 'button_txt', 'user1', { + test_attribute: 'test_value', + }); assert.strictEqual(result, 'Buy me'); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.INFO, 'OPTIMIZELY: Feature "test_feature_for_experiment" is not enabled for user user1. Returning default value for variable "button_txt".'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.INFO, + 'OPTIMIZELY: Feature "test_feature_for_experiment" is not enabled for user user1. Returning default value for variable "button_txt".' + ); }); }); }); - 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.projectConfigManager.getConfig(), '594031'); + 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.projectConfigManager.getConfig(), + '594031' + ); var variation = experiment.variations[0]; sandbox.stub(optlyInstance.decisionService, 'getVariationForFeature').returns({ experiment: experiment, @@ -4250,112 +4832,211 @@ describe('lib/optimizely', function () { }); }); - it('returns the right value from getFeatureVariable', function () { - var result = optlyInstance.getFeatureVariable('test_feature', 'new_content', 'user1', { test_attribute: 'test_value' }); + it('returns the right value from getFeatureVariable', function() { + var result = optlyInstance.getFeatureVariable('test_feature', 'new_content', 'user1', { + test_attribute: 'test_value', + }); assert.strictEqual(result, true); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.INFO, 'OPTIMIZELY: Value for variable "new_content" of feature flag "test_feature" is true for user "user1"'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.INFO, + 'OPTIMIZELY: Value for variable "new_content" of feature flag "test_feature" is true for user "user1"' + ); }); - it('returns the right value from getFeatureVariable', function () { - var result = optlyInstance.getFeatureVariable('test_feature', 'price', 'user1', { test_attribute: 'test_value' }); + it('returns the right value from getFeatureVariable', function() { + var result = optlyInstance.getFeatureVariable('test_feature', 'price', 'user1', { + test_attribute: 'test_value', + }); assert.strictEqual(result, 4.99); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.INFO, 'OPTIMIZELY: Value for variable "price" of feature flag "test_feature" is 4.99 for user "user1"'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.INFO, + 'OPTIMIZELY: Value for variable "price" of feature flag "test_feature" is 4.99 for user "user1"' + ); }); - it('returns the right value from getFeatureVariable', function () { - var result = optlyInstance.getFeatureVariable('test_feature', 'lasers', 'user1', { test_attribute: 'test_value' }); + it('returns the right value from getFeatureVariable', function() { + var result = optlyInstance.getFeatureVariable('test_feature', 'lasers', 'user1', { + test_attribute: 'test_value', + }); assert.strictEqual(result, 395); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.INFO, 'OPTIMIZELY: Value for variable "lasers" of feature flag "test_feature" is 395 for user "user1"'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.INFO, + 'OPTIMIZELY: Value for variable "lasers" of feature flag "test_feature" is 395 for user "user1"' + ); }); - it('returns the right value from getFeatureVariable', function () { - var result = optlyInstance.getFeatureVariable('test_feature', 'message', 'user1', { test_attribute: 'test_value' }); + it('returns the right value from getFeatureVariable', function() { + var result = optlyInstance.getFeatureVariable('test_feature', 'message', 'user1', { + test_attribute: 'test_value', + }); assert.strictEqual(result, 'Hello audience'); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.INFO, 'OPTIMIZELY: Value for variable "message" of feature flag "test_feature" is Hello audience for user "user1"'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.INFO, + 'OPTIMIZELY: Value for variable "message" of feature flag "test_feature" is Hello audience for user "user1"' + ); }); - it('returns the right value from getFeatureVariableBoolean', function () { - var result = optlyInstance.getFeatureVariableBoolean('test_feature', 'new_content', 'user1', { test_attribute: 'test_value' }); + it('returns the right value from getFeatureVariableBoolean', function() { + var result = optlyInstance.getFeatureVariableBoolean('test_feature', 'new_content', 'user1', { + test_attribute: 'test_value', + }); assert.strictEqual(result, true); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.INFO, 'OPTIMIZELY: Value for variable "new_content" of feature flag "test_feature" is true for user "user1"'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.INFO, + 'OPTIMIZELY: Value for variable "new_content" of feature flag "test_feature" is true for user "user1"' + ); }); - it('returns the right value from getFeatureVariableDouble', function () { - var result = optlyInstance.getFeatureVariableDouble('test_feature', 'price', 'user1', { test_attribute: 'test_value' }); + it('returns the right value from getFeatureVariableDouble', function() { + var result = optlyInstance.getFeatureVariableDouble('test_feature', 'price', 'user1', { + test_attribute: 'test_value', + }); assert.strictEqual(result, 4.99); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.INFO, 'OPTIMIZELY: Value for variable "price" of feature flag "test_feature" is 4.99 for user "user1"'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.INFO, + 'OPTIMIZELY: Value for variable "price" of feature flag "test_feature" is 4.99 for user "user1"' + ); }); - it('returns the right value from getFeatureVariableInteger', function () { - var result = optlyInstance.getFeatureVariableInteger('test_feature', 'lasers', 'user1', { test_attribute: 'test_value' }); + it('returns the right value from getFeatureVariableInteger', function() { + var result = optlyInstance.getFeatureVariableInteger('test_feature', 'lasers', 'user1', { + test_attribute: 'test_value', + }); assert.strictEqual(result, 395); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.INFO, 'OPTIMIZELY: Value for variable "lasers" of feature flag "test_feature" is 395 for user "user1"'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.INFO, + 'OPTIMIZELY: Value for variable "lasers" of feature flag "test_feature" is 395 for user "user1"' + ); }); - it('returns the right value from getFeatureVariableString', function () { - var result = optlyInstance.getFeatureVariableString('test_feature', 'message', 'user1', { test_attribute: 'test_value' }); + it('returns the right value from getFeatureVariableString', function() { + var result = optlyInstance.getFeatureVariableString('test_feature', 'message', 'user1', { + test_attribute: 'test_value', + }); assert.strictEqual(result, 'Hello audience'); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.INFO, 'OPTIMIZELY: Value for variable "message" of feature flag "test_feature" is Hello audience for user "user1"'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.INFO, + 'OPTIMIZELY: Value for variable "message" of feature flag "test_feature" is Hello audience for user "user1"' + ); }); - describe('when the variable is not used in the variation', function () { - beforeEach(function () { + describe('when the variable is not used in the variation', function() { + beforeEach(function() { sandbox.stub(projectConfig, 'getVariableValueForVariation').returns(null); }); - it('returns the variable default value from getFeatureVariable', function () { - var result = optlyInstance.getFeatureVariable('test_feature', 'new_content', 'user1', { test_attribute: 'test_value' }); + it('returns the variable default value from getFeatureVariable', function() { + var result = optlyInstance.getFeatureVariable('test_feature', 'new_content', 'user1', { + test_attribute: 'test_value', + }); assert.strictEqual(result, false); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.INFO, 'OPTIMIZELY: Variable "new_content" is not used in variation "594032". Returning default value.'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.INFO, + 'OPTIMIZELY: Variable "new_content" is not used in variation "594032". Returning default value.' + ); }); - it('returns the variable default value from getFeatureVariable', function () { - var result = optlyInstance.getFeatureVariable('test_feature', 'price', 'user1', { test_attribute: 'test_value' }); + it('returns the variable default value from getFeatureVariable', function() { + var result = optlyInstance.getFeatureVariable('test_feature', 'price', 'user1', { + test_attribute: 'test_value', + }); assert.strictEqual(result, 14.99); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.INFO, 'OPTIMIZELY: Variable "price" is not used in variation "594032". Returning default value.'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.INFO, + 'OPTIMIZELY: Variable "price" is not used in variation "594032". Returning default value.' + ); }); - it('returns the variable default value from getFeatureVariable', function () { - var result = optlyInstance.getFeatureVariable('test_feature', 'lasers', 'user1', { test_attribute: 'test_value' }); + it('returns the variable default value from getFeatureVariable', function() { + var result = optlyInstance.getFeatureVariable('test_feature', 'lasers', 'user1', { + test_attribute: 'test_value', + }); assert.strictEqual(result, 400); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.INFO, 'OPTIMIZELY: Variable "lasers" is not used in variation "594032". Returning default value.'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.INFO, + 'OPTIMIZELY: Variable "lasers" is not used in variation "594032". Returning default value.' + ); }); - it('returns the variable default value from getFeatureVariable', function () { - var result = optlyInstance.getFeatureVariable('test_feature', 'message', 'user1', { test_attribute: 'test_value' }); + it('returns the variable default value from getFeatureVariable', function() { + var result = optlyInstance.getFeatureVariable('test_feature', 'message', 'user1', { + test_attribute: 'test_value', + }); assert.strictEqual(result, 'Hello'); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.INFO, 'OPTIMIZELY: Variable "message" is not used in variation "594032". Returning default value.'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.INFO, + 'OPTIMIZELY: Variable "message" is not used in variation "594032". Returning default value.' + ); }); - it('returns the variable default value from getFeatureVariableBoolean', function () { - var result = optlyInstance.getFeatureVariableBoolean('test_feature', 'new_content', 'user1', { test_attribute: 'test_value' }); + it('returns the variable default value from getFeatureVariableBoolean', function() { + var result = optlyInstance.getFeatureVariableBoolean('test_feature', 'new_content', 'user1', { + test_attribute: 'test_value', + }); assert.strictEqual(result, false); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.INFO, 'OPTIMIZELY: Variable "new_content" is not used in variation "594032". Returning default value.'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.INFO, + 'OPTIMIZELY: Variable "new_content" is not used in variation "594032". Returning default value.' + ); }); - it('returns the variable default value from getFeatureVariableDouble', function () { - var result = optlyInstance.getFeatureVariableDouble('test_feature', 'price', 'user1', { test_attribute: 'test_value' }); + it('returns the variable default value from getFeatureVariableDouble', function() { + var result = optlyInstance.getFeatureVariableDouble('test_feature', 'price', 'user1', { + test_attribute: 'test_value', + }); assert.strictEqual(result, 14.99); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.INFO, 'OPTIMIZELY: Variable "price" is not used in variation "594032". Returning default value.'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.INFO, + 'OPTIMIZELY: Variable "price" is not used in variation "594032". Returning default value.' + ); }); - it('returns the variable default value from getFeatureVariableInteger', function () { - var result = optlyInstance.getFeatureVariableInteger('test_feature', 'lasers', 'user1', { test_attribute: 'test_value' }); + it('returns the variable default value from getFeatureVariableInteger', function() { + var result = optlyInstance.getFeatureVariableInteger('test_feature', 'lasers', 'user1', { + test_attribute: 'test_value', + }); assert.strictEqual(result, 400); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.INFO, 'OPTIMIZELY: Variable "lasers" is not used in variation "594032". Returning default value.'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.INFO, + 'OPTIMIZELY: Variable "lasers" is not used in variation "594032". Returning default value.' + ); }); - it('returns the variable default value from getFeatureVariableString', function () { - var result = optlyInstance.getFeatureVariableString('test_feature', 'message', 'user1', { test_attribute: 'test_value' }); + it('returns the variable default value from getFeatureVariableString', function() { + var result = optlyInstance.getFeatureVariableString('test_feature', 'message', 'user1', { + test_attribute: 'test_value', + }); assert.strictEqual(result, 'Hello'); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.INFO, 'OPTIMIZELY: Variable "message" is not used in variation "594032". Returning default value.'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.INFO, + 'OPTIMIZELY: Variable "message" is not used in variation "594032". Returning default value.' + ); }); }); }); - describe('when the variation is toggled OFF', function () { - beforeEach(function () { - var experiment = projectConfig.getExperimentFromKey(optlyInstance.projectConfigManager.getConfig(), '594037'); + describe('when the variation is toggled OFF', function() { + beforeEach(function() { + var experiment = projectConfig.getExperimentFromKey( + optlyInstance.projectConfigManager.getConfig(), + '594037' + ); var variation = experiment.variations[0]; sandbox.stub(optlyInstance.decisionService, 'getVariationForFeature').returns({ experiment: experiment, @@ -4364,58 +5045,106 @@ describe('lib/optimizely', function () { }); }); - it('returns the variable default value from getFeatureVariable', function () { - var result = optlyInstance.getFeatureVariable('test_feature', 'new_content', 'user1', { test_attribute: 'test_value' }); + it('returns the variable default value from getFeatureVariable', function() { + var result = optlyInstance.getFeatureVariable('test_feature', 'new_content', 'user1', { + test_attribute: 'test_value', + }); assert.strictEqual(result, false); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.INFO, 'OPTIMIZELY: Feature "test_feature" is not enabled for user user1. Returning default value for variable "new_content".'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.INFO, + 'OPTIMIZELY: Feature "test_feature" is not enabled for user user1. Returning default value for variable "new_content".' + ); }); - it('returns the variable default value from getFeatureVariable', function () { - var result = optlyInstance.getFeatureVariable('test_feature', 'price', 'user1', { test_attribute: 'test_value' }); + it('returns the variable default value from getFeatureVariable', function() { + var result = optlyInstance.getFeatureVariable('test_feature', 'price', 'user1', { + test_attribute: 'test_value', + }); assert.strictEqual(result, 14.99); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.INFO, 'OPTIMIZELY: Feature "test_feature" is not enabled for user user1. Returning default value for variable "price".'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.INFO, + 'OPTIMIZELY: Feature "test_feature" is not enabled for user user1. Returning default value for variable "price".' + ); }); - it('returns the variable default value from getFeatureVariable', function () { - var result = optlyInstance.getFeatureVariable('test_feature', 'lasers', 'user1', { test_attribute: 'test_value' }); + it('returns the variable default value from getFeatureVariable', function() { + var result = optlyInstance.getFeatureVariable('test_feature', 'lasers', 'user1', { + test_attribute: 'test_value', + }); assert.strictEqual(result, 400); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.INFO, 'OPTIMIZELY: Feature "test_feature" is not enabled for user user1. Returning default value for variable "lasers".'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.INFO, + 'OPTIMIZELY: Feature "test_feature" is not enabled for user user1. Returning default value for variable "lasers".' + ); }); - it('returns the variable default value from getFeatureVariable', function () { - var result = optlyInstance.getFeatureVariable('test_feature', 'message', 'user1', { test_attribute: 'test_value' }); + it('returns the variable default value from getFeatureVariable', function() { + var result = optlyInstance.getFeatureVariable('test_feature', 'message', 'user1', { + test_attribute: 'test_value', + }); assert.strictEqual(result, 'Hello'); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.INFO, 'OPTIMIZELY: Feature "test_feature" is not enabled for user user1. Returning default value for variable "message".'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.INFO, + 'OPTIMIZELY: Feature "test_feature" is not enabled for user user1. Returning default value for variable "message".' + ); }); - it('returns the variable default value from getFeatureVariableBoolean', function () { - var result = optlyInstance.getFeatureVariableBoolean('test_feature', 'new_content', 'user1', { test_attribute: 'test_value' }); + it('returns the variable default value from getFeatureVariableBoolean', function() { + var result = optlyInstance.getFeatureVariableBoolean('test_feature', 'new_content', 'user1', { + test_attribute: 'test_value', + }); assert.strictEqual(result, false); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.INFO, 'OPTIMIZELY: Feature "test_feature" is not enabled for user user1. Returning default value for variable "new_content".'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.INFO, + 'OPTIMIZELY: Feature "test_feature" is not enabled for user user1. Returning default value for variable "new_content".' + ); }); - it('returns the variable default value from getFeatureVariableDouble', function () { - var result = optlyInstance.getFeatureVariableDouble('test_feature', 'price', 'user1', { test_attribute: 'test_value' }); + it('returns the variable default value from getFeatureVariableDouble', function() { + var result = optlyInstance.getFeatureVariableDouble('test_feature', 'price', 'user1', { + test_attribute: 'test_value', + }); assert.strictEqual(result, 14.99); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.INFO, 'OPTIMIZELY: Feature "test_feature" is not enabled for user user1. Returning default value for variable "price".'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.INFO, + 'OPTIMIZELY: Feature "test_feature" is not enabled for user user1. Returning default value for variable "price".' + ); }); - it('returns the variable default value from getFeatureVariableInteger', function () { - var result = optlyInstance.getFeatureVariableInteger('test_feature', 'lasers', 'user1', { test_attribute: 'test_value' }); + it('returns the variable default value from getFeatureVariableInteger', function() { + var result = optlyInstance.getFeatureVariableInteger('test_feature', 'lasers', 'user1', { + test_attribute: 'test_value', + }); assert.strictEqual(result, 400); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.INFO, 'OPTIMIZELY: Feature "test_feature" is not enabled for user user1. Returning default value for variable "lasers".'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.INFO, + 'OPTIMIZELY: Feature "test_feature" is not enabled for user user1. Returning default value for variable "lasers".' + ); }); - it('returns the variable default value from getFeatureVariableString', function () { - var result = optlyInstance.getFeatureVariableString('test_feature', 'message', 'user1', { test_attribute: 'test_value' }); + it('returns the variable default value from getFeatureVariableString', function() { + var result = optlyInstance.getFeatureVariableString('test_feature', 'message', 'user1', { + test_attribute: 'test_value', + }); assert.strictEqual(result, 'Hello'); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.INFO, 'OPTIMIZELY: Feature "test_feature" is not enabled for user user1. Returning default value for variable "message".'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.INFO, + 'OPTIMIZELY: Feature "test_feature" is not enabled for user user1. Returning default value for variable "message".' + ); }); }); }); - describe('not bucketed into an experiment or a rollout ', function () { - beforeEach(function () { + describe('not bucketed into an experiment or a rollout ', function() { + beforeEach(function() { sandbox.stub(optlyInstance.decisionService, 'getVariationForFeature').returns({ experiment: null, variation: null, @@ -4423,358 +5152,675 @@ describe('lib/optimizely', function () { }); }); - it('returns the variable default value from getFeatureVariable', function () { - var result = optlyInstance.getFeatureVariable('test_feature_for_experiment', 'is_button_animated', 'user1', { test_attribute: 'test_value' }); + it('returns the variable default value from getFeatureVariable', function() { + var result = optlyInstance.getFeatureVariable('test_feature_for_experiment', 'is_button_animated', 'user1', { + test_attribute: 'test_value', + }); assert.strictEqual(result, false); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.INFO, 'OPTIMIZELY: User "user1" is not in any variation or rollout rule. Returning default value for variable "is_button_animated" of feature flag "test_feature_for_experiment".'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.INFO, + 'OPTIMIZELY: User "user1" is not in any variation or rollout rule. Returning default value for variable "is_button_animated" of feature flag "test_feature_for_experiment".' + ); }); - it('returns the variable default value from getFeatureVariable', function () { - var result = optlyInstance.getFeatureVariable('test_feature_for_experiment', 'button_width', 'user1', { test_attribute: 'test_value' }); + it('returns the variable default value from getFeatureVariable', function() { + var result = optlyInstance.getFeatureVariable('test_feature_for_experiment', 'button_width', 'user1', { + test_attribute: 'test_value', + }); assert.strictEqual(result, 50.55); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.INFO, 'OPTIMIZELY: User "user1" is not in any variation or rollout rule. Returning default value for variable "button_width" of feature flag "test_feature_for_experiment".'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.INFO, + 'OPTIMIZELY: User "user1" is not in any variation or rollout rule. Returning default value for variable "button_width" of feature flag "test_feature_for_experiment".' + ); }); - it('returns the variable default value from getFeatureVariable', function () { - var result = optlyInstance.getFeatureVariable('test_feature_for_experiment', 'num_buttons', 'user1', { test_attribute: 'test_value' }); + it('returns the variable default value from getFeatureVariable', function() { + var result = optlyInstance.getFeatureVariable('test_feature_for_experiment', 'num_buttons', 'user1', { + test_attribute: 'test_value', + }); assert.strictEqual(result, 10); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.INFO, 'OPTIMIZELY: User "user1" is not in any variation or rollout rule. Returning default value for variable "num_buttons" of feature flag "test_feature_for_experiment".'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.INFO, + 'OPTIMIZELY: User "user1" is not in any variation or rollout rule. Returning default value for variable "num_buttons" of feature flag "test_feature_for_experiment".' + ); }); - it('returns the variable default value from getFeatureVariable', function () { - var result = optlyInstance.getFeatureVariable('test_feature_for_experiment', 'button_txt', 'user1', { test_attribute: 'test_value' }); + it('returns the variable default value from getFeatureVariable', function() { + var result = optlyInstance.getFeatureVariable('test_feature_for_experiment', 'button_txt', 'user1', { + test_attribute: 'test_value', + }); assert.strictEqual(result, 'Buy me'); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.INFO, 'OPTIMIZELY: User "user1" is not in any variation or rollout rule. Returning default value for variable "button_txt" of feature flag "test_feature_for_experiment".'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.INFO, + 'OPTIMIZELY: User "user1" is not in any variation or rollout rule. Returning default value for variable "button_txt" of feature flag "test_feature_for_experiment".' + ); }); - it('returns the variable default value from getFeatureVariableBoolean', function () { - var result = optlyInstance.getFeatureVariableBoolean('test_feature_for_experiment', 'is_button_animated', 'user1', { test_attribute: 'test_value' }); + it('returns the variable default value from getFeatureVariableBoolean', function() { + var result = optlyInstance.getFeatureVariableBoolean( + 'test_feature_for_experiment', + 'is_button_animated', + 'user1', + { test_attribute: 'test_value' } + ); assert.strictEqual(result, false); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.INFO, 'OPTIMIZELY: User "user1" is not in any variation or rollout rule. Returning default value for variable "is_button_animated" of feature flag "test_feature_for_experiment".'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.INFO, + 'OPTIMIZELY: User "user1" is not in any variation or rollout rule. Returning default value for variable "is_button_animated" of feature flag "test_feature_for_experiment".' + ); }); - it('returns the variable default value from getFeatureVariableDouble', function () { - var result = optlyInstance.getFeatureVariableDouble('test_feature_for_experiment', 'button_width', 'user1', { test_attribute: 'test_value' }); + it('returns the variable default value from getFeatureVariableDouble', function() { + var result = optlyInstance.getFeatureVariableDouble('test_feature_for_experiment', 'button_width', 'user1', { + test_attribute: 'test_value', + }); assert.strictEqual(result, 50.55); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.INFO, 'OPTIMIZELY: User "user1" is not in any variation or rollout rule. Returning default value for variable "button_width" of feature flag "test_feature_for_experiment".'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.INFO, + 'OPTIMIZELY: User "user1" is not in any variation or rollout rule. Returning default value for variable "button_width" of feature flag "test_feature_for_experiment".' + ); }); - it('returns the variable default value from getFeatureVariableInteger', function () { - var result = optlyInstance.getFeatureVariableInteger('test_feature_for_experiment', 'num_buttons', 'user1', { test_attribute: 'test_value' }); + it('returns the variable default value from getFeatureVariableInteger', function() { + var result = optlyInstance.getFeatureVariableInteger('test_feature_for_experiment', 'num_buttons', 'user1', { + test_attribute: 'test_value', + }); assert.strictEqual(result, 10); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.INFO, 'OPTIMIZELY: User "user1" is not in any variation or rollout rule. Returning default value for variable "num_buttons" of feature flag "test_feature_for_experiment".'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.INFO, + 'OPTIMIZELY: User "user1" is not in any variation or rollout rule. Returning default value for variable "num_buttons" of feature flag "test_feature_for_experiment".' + ); }); - it('returns the variable default value from getFeatureVariableString', function () { - var result = optlyInstance.getFeatureVariableString('test_feature_for_experiment', 'button_txt', 'user1', { test_attribute: 'test_value' }); + it('returns the variable default value from getFeatureVariableString', function() { + var result = optlyInstance.getFeatureVariableString('test_feature_for_experiment', 'button_txt', 'user1', { + test_attribute: 'test_value', + }); assert.strictEqual(result, 'Buy me'); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.INFO, 'OPTIMIZELY: User "user1" is not in any variation or rollout rule. Returning default value for variable "button_txt" of feature flag "test_feature_for_experiment".'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.INFO, + 'OPTIMIZELY: User "user1" is not in any variation or rollout rule. Returning default value for variable "button_txt" of feature flag "test_feature_for_experiment".' + ); }); }); - it('returns null from getFeatureVariable if user id is null', function () { - var result = optlyInstance.getFeatureVariable('test_feature_for_experiment', 'is_button_animated', null, { test_attribute: 'test_value' }); + it('returns null from getFeatureVariable if user id is null', function() { + var result = optlyInstance.getFeatureVariable('test_feature_for_experiment', 'is_button_animated', null, { + test_attribute: 'test_value', + }); assert.strictEqual(result, null); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.ERROR, 'OPTIMIZELY: Provided user_id is in an invalid format.'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.ERROR, + 'OPTIMIZELY: Provided user_id is in an invalid format.' + ); }); - it('returns null from getFeatureVariable if user id is undefined', function () { - var result = optlyInstance.getFeatureVariable('test_feature_for_experiment', 'is_button_animated', undefined, { test_attribute: 'test_value' }); + it('returns null from getFeatureVariable if user id is undefined', function() { + var result = optlyInstance.getFeatureVariable('test_feature_for_experiment', 'is_button_animated', undefined, { + test_attribute: 'test_value', + }); assert.strictEqual(result, null); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.ERROR, 'OPTIMIZELY: Provided user_id is in an invalid format.'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.ERROR, + 'OPTIMIZELY: Provided user_id is in an invalid format.' + ); }); - it('returns null from getFeatureVariable if user id is not provided', function () { + it('returns null from getFeatureVariable if user id is not provided', function() { var result = optlyInstance.getFeatureVariable('test_feature_for_experiment', 'is_button_animated'); assert.strictEqual(result, null); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.ERROR, 'OPTIMIZELY: Provided user_id is in an invalid format.'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.ERROR, + 'OPTIMIZELY: Provided user_id is in an invalid format.' + ); }); - it('returns null from getFeatureVariable if user id is null', function () { - var result = optlyInstance.getFeatureVariable('test_feature_for_experiment', 'button_width', null, { test_attribute: 'test_value' }); + it('returns null from getFeatureVariable if user id is null', function() { + var result = optlyInstance.getFeatureVariable('test_feature_for_experiment', 'button_width', null, { + test_attribute: 'test_value', + }); assert.strictEqual(result, null); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.ERROR, 'OPTIMIZELY: Provided user_id is in an invalid format.'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.ERROR, + 'OPTIMIZELY: Provided user_id is in an invalid format.' + ); }); - it('returns null from getFeatureVariable if user id is undefined', function () { - var result = optlyInstance.getFeatureVariable('test_feature_for_experiment', 'button_width', undefined, { test_attribute: 'test_value' }); + it('returns null from getFeatureVariable if user id is undefined', function() { + var result = optlyInstance.getFeatureVariable('test_feature_for_experiment', 'button_width', undefined, { + test_attribute: 'test_value', + }); assert.strictEqual(result, null); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.ERROR, 'OPTIMIZELY: Provided user_id is in an invalid format.'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.ERROR, + 'OPTIMIZELY: Provided user_id is in an invalid format.' + ); }); - it('returns null from getFeatureVariable if user id is not provided', function () { + it('returns null from getFeatureVariable if user id is not provided', function() { var result = optlyInstance.getFeatureVariable('test_feature_for_experiment', 'button_width'); assert.strictEqual(result, null); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.ERROR, 'OPTIMIZELY: Provided user_id is in an invalid format.'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.ERROR, + 'OPTIMIZELY: Provided user_id is in an invalid format.' + ); }); - it('returns null from getFeatureVariable if user id is null', function () { - var result = optlyInstance.getFeatureVariable('test_feature_for_experiment', 'num_buttons', null, { test_attribute: 'test_value' }); + it('returns null from getFeatureVariable if user id is null', function() { + var result = optlyInstance.getFeatureVariable('test_feature_for_experiment', 'num_buttons', null, { + test_attribute: 'test_value', + }); assert.strictEqual(result, null); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.ERROR, 'OPTIMIZELY: Provided user_id is in an invalid format.'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.ERROR, + 'OPTIMIZELY: Provided user_id is in an invalid format.' + ); }); - it('returns null from getFeatureVariable if user id is undefined', function () { - var result = optlyInstance.getFeatureVariable('test_feature_for_experiment', 'num_buttons', undefined, { test_attribute: 'test_value' }); + it('returns null from getFeatureVariable if user id is undefined', function() { + var result = optlyInstance.getFeatureVariable('test_feature_for_experiment', 'num_buttons', undefined, { + test_attribute: 'test_value', + }); assert.strictEqual(result, null); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.ERROR, 'OPTIMIZELY: Provided user_id is in an invalid format.'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.ERROR, + 'OPTIMIZELY: Provided user_id is in an invalid format.' + ); }); - it('returns null from getFeatureVariable if user id is not provided', function () { + it('returns null from getFeatureVariable if user id is not provided', function() { var result = optlyInstance.getFeatureVariable('test_feature_for_experiment', 'num_buttons'); assert.strictEqual(result, null); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.ERROR, 'OPTIMIZELY: Provided user_id is in an invalid format.'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.ERROR, + 'OPTIMIZELY: Provided user_id is in an invalid format.' + ); }); - it('returns null from getFeatureVariable if user id is null', function () { - var result = optlyInstance.getFeatureVariable('test_feature_for_experiment', 'button_txt', null, { test_attribute: 'test_value' }); + it('returns null from getFeatureVariable if user id is null', function() { + var result = optlyInstance.getFeatureVariable('test_feature_for_experiment', 'button_txt', null, { + test_attribute: 'test_value', + }); assert.strictEqual(result, null); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.ERROR, 'OPTIMIZELY: Provided user_id is in an invalid format.'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.ERROR, + 'OPTIMIZELY: Provided user_id is in an invalid format.' + ); }); - it('returns null from getFeatureVariable if user id is undefined', function () { - var result = optlyInstance.getFeatureVariable('test_feature_for_experiment', 'button_txt', undefined, { test_attribute: 'test_value' }); + it('returns null from getFeatureVariable if user id is undefined', function() { + var result = optlyInstance.getFeatureVariable('test_feature_for_experiment', 'button_txt', undefined, { + test_attribute: 'test_value', + }); assert.strictEqual(result, null); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.ERROR, 'OPTIMIZELY: Provided user_id is in an invalid format.'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.ERROR, + 'OPTIMIZELY: Provided user_id is in an invalid format.' + ); }); - it('returns null from getFeatureVariable if user id is not provided', function () { + it('returns null from getFeatureVariable if user id is not provided', function() { var result = optlyInstance.getFeatureVariable('test_feature_for_experiment', 'button_txt'); assert.strictEqual(result, null); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.ERROR, 'OPTIMIZELY: Provided user_id is in an invalid format.'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.ERROR, + 'OPTIMIZELY: Provided user_id is in an invalid format.' + ); }); - it('returns null from getFeatureVariableBoolean when called with a non-boolean variable', function () { + it('returns null from getFeatureVariableBoolean when called with a non-boolean variable', function() { var result = optlyInstance.getFeatureVariableBoolean('test_feature_for_experiment', 'button_width', 'user1'); assert.strictEqual(result, null); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.WARNING, 'OPTIMIZELY: Requested variable type "boolean", but variable is of type "double". Use correct API to retrieve value. Returning None.'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.WARNING, + 'OPTIMIZELY: Requested variable type "boolean", but variable is of type "double". Use correct API to retrieve value. Returning None.' + ); }); - it('returns null from getFeatureVariableDouble when called with a non-double variable', function () { - var result = optlyInstance.getFeatureVariableDouble('test_feature_for_experiment', 'is_button_animated', 'user1'); + it('returns null from getFeatureVariableDouble when called with a non-double variable', function() { + var result = optlyInstance.getFeatureVariableDouble( + 'test_feature_for_experiment', + 'is_button_animated', + 'user1' + ); assert.strictEqual(result, null); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.WARNING, 'OPTIMIZELY: Requested variable type "double", but variable is of type "boolean". Use correct API to retrieve value. Returning None.'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.WARNING, + 'OPTIMIZELY: Requested variable type "double", but variable is of type "boolean". Use correct API to retrieve value. Returning None.' + ); }); - it('returns null from getFeatureVariableInteger when called with a non-integer variable', function () { + it('returns null from getFeatureVariableInteger when called with a non-integer variable', function() { var result = optlyInstance.getFeatureVariableInteger('test_feature_for_experiment', 'button_width', 'user1'); assert.strictEqual(result, null); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.WARNING, 'OPTIMIZELY: Requested variable type "integer", but variable is of type "double". Use correct API to retrieve value. Returning None.'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.WARNING, + 'OPTIMIZELY: Requested variable type "integer", but variable is of type "double". Use correct API to retrieve value. Returning None.' + ); }); - it('returns null from getFeatureVariableString when called with a non-string variable', function () { + it('returns null from getFeatureVariableString when called with a non-string variable', function() { var result = optlyInstance.getFeatureVariableString('test_feature_for_experiment', 'num_buttons', 'user1'); assert.strictEqual(result, null); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.WARNING, 'OPTIMIZELY: Requested variable type "string", but variable is of type "integer". Use correct API to retrieve value. Returning None.'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.WARNING, + 'OPTIMIZELY: Requested variable type "string", but variable is of type "integer". Use correct API to retrieve value. Returning None.' + ); }); - it('returns null from getFeatureVariableBoolean if user id is null', function () { - var result = optlyInstance.getFeatureVariableBoolean('test_feature_for_experiment', 'is_button_animated', null, { test_attribute: 'test_value' }); + it('returns null from getFeatureVariableBoolean if user id is null', function() { + var result = optlyInstance.getFeatureVariableBoolean( + 'test_feature_for_experiment', + 'is_button_animated', + null, + { test_attribute: 'test_value' } + ); assert.strictEqual(result, null); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.ERROR, 'OPTIMIZELY: Provided user_id is in an invalid format.'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.ERROR, + 'OPTIMIZELY: Provided user_id is in an invalid format.' + ); }); - it('returns null from getFeatureVariableBoolean if user id is undefined', function () { - var result = optlyInstance.getFeatureVariableBoolean('test_feature_for_experiment', 'is_button_animated', undefined, { test_attribute: 'test_value' }); + it('returns null from getFeatureVariableBoolean if user id is undefined', function() { + var result = optlyInstance.getFeatureVariableBoolean( + 'test_feature_for_experiment', + 'is_button_animated', + undefined, + { test_attribute: 'test_value' } + ); assert.strictEqual(result, null); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.ERROR, 'OPTIMIZELY: Provided user_id is in an invalid format.'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.ERROR, + 'OPTIMIZELY: Provided user_id is in an invalid format.' + ); }); - it('returns null from getFeatureVariableBoolean if user id is not provided', function () { + it('returns null from getFeatureVariableBoolean if user id is not provided', function() { var result = optlyInstance.getFeatureVariableBoolean('test_feature_for_experiment', 'is_button_animated'); assert.strictEqual(result, null); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.ERROR, 'OPTIMIZELY: Provided user_id is in an invalid format.'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.ERROR, + 'OPTIMIZELY: Provided user_id is in an invalid format.' + ); }); - it('returns null from getFeatureVariableDouble if user id is null', function () { - var result = optlyInstance.getFeatureVariableDouble('test_feature_for_experiment', 'button_width', null, { test_attribute: 'test_value' }); + it('returns null from getFeatureVariableDouble if user id is null', function() { + var result = optlyInstance.getFeatureVariableDouble('test_feature_for_experiment', 'button_width', null, { + test_attribute: 'test_value', + }); assert.strictEqual(result, null); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.ERROR, 'OPTIMIZELY: Provided user_id is in an invalid format.'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.ERROR, + 'OPTIMIZELY: Provided user_id is in an invalid format.' + ); }); - it('returns null from getFeatureVariableDouble if user id is undefined', function () { - var result = optlyInstance.getFeatureVariableDouble('test_feature_for_experiment', 'button_width', undefined, { test_attribute: 'test_value' }); + it('returns null from getFeatureVariableDouble if user id is undefined', function() { + var result = optlyInstance.getFeatureVariableDouble('test_feature_for_experiment', 'button_width', undefined, { + test_attribute: 'test_value', + }); assert.strictEqual(result, null); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.ERROR, 'OPTIMIZELY: Provided user_id is in an invalid format.'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.ERROR, + 'OPTIMIZELY: Provided user_id is in an invalid format.' + ); }); - it('returns null from getFeatureVariableDouble if user id is not provided', function () { + it('returns null from getFeatureVariableDouble if user id is not provided', function() { var result = optlyInstance.getFeatureVariableDouble('test_feature_for_experiment', 'button_width'); assert.strictEqual(result, null); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.ERROR, 'OPTIMIZELY: Provided user_id is in an invalid format.'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.ERROR, + 'OPTIMIZELY: Provided user_id is in an invalid format.' + ); }); - it('returns null from getFeatureVariableInteger if user id is null', function () { - var result = optlyInstance.getFeatureVariableInteger('test_feature_for_experiment', 'num_buttons', null, { test_attribute: 'test_value' }); + it('returns null from getFeatureVariableInteger if user id is null', function() { + var result = optlyInstance.getFeatureVariableInteger('test_feature_for_experiment', 'num_buttons', null, { + test_attribute: 'test_value', + }); assert.strictEqual(result, null); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.ERROR, 'OPTIMIZELY: Provided user_id is in an invalid format.'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.ERROR, + 'OPTIMIZELY: Provided user_id is in an invalid format.' + ); }); - it('returns null from getFeatureVariableInteger if user id is undefined', function () { - var result = optlyInstance.getFeatureVariableInteger('test_feature_for_experiment', 'num_buttons', undefined, { test_attribute: 'test_value' }); + it('returns null from getFeatureVariableInteger if user id is undefined', function() { + var result = optlyInstance.getFeatureVariableInteger('test_feature_for_experiment', 'num_buttons', undefined, { + test_attribute: 'test_value', + }); assert.strictEqual(result, null); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.ERROR, 'OPTIMIZELY: Provided user_id is in an invalid format.'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.ERROR, + 'OPTIMIZELY: Provided user_id is in an invalid format.' + ); }); - it('returns null from getFeatureVariableInteger if user id is not provided', function () { + it('returns null from getFeatureVariableInteger if user id is not provided', function() { var result = optlyInstance.getFeatureVariableInteger('test_feature_for_experiment', 'num_buttons'); assert.strictEqual(result, null); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.ERROR, 'OPTIMIZELY: Provided user_id is in an invalid format.'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.ERROR, + 'OPTIMIZELY: Provided user_id is in an invalid format.' + ); }); - it('returns null from getFeatureVariableString if user id is null', function () { - var result = optlyInstance.getFeatureVariableString('test_feature_for_experiment', 'button_txt', null, { test_attribute: 'test_value' }); + it('returns null from getFeatureVariableString if user id is null', function() { + var result = optlyInstance.getFeatureVariableString('test_feature_for_experiment', 'button_txt', null, { + test_attribute: 'test_value', + }); assert.strictEqual(result, null); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.ERROR, 'OPTIMIZELY: Provided user_id is in an invalid format.'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.ERROR, + 'OPTIMIZELY: Provided user_id is in an invalid format.' + ); }); - it('returns null from getFeatureVariableString if user id is undefined', function () { - var result = optlyInstance.getFeatureVariableString('test_feature_for_experiment', 'button_txt', undefined, { test_attribute: 'test_value' }); + it('returns null from getFeatureVariableString if user id is undefined', function() { + var result = optlyInstance.getFeatureVariableString('test_feature_for_experiment', 'button_txt', undefined, { + test_attribute: 'test_value', + }); assert.strictEqual(result, null); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.ERROR, 'OPTIMIZELY: Provided user_id is in an invalid format.'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.ERROR, + 'OPTIMIZELY: Provided user_id is in an invalid format.' + ); }); - it('returns null from getFeatureVariableString if user id is not provided', function () { + it('returns null from getFeatureVariableString if user id is not provided', function() { var result = optlyInstance.getFeatureVariableString('test_feature_for_experiment', 'button_txt'); assert.strictEqual(result, null); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.ERROR, 'OPTIMIZELY: Provided user_id is in an invalid format.'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.ERROR, + 'OPTIMIZELY: Provided user_id is in an invalid format.' + ); }); - describe('type casting failures', function () { - describe('invalid boolean', function () { - beforeEach(function () { + describe('type casting failures', function() { + describe('invalid boolean', function() { + beforeEach(function() { sandbox.stub(projectConfig, 'getVariableValueForVariation').returns('falsezzz'); }); - it('should return null and log an error', function () { - var result = optlyInstance.getFeatureVariableBoolean('test_feature_for_experiment', 'is_button_animated', 'user1'); + it('should return null and log an error', function() { + var result = optlyInstance.getFeatureVariableBoolean( + 'test_feature_for_experiment', + 'is_button_animated', + 'user1' + ); assert.strictEqual(result, null); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.ERROR, 'PROJECT_CONFIG: Unable to cast value falsezzz to type boolean, returning null.'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.ERROR, + 'PROJECT_CONFIG: Unable to cast value falsezzz to type boolean, returning null.' + ); }); }); - describe('invalid integer', function () { - beforeEach(function () { + describe('invalid integer', function() { + beforeEach(function() { sandbox.stub(projectConfig, 'getVariableValueForVariation').returns('zzz123'); }); - it('should return null and log an error', function () { + it('should return null and log an error', function() { var result = optlyInstance.getFeatureVariableInteger('test_feature_for_experiment', 'num_buttons', 'user1'); assert.strictEqual(result, null); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.ERROR, 'PROJECT_CONFIG: Unable to cast value zzz123 to type integer, returning null.'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.ERROR, + 'PROJECT_CONFIG: Unable to cast value zzz123 to type integer, returning null.' + ); }); }); - describe('invalid double', function () { - beforeEach(function () { + describe('invalid double', function() { + beforeEach(function() { sandbox.stub(projectConfig, 'getVariableValueForVariation').returns('zzz44.55'); }); - it('should return null and log an error', function () { + it('should return null and log an error', function() { var result = optlyInstance.getFeatureVariableDouble('test_feature_for_experiment', 'button_width', 'user1'); assert.strictEqual(result, null); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.ERROR, 'PROJECT_CONFIG: Unable to cast value zzz44.55 to type double, returning null.'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.ERROR, + 'PROJECT_CONFIG: Unable to cast value zzz44.55 to type double, returning null.' + ); }); }); }); - it('returns null from getFeatureVariable if the argument feature key is invalid', function () { + it('returns null from getFeatureVariable if the argument feature key is invalid', function() { var result = optlyInstance.getFeatureVariable('thisIsNotAValidKey<><><>', 'is_button_animated', 'user1'); assert.strictEqual(result, null); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.ERROR, 'PROJECT_CONFIG: Feature key thisIsNotAValidKey<><><> is not in datafile.'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.ERROR, + 'PROJECT_CONFIG: Feature key thisIsNotAValidKey<><><> is not in datafile.' + ); }); - it('returns null from getFeatureVariable if the argument feature key is invalid', function () { + it('returns null from getFeatureVariable if the argument feature key is invalid', function() { var result = optlyInstance.getFeatureVariable('thisIsNotAValidKey<><><>', 'button_width', 'user1'); assert.strictEqual(result, null); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.ERROR, 'PROJECT_CONFIG: Feature key thisIsNotAValidKey<><><> is not in datafile.'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.ERROR, + 'PROJECT_CONFIG: Feature key thisIsNotAValidKey<><><> is not in datafile.' + ); }); - it('returns null from getFeatureVariable if the argument feature key is invalid', function () { + it('returns null from getFeatureVariable if the argument feature key is invalid', function() { var result = optlyInstance.getFeatureVariable('thisIsNotAValidKey<><><>', 'num_buttons', 'user1'); assert.strictEqual(result, null); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.ERROR, 'PROJECT_CONFIG: Feature key thisIsNotAValidKey<><><> is not in datafile.'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.ERROR, + 'PROJECT_CONFIG: Feature key thisIsNotAValidKey<><><> is not in datafile.' + ); }); - it('returns null from getFeatureVariable if the argument feature key is invalid', function () { + it('returns null from getFeatureVariable if the argument feature key is invalid', function() { var result = optlyInstance.getFeatureVariable('thisIsNotAValidKey<><><>', 'button_txt', 'user1'); assert.strictEqual(result, null); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.ERROR, 'PROJECT_CONFIG: Feature key thisIsNotAValidKey<><><> is not in datafile.'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.ERROR, + 'PROJECT_CONFIG: Feature key thisIsNotAValidKey<><><> is not in datafile.' + ); }); - it('returns null from getFeatureVariable if the argument variable key is invalid', function () { - var result = optlyInstance.getFeatureVariable('test_feature_for_experiment', 'thisIsNotAVariableKey****', 'user1'); + it('returns null from getFeatureVariable if the argument variable key is invalid', function() { + var result = optlyInstance.getFeatureVariable( + 'test_feature_for_experiment', + 'thisIsNotAVariableKey****', + 'user1' + ); assert.strictEqual(result, null); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.ERROR, 'PROJECT_CONFIG: Variable with key "thisIsNotAVariableKey****" associated with feature with key "test_feature_for_experiment" is not in datafile.'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.ERROR, + 'PROJECT_CONFIG: Variable with key "thisIsNotAVariableKey****" associated with feature with key "test_feature_for_experiment" is not in datafile.' + ); }); - it('returns null from getFeatureVariable if the argument variable key is invalid', function () { - var result = optlyInstance.getFeatureVariable('test_feature_for_experiment', 'thisIsNotAVariableKey****', 'user1'); + it('returns null from getFeatureVariable if the argument variable key is invalid', function() { + var result = optlyInstance.getFeatureVariable( + 'test_feature_for_experiment', + 'thisIsNotAVariableKey****', + 'user1' + ); assert.strictEqual(result, null); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.ERROR, 'PROJECT_CONFIG: Variable with key "thisIsNotAVariableKey****" associated with feature with key "test_feature_for_experiment" is not in datafile.'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.ERROR, + 'PROJECT_CONFIG: Variable with key "thisIsNotAVariableKey****" associated with feature with key "test_feature_for_experiment" is not in datafile.' + ); }); - it('returns null from getFeatureVariable if the argument variable key is invalid', function () { - var result = optlyInstance.getFeatureVariable('test_feature_for_experiment', 'thisIsNotAVariableKey****', 'user1'); + it('returns null from getFeatureVariable if the argument variable key is invalid', function() { + var result = optlyInstance.getFeatureVariable( + 'test_feature_for_experiment', + 'thisIsNotAVariableKey****', + 'user1' + ); assert.strictEqual(result, null); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.ERROR, 'PROJECT_CONFIG: Variable with key "thisIsNotAVariableKey****" associated with feature with key "test_feature_for_experiment" is not in datafile.'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.ERROR, + 'PROJECT_CONFIG: Variable with key "thisIsNotAVariableKey****" associated with feature with key "test_feature_for_experiment" is not in datafile.' + ); }); - it('returns null from getFeatureVariable if the argument variable key is invalid', function () { - var result = optlyInstance.getFeatureVariable('test_feature_for_experiment', 'thisIsNotAVariableKey****', 'user1'); + it('returns null from getFeatureVariable if the argument variable key is invalid', function() { + var result = optlyInstance.getFeatureVariable( + 'test_feature_for_experiment', + 'thisIsNotAVariableKey****', + 'user1' + ); assert.strictEqual(result, null); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.ERROR, 'PROJECT_CONFIG: Variable with key "thisIsNotAVariableKey****" associated with feature with key "test_feature_for_experiment" is not in datafile.'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.ERROR, + 'PROJECT_CONFIG: Variable with key "thisIsNotAVariableKey****" associated with feature with key "test_feature_for_experiment" is not in datafile.' + ); }); - it('returns null from getFeatureVariableBoolean if the argument feature key is invalid', function () { + it('returns null from getFeatureVariableBoolean if the argument feature key is invalid', function() { var result = optlyInstance.getFeatureVariableBoolean('thisIsNotAValidKey<><><>', 'is_button_animated', 'user1'); assert.strictEqual(result, null); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.ERROR, 'PROJECT_CONFIG: Feature key thisIsNotAValidKey<><><> is not in datafile.'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.ERROR, + 'PROJECT_CONFIG: Feature key thisIsNotAValidKey<><><> is not in datafile.' + ); }); - it('returns null from getFeatureVariableDouble if the argument feature key is invalid', function () { + it('returns null from getFeatureVariableDouble if the argument feature key is invalid', function() { var result = optlyInstance.getFeatureVariableDouble('thisIsNotAValidKey<><><>', 'button_width', 'user1'); assert.strictEqual(result, null); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.ERROR, 'PROJECT_CONFIG: Feature key thisIsNotAValidKey<><><> is not in datafile.'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.ERROR, + 'PROJECT_CONFIG: Feature key thisIsNotAValidKey<><><> is not in datafile.' + ); }); - it('returns null from getFeatureVariableInteger if the argument feature key is invalid', function () { + it('returns null from getFeatureVariableInteger if the argument feature key is invalid', function() { var result = optlyInstance.getFeatureVariableInteger('thisIsNotAValidKey<><><>', 'num_buttons', 'user1'); assert.strictEqual(result, null); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.ERROR, 'PROJECT_CONFIG: Feature key thisIsNotAValidKey<><><> is not in datafile.'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.ERROR, + 'PROJECT_CONFIG: Feature key thisIsNotAValidKey<><><> is not in datafile.' + ); }); - it('returns null from getFeatureVariableString if the argument feature key is invalid', function () { + it('returns null from getFeatureVariableString if the argument feature key is invalid', function() { var result = optlyInstance.getFeatureVariableString('thisIsNotAValidKey<><><>', 'button_txt', 'user1'); assert.strictEqual(result, null); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.ERROR, 'PROJECT_CONFIG: Feature key thisIsNotAValidKey<><><> is not in datafile.'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.ERROR, + 'PROJECT_CONFIG: Feature key thisIsNotAValidKey<><><> is not in datafile.' + ); }); - it('returns null from getFeatureVariableBoolean if the argument variable key is invalid', function () { - var result = optlyInstance.getFeatureVariableBoolean('test_feature_for_experiment', 'thisIsNotAVariableKey****', 'user1'); + it('returns null from getFeatureVariableBoolean if the argument variable key is invalid', function() { + var result = optlyInstance.getFeatureVariableBoolean( + 'test_feature_for_experiment', + 'thisIsNotAVariableKey****', + 'user1' + ); assert.strictEqual(result, null); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.ERROR, 'PROJECT_CONFIG: Variable with key "thisIsNotAVariableKey****" associated with feature with key "test_feature_for_experiment" is not in datafile.'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.ERROR, + 'PROJECT_CONFIG: Variable with key "thisIsNotAVariableKey****" associated with feature with key "test_feature_for_experiment" is not in datafile.' + ); }); - it('returns null from getFeatureVariableDouble if the argument variable key is invalid', function () { - var result = optlyInstance.getFeatureVariableDouble('test_feature_for_experiment', 'thisIsNotAVariableKey****', 'user1'); + it('returns null from getFeatureVariableDouble if the argument variable key is invalid', function() { + var result = optlyInstance.getFeatureVariableDouble( + 'test_feature_for_experiment', + 'thisIsNotAVariableKey****', + 'user1' + ); assert.strictEqual(result, null); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.ERROR, 'PROJECT_CONFIG: Variable with key "thisIsNotAVariableKey****" associated with feature with key "test_feature_for_experiment" is not in datafile.'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.ERROR, + 'PROJECT_CONFIG: Variable with key "thisIsNotAVariableKey****" associated with feature with key "test_feature_for_experiment" is not in datafile.' + ); }); - it('returns null from getFeatureVariableInteger if the argument variable key is invalid', function () { - var result = optlyInstance.getFeatureVariableInteger('test_feature_for_experiment', 'thisIsNotAVariableKey****', 'user1'); + it('returns null from getFeatureVariableInteger if the argument variable key is invalid', function() { + var result = optlyInstance.getFeatureVariableInteger( + 'test_feature_for_experiment', + 'thisIsNotAVariableKey****', + 'user1' + ); assert.strictEqual(result, null); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.ERROR, 'PROJECT_CONFIG: Variable with key "thisIsNotAVariableKey****" associated with feature with key "test_feature_for_experiment" is not in datafile.'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.ERROR, + 'PROJECT_CONFIG: Variable with key "thisIsNotAVariableKey****" associated with feature with key "test_feature_for_experiment" is not in datafile.' + ); }); - it('returns null from getFeatureVariableString if the argument variable key is invalid', function () { - var result = optlyInstance.getFeatureVariableString('test_feature_for_experiment', 'thisIsNotAVariableKey****', 'user1'); + it('returns null from getFeatureVariableString if the argument variable key is invalid', function() { + var result = optlyInstance.getFeatureVariableString( + 'test_feature_for_experiment', + 'thisIsNotAVariableKey****', + 'user1' + ); assert.strictEqual(result, null); - sinon.assert.calledWith(createdLogger.log, LOG_LEVEL.ERROR, 'PROJECT_CONFIG: Variable with key "thisIsNotAVariableKey****" associated with feature with key "test_feature_for_experiment" is not in datafile.'); + sinon.assert.calledWith( + createdLogger.log, + LOG_LEVEL.ERROR, + 'PROJECT_CONFIG: Variable with key "thisIsNotAVariableKey****" associated with feature with key "test_feature_for_experiment" is not in datafile.' + ); }); - it('returns null from getFeatureVariable when optimizely object is not a valid instance', function () { + it('returns null from getFeatureVariable when optimizely object is not a valid instance', function() { var instance = new Optimizely({ datafile: {}, errorHandler: errorHandler, @@ -4791,7 +5837,7 @@ describe('lib/optimizely', function () { assert.strictEqual(logMessage, sprintf(LOG_MESSAGES.INVALID_OBJECT, 'OPTIMIZELY', 'getFeatureVariable')); }); - it('returns null from getFeatureVariableBoolean when optimizely object is not a valid instance', function () { + it('returns null from getFeatureVariableBoolean when optimizely object is not a valid instance', function() { var instance = new Optimizely({ datafile: {}, errorHandler: errorHandler, @@ -4808,7 +5854,7 @@ describe('lib/optimizely', function () { assert.strictEqual(logMessage, sprintf(LOG_MESSAGES.INVALID_OBJECT, 'OPTIMIZELY', 'getFeatureVariableBoolean')); }); - it('returns null from getFeatureVariable when optimizely object is not a valid instance', function () { + it('returns null from getFeatureVariable when optimizely object is not a valid instance', function() { var instance = new Optimizely({ datafile: {}, errorHandler: errorHandler, @@ -4825,7 +5871,7 @@ describe('lib/optimizely', function () { assert.strictEqual(logMessage, sprintf(LOG_MESSAGES.INVALID_OBJECT, 'OPTIMIZELY', 'getFeatureVariable')); }); - it('returns null from getFeatureVariableDouble when optimizely object is not a valid instance', function () { + it('returns null from getFeatureVariableDouble when optimizely object is not a valid instance', function() { var instance = new Optimizely({ datafile: {}, errorHandler: errorHandler, @@ -4842,7 +5888,7 @@ describe('lib/optimizely', function () { assert.strictEqual(logMessage, sprintf(LOG_MESSAGES.INVALID_OBJECT, 'OPTIMIZELY', 'getFeatureVariableDouble')); }); - it('returns null from getFeatureVariable when optimizely object is not a valid instance', function () { + it('returns null from getFeatureVariable when optimizely object is not a valid instance', function() { var instance = new Optimizely({ datafile: {}, errorHandler: errorHandler, @@ -4859,7 +5905,7 @@ describe('lib/optimizely', function () { assert.strictEqual(logMessage, sprintf(LOG_MESSAGES.INVALID_OBJECT, 'OPTIMIZELY', 'getFeatureVariable')); }); - it('returns null from getFeatureVariableInteger when optimizely object is not a valid instance', function () { + it('returns null from getFeatureVariableInteger when optimizely object is not a valid instance', function() { var instance = new Optimizely({ datafile: {}, errorHandler: errorHandler, @@ -4876,7 +5922,7 @@ describe('lib/optimizely', function () { assert.strictEqual(logMessage, sprintf(LOG_MESSAGES.INVALID_OBJECT, 'OPTIMIZELY', 'getFeatureVariableInteger')); }); - it('returns null from getFeatureVariable when optimizely object is not a valid instance', function () { + it('returns null from getFeatureVariable when optimizely object is not a valid instance', function() { var instance = new Optimizely({ datafile: {}, errorHandler: errorHandler, @@ -4893,7 +5939,7 @@ describe('lib/optimizely', function () { assert.strictEqual(logMessage, sprintf(LOG_MESSAGES.INVALID_OBJECT, 'OPTIMIZELY', 'getFeatureVariable')); }); - it('returns null from getFeatureVariableString when optimizely object is not a valid instance', function () { + it('returns null from getFeatureVariableString when optimizely object is not a valid instance', function() { var instance = new Optimizely({ datafile: {}, errorHandler: errorHandler, @@ -4912,14 +5958,14 @@ describe('lib/optimizely', function () { }); }); - describe('audience match types', function () { + describe('audience match types', function() { var sandbox = sinon.sandbox.create(); var createdLogger = logger.createLogger({ logLevel: LOG_LEVEL.INFO, logToConsole: false, }); var optlyInstance; - beforeEach(function () { + beforeEach(function() { optlyInstance = new Optimizely({ clientEngine: 'node-sdk', datafile: testData.getTypedAudiencesConfig(), @@ -4937,21 +5983,20 @@ describe('lib/optimizely', function () { sandbox.stub(createdLogger, 'log'); }); - afterEach(function () { + afterEach(function() { sandbox.restore(); }); - it('can activate an experiment with a typed audience', function () { + it('can activate an experiment with a typed audience', function() { var variationKey = optlyInstance.activate('typed_audience_experiment', 'user1', { // Should be included via exact match string audience with id '3468206642' house: 'Gryffindor', }); assert.strictEqual(variationKey, 'A'); sinon.assert.calledOnce(eventDispatcher.dispatchEvent); - assert.includeDeepMembers( - eventDispatcher.dispatchEvent.getCall(0).args[0].params.visitors[0].attributes, - [{ entity_id: '594015', key: 'house', type: 'custom', value: 'Gryffindor' }] - ); + assert.includeDeepMembers(eventDispatcher.dispatchEvent.getCall(0).args[0].params.visitors[0].attributes, [ + { entity_id: '594015', key: 'house', type: 'custom', value: 'Gryffindor' }, + ]); variationKey = optlyInstance.activate('typed_audience_experiment', 'user1', { // Should be included via exact match number audience with id '3468206646' @@ -4959,13 +6004,12 @@ describe('lib/optimizely', function () { }); assert.strictEqual(variationKey, 'A'); sinon.assert.calledTwice(eventDispatcher.dispatchEvent); - assert.includeDeepMembers( - eventDispatcher.dispatchEvent.getCall(1).args[0].params.visitors[0].attributes, - [{ entity_id: '594016', key: 'lasers', type: 'custom', value: 45.5 }] - ); + assert.includeDeepMembers(eventDispatcher.dispatchEvent.getCall(1).args[0].params.visitors[0].attributes, [ + { entity_id: '594016', key: 'lasers', type: 'custom', value: 45.5 }, + ]); }); - it('can exclude a user from an experiment with a typed audience via activate', function () { + it('can exclude a user from an experiment with a typed audience via activate', function() { var variationKey = optlyInstance.activate('typed_audience_experiment', 'user1', { house: 'Hufflepuff', }); @@ -4973,19 +6017,18 @@ describe('lib/optimizely', function () { sinon.assert.notCalled(eventDispatcher.dispatchEvent); }); - it('can track an experiment with a typed audience', function () { + it('can track an experiment with a typed audience', function() { optlyInstance.track('item_bought', 'user1', { // Should be included via substring match string audience with id '3988293898' house: 'Welcome to Slytherin!', }); sinon.assert.calledOnce(eventDispatcher.dispatchEvent); - assert.includeDeepMembers( - eventDispatcher.dispatchEvent.getCall(0).args[0].params.visitors[0].attributes, - [{ entity_id: '594015', key: 'house', type: 'custom', value: 'Welcome to Slytherin!' }] - ); + assert.includeDeepMembers(eventDispatcher.dispatchEvent.getCall(0).args[0].params.visitors[0].attributes, [ + { entity_id: '594015', key: 'house', type: 'custom', value: 'Welcome to Slytherin!' }, + ]); }); - it('can include a user in a rollout with a typed audience via isFeatureEnabled', function () { + it('can include a user in a rollout with a typed audience via isFeatureEnabled', function() { var featureEnabled = optlyInstance.isFeatureEnabled('feat', 'user1', { // Should be included via exists match audience with id '3988293899' favorite_ice_cream: 'chocolate', @@ -4999,12 +6042,12 @@ describe('lib/optimizely', function () { assert.isTrue(featureEnabled); }); - it('can exclude a user from a rollout with a typed audience via isFeatureEnabled', function () { + it('can exclude a user from a rollout with a typed audience via isFeatureEnabled', function() { var featureEnabled = optlyInstance.isFeatureEnabled('feat', 'user1', {}); assert.isFalse(featureEnabled); }); - it('can return a variable value from a feature test with a typed audience via getFeatureVariable', function () { + it('can return a variable value from a feature test with a typed audience via getFeatureVariable', function() { var variableValue = optlyInstance.getFeatureVariable('feat_with_var', 'x', 'user1', { // Should be included in the feature test via greater-than match audience with id '3468206647' lasers: 71, @@ -5018,7 +6061,7 @@ describe('lib/optimizely', function () { assert.strictEqual(variableValue, 'xyz'); }); - it('can return a variable value from a feature test with a typed audience via getFeatureVariableString', function () { + it('can return a variable value from a feature test with a typed audience via getFeatureVariableString', function() { var variableValue = optlyInstance.getFeatureVariableString('feat_with_var', 'x', 'user1', { // Should be included in the feature test via greater-than match audience with id '3468206647' lasers: 71, @@ -5032,14 +6075,14 @@ describe('lib/optimizely', function () { assert.strictEqual(variableValue, 'xyz'); }); - it('can return the default value from a feature variable from getFeatureVariable, via excluding a user from a feature test with a typed audience', function () { + it('can return the default value from a feature variable from getFeatureVariable, via excluding a user from a feature test with a typed audience', function() { var variableValue = optlyInstance.getFeatureVariable('feat_with_var', 'x', 'user1', { lasers: 50, }); assert.strictEqual(variableValue, 'x'); }); - it('can return the default value from a feature variable from getFeatureVariableString, via excluding a user from a feature test with a typed audience', function () { + it('can return the default value from a feature variable from getFeatureVariableString, via excluding a user from a feature test with a typed audience', function() { var variableValue = optlyInstance.getFeatureVariableString('feat_with_var', 'x', 'user1', { lasers: 50, }); @@ -5047,7 +6090,7 @@ describe('lib/optimizely', function () { }); }); - describe('audience combinations', function () { + describe('audience combinations', function() { var sandbox = sinon.sandbox.create(); var createdLogger = logger.createLogger({ logLevel: LOG_LEVEL.INFO, @@ -5055,7 +6098,7 @@ describe('lib/optimizely', function () { }); var optlyInstance; var audienceEvaluator; - beforeEach(function () { + beforeEach(function() { optlyInstance = new Optimizely({ clientEngine: 'node-sdk', datafile: testData.getTypedAudiencesConfig(), @@ -5075,11 +6118,11 @@ describe('lib/optimizely', function () { sandbox.spy(audienceEvaluator, 'evaluate'); }); - afterEach(function () { + afterEach(function() { sandbox.restore(); }); - it('can activate an experiment with complex audience conditions', function () { + it('can activate an experiment with complex audience conditions', function() { var variationKey = optlyInstance.activate('audience_combinations_experiment', 'user1', { // Should be included via substring match string audience with id '3988293898', and // exact match number audience with id '3468206646' @@ -5088,13 +6131,10 @@ describe('lib/optimizely', function () { }); assert.strictEqual(variationKey, 'A'); sinon.assert.calledOnce(eventDispatcher.dispatchEvent); - assert.includeDeepMembers( - eventDispatcher.dispatchEvent.getCall(0).args[0].params.visitors[0].attributes, - [ - { entity_id: '594015', key: 'house', type: 'custom', value: 'Welcome to Slytherin!' }, - { entity_id: '594016', key: 'lasers', type: 'custom', value: 45.5 }, - ] - ); + assert.includeDeepMembers(eventDispatcher.dispatchEvent.getCall(0).args[0].params.visitors[0].attributes, [ + { entity_id: '594015', key: 'house', type: 'custom', value: 'Welcome to Slytherin!' }, + { entity_id: '594016', key: 'lasers', type: 'custom', value: 45.5 }, + ]); sinon.assert.calledWithExactly( audienceEvaluator.evaluate, optlyInstance.projectConfigManager.getConfig().experiments[2].audienceConditions, @@ -5103,7 +6143,7 @@ describe('lib/optimizely', function () { ); }); - it('can exclude a user from an experiment with complex audience conditions', function () { + it('can exclude a user from an experiment with complex audience conditions', function() { var variationKey = optlyInstance.activate('audience_combinations_experiment', 'user1', { // Should be excluded - substring string audience with id '3988293898' does not match, // so the overall conditions fail @@ -5120,7 +6160,7 @@ describe('lib/optimizely', function () { ); }); - it('can track an experiment with complex audience conditions', function () { + it('can track an experiment with complex audience conditions', function() { optlyInstance.track('user_signed_up', 'user1', { // Should be included via exact match string audience with id '3468206642', and // exact match boolean audience with id '3468206643' @@ -5128,16 +6168,13 @@ describe('lib/optimizely', function () { should_do_it: true, }); sinon.assert.calledOnce(eventDispatcher.dispatchEvent); - assert.includeDeepMembers( - eventDispatcher.dispatchEvent.getCall(0).args[0].params.visitors[0].attributes, - [ - { entity_id: '594015', key: 'house', type: 'custom', value: 'Gryffindor' }, - { entity_id: '594017', key: 'should_do_it', type: 'custom', value: true } - ] - ); + assert.includeDeepMembers(eventDispatcher.dispatchEvent.getCall(0).args[0].params.visitors[0].attributes, [ + { entity_id: '594015', key: 'house', type: 'custom', value: 'Gryffindor' }, + { entity_id: '594017', key: 'should_do_it', type: 'custom', value: true }, + ]); }); - it('can include a user in a rollout with complex audience conditions via isFeatureEnabled', function () { + it('can include a user in a rollout with complex audience conditions via isFeatureEnabled', function() { var featureEnabled = optlyInstance.isFeatureEnabled('feat2', 'user1', { // Should be included via substring match string audience with id '3988293898', and // exists audience with id '3988293899' @@ -5153,7 +6190,7 @@ describe('lib/optimizely', function () { ); }); - it('can exclude a user from a rollout with complex audience conditions via isFeatureEnabled', function () { + it('can exclude a user from a rollout with complex audience conditions via isFeatureEnabled', function() { var featureEnabled = optlyInstance.isFeatureEnabled('feat2', 'user1', { // Should be excluded - substring match string audience with id '3988293898' does not match, // and no audience in the other branch of the 'and' matches either @@ -5168,7 +6205,7 @@ describe('lib/optimizely', function () { ); }); - it('can return a variable value from a feature test with complex audience conditions via getFeatureVariableString', function () { + it('can return a variable value from a feature test with complex audience conditions via getFeatureVariableString', function() { var variableValue = optlyInstance.getFeatureVariableInteger('feat2_with_var', 'z', 'user1', { // Should be included via exact match string audience with id '3468206642', and // greater than audience with id '3468206647' @@ -5184,7 +6221,7 @@ describe('lib/optimizely', function () { ); }); - it('can return a variable value from a feature test with complex audience conditions via getFeatureVariable', function () { + it('can return a variable value from a feature test with complex audience conditions via getFeatureVariable', function() { var variableValue = optlyInstance.getFeatureVariable('feat2_with_var', 'z', 'user1', { // Should be included via exact match string audience with id '3468206642', and // greater than audience with id '3468206647' @@ -5200,7 +6237,7 @@ describe('lib/optimizely', function () { ); }); - it('can return the default value for a feature variable from getFeatureVariable, via excluding a user from a feature test with complex audience conditions', function () { + it('can return the default value for a feature variable from getFeatureVariable, via excluding a user from a feature test with complex audience conditions', function() { var variableValue = optlyInstance.getFeatureVariable('feat2_with_var', 'z', 'user1', { // Should be excluded - no audiences match with no attributes }); @@ -5213,7 +6250,7 @@ describe('lib/optimizely', function () { ); }); - it('can return the default value for a feature variable from getFeatureVariableString, via excluding a user from a feature test with complex audience conditions', function () { + it('can return the default value for a feature variable from getFeatureVariableString, via excluding a user from a feature test with complex audience conditions', function() { var variableValue = optlyInstance.getFeatureVariableInteger('feat2_with_var', 'z', 'user1', { // Should be excluded - no audiences match with no attributes }); @@ -5227,7 +6264,7 @@ describe('lib/optimizely', function () { }); }); - describe('event batching', function () { + describe('event batching', function() { var bucketStub; var clock; @@ -5236,7 +6273,7 @@ describe('lib/optimizely', function () { logToConsole: false, }); - beforeEach(function () { + beforeEach(function() { bucketStub = sinon.stub(bucketer, 'bucket'); sinon.stub(eventDispatcher, 'dispatchEvent'); sinon.stub(errorHandler, 'handleError'); @@ -5246,7 +6283,7 @@ describe('lib/optimizely', function () { clock = sinon.useFakeTimers(new Date().getTime()); }); - afterEach(function () { + afterEach(function() { bucketer.bucket.restore(); eventDispatcher.dispatchEvent.restore(); errorHandler.handleError.restore(); @@ -5255,10 +6292,10 @@ describe('lib/optimizely', function () { uuid.v4.restore(); }); - describe('when eventBatchSize = 3 and eventFlushInterval = 100', function () { + describe('when eventBatchSize = 3 and eventFlushInterval = 100', function() { var optlyInstance; - beforeEach(function () { + beforeEach(function() { optlyInstance = new Optimizely({ clientEngine: 'node-sdk', datafile: testData.getTestProjectConfig(), @@ -5273,11 +6310,11 @@ describe('lib/optimizely', function () { }); }); - afterEach(function () { + afterEach(function() { optlyInstance.close(); }); - it('should send batched events when the maxQueueSize is reached', function () { + it('should send batched events when the maxQueueSize is reached', function() { bucketStub.returns('111129'); var activate = optlyInstance.activate('testExperiment', 'testUser'); assert.strictEqual(activate, 'variation'); @@ -5291,25 +6328,31 @@ describe('lib/optimizely', function () { url: 'https://logx.optimizely.com/v1/events', httpVerb: 'POST', params: { - 'account_id': '12001', - 'project_id': '111001', - 'visitors': [ + account_id: '12001', + project_id: '111001', + visitors: [ { - 'snapshots': [{ - 'decisions': [{ - 'campaign_id': '4', - 'experiment_id': '111127', - 'variation_id': '111129' - }], - 'events': [{ - 'entity_id': '4', - 'timestamp': Math.round(new Date().getTime()), - 'key': 'campaign_activated', - 'uuid': 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c' - }] - }], - 'visitor_id': 'testUser', - 'attributes': [], + snapshots: [ + { + decisions: [ + { + campaign_id: '4', + experiment_id: '111127', + variation_id: '111129', + }, + ], + events: [ + { + entity_id: '4', + timestamp: Math.round(new Date().getTime()), + key: 'campaign_activated', + uuid: 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c', + }, + ], + }, + ], + visitor_id: 'testUser', + attributes: [], }, { attributes: [], @@ -5320,10 +6363,10 @@ describe('lib/optimizely', function () { entity_id: '111095', key: 'testEvent', timestamp: new Date().getTime(), - uuid: 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c' - } - ] - } + uuid: 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c', + }, + ], + }, ], visitor_id: 'testUser', }, @@ -5336,26 +6379,26 @@ describe('lib/optimizely', function () { entity_id: '111095', key: 'testEvent', timestamp: new Date().getTime(), - uuid: 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c' - } - ] - } + uuid: 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c', + }, + ], + }, ], visitor_id: 'testUser', }, ], - 'revision': '42', - 'client_name': 'node-sdk', - 'client_version': enums.NODE_CLIENT_VERSION, - 'anonymize_ip': false, - 'enrich_decisions': true, + revision: '42', + client_name: 'node-sdk', + client_version: enums.NODE_CLIENT_VERSION, + anonymize_ip: false, + enrich_decisions: true, }, }; var eventDispatcherCall = eventDispatcher.dispatchEvent.args[0]; assert.deepEqual(eventDispatcherCall[0], expectedObj); }); - it('should flush the queue when the flushInterval occurs', function () { + it('should flush the queue when the flushInterval occurs', function() { var timestamp = new Date().getTime(); bucketStub.returns('111129'); var activate = optlyInstance.activate('testExperiment', 'testUser'); @@ -5373,25 +6416,31 @@ describe('lib/optimizely', function () { url: 'https://logx.optimizely.com/v1/events', httpVerb: 'POST', params: { - 'account_id': '12001', - 'project_id': '111001', - 'visitors': [ + account_id: '12001', + project_id: '111001', + visitors: [ { - 'snapshots': [{ - 'decisions': [{ - 'campaign_id': '4', - 'experiment_id': '111127', - 'variation_id': '111129' - }], - 'events': [{ - 'entity_id': '4', - 'timestamp': timestamp, - 'key': 'campaign_activated', - 'uuid': 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c' - }] - }], - 'visitor_id': 'testUser', - 'attributes': [], + snapshots: [ + { + decisions: [ + { + campaign_id: '4', + experiment_id: '111127', + variation_id: '111129', + }, + ], + events: [ + { + entity_id: '4', + timestamp: timestamp, + key: 'campaign_activated', + uuid: 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c', + }, + ], + }, + ], + visitor_id: 'testUser', + attributes: [], }, { attributes: [], @@ -5402,33 +6451,32 @@ describe('lib/optimizely', function () { entity_id: '111095', key: 'testEvent', timestamp: timestamp, - uuid: 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c' - } - ] - } + uuid: 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c', + }, + ], + }, ], visitor_id: 'testUser', }, ], - 'revision': '42', - 'client_name': 'node-sdk', - 'client_version': enums.NODE_CLIENT_VERSION, - 'anonymize_ip': false, - 'enrich_decisions': true, + revision: '42', + client_name: 'node-sdk', + client_version: enums.NODE_CLIENT_VERSION, + anonymize_ip: false, + enrich_decisions: true, }, }; var eventDispatcherCall = eventDispatcher.dispatchEvent.args[0]; assert.deepEqual(eventDispatcherCall[0], expectedObj); }); - it('should flush the queue when optimizely.close() is called', function () { + it('should flush the queue when optimizely.close() is called', function() { bucketStub.returns('111129'); var activate = optlyInstance.activate('testExperiment', 'testUser'); assert.strictEqual(activate, 'variation'); optlyInstance.track('testEvent', 'testUser'); - sinon.assert.notCalled(eventDispatcher.dispatchEvent); optlyInstance.close(); @@ -5439,25 +6487,31 @@ describe('lib/optimizely', function () { url: 'https://logx.optimizely.com/v1/events', httpVerb: 'POST', params: { - 'account_id': '12001', - 'project_id': '111001', - 'visitors': [ + account_id: '12001', + project_id: '111001', + visitors: [ { - 'snapshots': [{ - 'decisions': [{ - 'campaign_id': '4', - 'experiment_id': '111127', - 'variation_id': '111129' - }], - 'events': [{ - 'entity_id': '4', - 'timestamp': Math.round(new Date().getTime()), - 'key': 'campaign_activated', - 'uuid': 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c' - }] - }], - 'visitor_id': 'testUser', - 'attributes': [], + snapshots: [ + { + decisions: [ + { + campaign_id: '4', + experiment_id: '111127', + variation_id: '111129', + }, + ], + events: [ + { + entity_id: '4', + timestamp: Math.round(new Date().getTime()), + key: 'campaign_activated', + uuid: 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c', + }, + ], + }, + ], + visitor_id: 'testUser', + attributes: [], }, { attributes: [], @@ -5468,19 +6522,19 @@ describe('lib/optimizely', function () { entity_id: '111095', key: 'testEvent', timestamp: new Date().getTime(), - uuid: 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c' - } - ] - } + uuid: 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c', + }, + ], + }, ], visitor_id: 'testUser', }, ], - 'revision': '42', - 'client_name': 'node-sdk', - 'client_version': enums.NODE_CLIENT_VERSION, - 'anonymize_ip': false, - 'enrich_decisions': true, + revision: '42', + client_name: 'node-sdk', + client_version: enums.NODE_CLIENT_VERSION, + anonymize_ip: false, + enrich_decisions: true, }, }; var eventDispatcherCall = eventDispatcher.dispatchEvent.args[0]; @@ -5488,11 +6542,11 @@ describe('lib/optimizely', function () { }); }); - describe('close method', function () { + describe('close method', function() { var eventProcessorStopPromise; var optlyInstance; var mockEventProcessor; - beforeEach(function () { + beforeEach(function() { mockEventProcessor = { process: sinon.stub(), start: sinon.stub(), @@ -5501,12 +6555,12 @@ describe('lib/optimizely', function () { sinon.stub(eventProcessor, 'LogTierV1EventProcessor').returns(mockEventProcessor); }); - afterEach(function () { + afterEach(function() { eventProcessor.LogTierV1EventProcessor.restore(); }); - describe('when the event processor stop method returns a promise that fulfills', function () { - beforeEach(function () { + describe('when the event processor stop method returns a promise that fulfills', function() { + beforeEach(function() { eventProcessorStopPromise = Promise.resolve(); mockEventProcessor.stop.returns(eventProcessorStopPromise); optlyInstance = new Optimizely({ @@ -5523,21 +6577,21 @@ describe('lib/optimizely', function () { }); }); - afterEach(function () { - return eventProcessorStopPromise.catch(function () { + afterEach(function() { + return eventProcessorStopPromise.catch(function() { // Handle rejected promise - don't want test to fail }); }); - it('returns a promise that fulfills with a successful result object', function () { - return optlyInstance.close().then(function (result) { + it('returns a promise that fulfills with a successful result object', function() { + return optlyInstance.close().then(function(result) { assert.deepEqual(result, { success: true }); }); }); }); - describe('when the event processor stop method returns a promise that rejects', function () { - beforeEach(function () { + describe('when the event processor stop method returns a promise that rejects', function() { + beforeEach(function() { eventProcessorStopPromise = Promise.reject(new Error('Failed to stop')); mockEventProcessor.stop.returns(eventProcessorStopPromise); optlyInstance = new Optimizely({ @@ -5554,14 +6608,14 @@ describe('lib/optimizely', function () { }); }); - afterEach(function () { - return eventProcessorStopPromise.catch(function () { + afterEach(function() { + return eventProcessorStopPromise.catch(function() { // Handle rejected promise - don't want test to fail }); }); - it('returns a promise that fulfills with an unsuccessful result object', function () { - return optlyInstance.close().then(function (result) { + it('returns a promise that fulfills with an unsuccessful result object', function() { + return optlyInstance.close().then(function(result) { assert.deepEqual(result, { success: false, reason: 'Error: Failed to stop', @@ -5572,27 +6626,27 @@ describe('lib/optimizely', function () { }); }); - describe('event processor configuration', function () { + describe('event processor configuration', function() { var createdLogger = logger.createLogger({ logLevel: LOG_LEVEL.INFO, logToConsole: false, }); - beforeEach(function () { + beforeEach(function() { sinon.stub(eventDispatcher, 'dispatchEvent'); sinon.stub(errorHandler, 'handleError'); sinon.stub(createdLogger, 'log'); sinon.spy(eventProcessor, 'LogTierV1EventProcessor'); }); - afterEach(function () { + afterEach(function() { eventDispatcher.dispatchEvent.restore(); errorHandler.handleError.restore(); createdLogger.log.restore(); eventProcessor.LogTierV1EventProcessor.restore(); }); - it('should instantiate the eventProcessor with the provided event flush interval and event batch size', function () { + it('should instantiate the eventProcessor with the provided event flush interval and event batch size', function() { optlyInstance = new Optimizely({ clientEngine: 'node-sdk', errorHandler: errorHandler, @@ -5605,27 +6659,30 @@ describe('lib/optimizely', function () { eventFlushInterval: 20000, }); - sinon.assert.calledWithExactly(eventProcessor.LogTierV1EventProcessor, sinon.match({ - dispatcher: eventDispatcher, - flushInterval: 20000, - maxQueueSize: 100, - })); + sinon.assert.calledWithExactly( + eventProcessor.LogTierV1EventProcessor, + sinon.match({ + dispatcher: eventDispatcher, + flushInterval: 20000, + maxQueueSize: 100, + }) + ); }); }); - describe('project config management', function () { + describe('project config management', function() { var createdLogger = logger.createLogger({ logLevel: LOG_LEVEL.INFO, logToConsole: false, }); - beforeEach(function () { + beforeEach(function() { sinon.stub(eventDispatcher, 'dispatchEvent'); sinon.stub(errorHandler, 'handleError'); sinon.stub(createdLogger, 'log'); }); - afterEach(function () { + afterEach(function() { eventDispatcher.dispatchEvent.restore(); errorHandler.handleError.restore(); createdLogger.log.restore(); @@ -5633,7 +6690,7 @@ describe('lib/optimizely', function () { var optlyInstance; - it('should call the project config manager stop method when the close method is called', function () { + it('should call the project config manager stop method when the close method is called', function() { optlyInstance = new Optimizely({ clientEngine: 'node-sdk', errorHandler: errorHandler, @@ -5648,8 +6705,8 @@ describe('lib/optimizely', function () { sinon.assert.calledOnce(fakeManager.stop); }); - describe('when no datafile is available yet ', function () { - beforeEach(function () { + describe('when no datafile is available yet ', function() { + beforeEach(function() { optlyInstance = new Optimizely({ clientEngine: 'node-sdk', errorHandler: errorHandler, @@ -5661,7 +6718,7 @@ describe('lib/optimizely', function () { }); }); - it('returns fallback values from API methods that return meaningful values', function () { + it('returns fallback values from API methods that return meaningful values', function() { assert.isNull(optlyInstance.activate('my_experiment', 'user1')); assert.isNull(optlyInstance.getVariation('my_experiment', 'user1')); assert.isFalse(optlyInstance.setForcedVariation('my_experiment', 'user1', 'variation_1')); @@ -5675,7 +6732,7 @@ describe('lib/optimizely', function () { assert.isNull(optlyInstance.getFeatureVariableString('my_feature', 'my_str_var', 'user1')); }); - it('does not dispatch any events in API methods that dispatch events', function () { + it('does not dispatch any events in API methods that dispatch events', function() { optlyInstance.activate('my_experiment', 'user1'); optlyInstance.track('my_event', 'user1'); optlyInstance.isFeatureEnabled('my_feature', 'user1'); @@ -5684,29 +6741,29 @@ describe('lib/optimizely', function () { }); }); - describe('onReady method', function () { + describe('onReady method', function() { var clock; var setTimeoutSpy; var clearTimeoutSpy; - beforeEach(function () { + beforeEach(function() { clock = sinon.useFakeTimers(new Date().getTime()); setTimeoutSpy = sinon.spy(clock, 'setTimeout'); clearTimeoutSpy = sinon.spy(clock, 'clearTimeout'); }); - afterEach(function () { + afterEach(function() { setTimeoutSpy.restore(); clearTimeoutSpy.restore(); clock.restore(); }); - it('fulfills the promise with the value from the project config manager ready promise after the project config manager ready promise is fulfilled', function () { - projectConfigManager.ProjectConfigManager.callsFake(function (config) { + it('fulfills the promise with the value from the project config manager ready promise after the project config manager ready promise is fulfilled', function() { + projectConfigManager.ProjectConfigManager.callsFake(function(config) { var currentConfig = config.datafile ? projectConfig.createProjectConfig(config.datafile) : null; return { stop: sinon.stub(), getConfig: sinon.stub().returns(currentConfig), - onUpdate: sinon.stub().returns(function () { }), + onUpdate: sinon.stub().returns(function() {}), onReady: sinon.stub().returns(Promise.resolve({ success: true })), }; }); @@ -5719,12 +6776,12 @@ describe('lib/optimizely', function () { sdkKey: '12345', isValidInstance: true, }); - return optlyInstance.onReady().then(function (result) { + return optlyInstance.onReady().then(function(result) { assert.deepEqual(result, { success: true }); }); }); - it('fulfills the promise with an unsuccessful result after the timeout has expired when the project config manager onReady promise still has not resolved', function () { + it('fulfills the promise with an unsuccessful result after the timeout has expired when the project config manager onReady promise still has not resolved', function() { optlyInstance = new Optimizely({ clientEngine: 'node-sdk', errorHandler: errorHandler, @@ -5736,14 +6793,14 @@ describe('lib/optimizely', function () { }); var readyPromise = optlyInstance.onReady({ timeout: 500 }); clock.tick(501); - return readyPromise.then(function (result) { + return readyPromise.then(function(result) { assert.include(result, { success: false, }); }); }); - it('fulfills the promise with an unsuccessful result after 30 seconds when no timeout argument is provided and the project config manager onReady promise still has not resolved', function () { + it('fulfills the promise with an unsuccessful result after 30 seconds when no timeout argument is provided and the project config manager onReady promise still has not resolved', function() { optlyInstance = new Optimizely({ clientEngine: 'node-sdk', errorHandler: errorHandler, @@ -5755,14 +6812,14 @@ describe('lib/optimizely', function () { }); var readyPromise = optlyInstance.onReady(); clock.tick(300001); - return readyPromise.then(function (result) { + return readyPromise.then(function(result) { assert.include(result, { success: false, }); }); }); - it('fulfills the promise with an unsuccessful result after the instance is closed', function () { + it('fulfills the promise with an unsuccessful result after the instance is closed', function() { optlyInstance = new Optimizely({ clientEngine: 'node-sdk', errorHandler: errorHandler, @@ -5774,14 +6831,14 @@ describe('lib/optimizely', function () { }); var readyPromise = optlyInstance.onReady({ timeout: 100 }); optlyInstance.close(); - return readyPromise.then(function (result) { + return readyPromise.then(function(result) { assert.include(result, { success: false, }); }); }); - it('can be called several times with different timeout values and the returned promises behave correctly', function () { + it('can be called several times with different timeout values and the returned promises behave correctly', function() { optlyInstance = new Optimizely({ clientEngine: 'node-sdk', errorHandler: errorHandler, @@ -5795,23 +6852,25 @@ describe('lib/optimizely', function () { var readyPromise2 = optlyInstance.onReady({ timeout: 200 }); var readyPromise3 = optlyInstance.onReady({ timeout: 300 }); clock.tick(101); - return readyPromise1.then(function () { - clock.tick(100); - return readyPromise2; - }).then(function () { - // readyPromise3 has not resolved yet because only 201 ms have elapsed. - // Calling close on the instance should resolve readyPromise3 - optlyInstance.close(); - return readyPromise3; - }); + return readyPromise1 + .then(function() { + clock.tick(100); + return readyPromise2; + }) + .then(function() { + // readyPromise3 has not resolved yet because only 201 ms have elapsed. + // Calling close on the instance should resolve readyPromise3 + optlyInstance.close(); + return readyPromise3; + }); }); - it('clears the timeout when the project config manager ready promise fulfills', function () { - projectConfigManager.ProjectConfigManager.callsFake(function (config) { + it('clears the timeout when the project config manager ready promise fulfills', function() { + projectConfigManager.ProjectConfigManager.callsFake(function(config) { return { stop: sinon.stub(), getConfig: sinon.stub().returns(null), - onUpdate: sinon.stub().returns(function () { }), + onUpdate: sinon.stub().returns(function() {}), onReady: sinon.stub().returns(Promise.resolve({ success: true })), }; }); @@ -5824,7 +6883,7 @@ describe('lib/optimizely', function () { sdkKey: '12345', isValidInstance: true, }); - return optlyInstance.onReady().then(function () { + return optlyInstance.onReady().then(function() { sinon.assert.calledOnce(clock.setTimeout); var timeout = clock.setTimeout.getCall(0).returnValue; sinon.assert.calledOnce(clock.clearTimeout); @@ -5833,14 +6892,14 @@ describe('lib/optimizely', function () { }); }); - describe('project config updates', function () { + describe('project config updates', function() { var fakeProjectConfigManager; - beforeEach(function () { + beforeEach(function() { fakeProjectConfigManager = { stop: sinon.stub(), getConfig: sinon.stub().returns(null), - onUpdate: sinon.stub().returns(function () { }), - onReady: sinon.stub().returns({ then: function () { } }), + onUpdate: sinon.stub().returns(function() {}), + onReady: sinon.stub().returns({ then: function() {} }), }; projectConfigManager.ProjectConfigManager.returns(fakeProjectConfigManager); @@ -5855,7 +6914,7 @@ describe('lib/optimizely', function () { }); }); - it('uses the newest project config object from project config manager', function () { + it('uses the newest project config object from project config manager', function() { // Should start off returning false/null - no project config available assert.isFalse(optlyInstance.isFeatureEnabled('test_feature_for_experiment', 'user45678')); assert.isNull(optlyInstance.activate('myOtherExperiment', 'user98765')); @@ -5874,8 +6933,7 @@ describe('lib/optimizely', function () { differentDatafile.experiments.push({ key: 'myOtherExperiment', status: 'Running', - forcedVariations: { - }, + forcedVariations: {}, audienceIds: [], layerId: '5', trafficAllocation: [ @@ -5901,7 +6959,7 @@ describe('lib/optimizely', function () { assert.strictEqual(optlyInstance.activate('myOtherExperiment', 'user98765'), 'control'); }); - it('emits a notification when the project config manager emits a new project config object', function () { + it('emits a notification when the project config manager emits a new project config object', function() { var listener = sinon.spy(); optlyInstance.notificationCenter.addNotificationListener( enums.NOTIFICATION_TYPES.OPTIMIZELY_CONFIG_UPDATE, @@ -5915,11 +6973,11 @@ describe('lib/optimizely', function () { }); }); - describe('log event notification', function () { + describe('log event notification', function() { var optlyInstance; var bucketStub; var eventDispatcherSpy; - beforeEach(function () { + beforeEach(function() { bucketStub = sinon.stub(bucketer, 'bucket'); eventDispatcherSpy = sinon.spy(); optlyInstance = new Optimizely({ @@ -5927,25 +6985,25 @@ describe('lib/optimizely', function () { datafile: testData.getTestProjectConfig(), eventBuilder: eventBuilder, errorHandler: { - handleError: function () { }, + handleError: function() {}, }, eventDispatcher: { dispatchEvent: eventDispatcherSpy, }, logger: { - log: function () { }, + log: function() {}, }, isValidInstance: true, eventBatchSize: 1, }); }); - afterEach(function () { + afterEach(function() { bucketer.bucket.restore(); optlyInstance.close(); }); - it('should trigger a log event notification when an impression event is dispatched', function () { + it('should trigger a log event notification when an impression event is dispatched', function() { var notificationListener = sinon.spy(); optlyInstance.notificationCenter.addNotificationListener( enums.NOTIFICATION_TYPES.LOG_EVENT, @@ -5959,7 +7017,7 @@ describe('lib/optimizely', function () { sinon.assert.calledWithExactly(notificationListener, eventDispatcherSpy.getCall(0).args[0]); }); - it('should trigger a log event notification when a conversion event is dispatched', function () { + it('should trigger a log event notification when a conversion event is dispatched', function() { var notificationListener = sinon.spy(); optlyInstance.notificationCenter.addNotificationListener( enums.NOTIFICATION_TYPES.LOG_EVENT, From 646665d0e8275dfa07dd67153a4b78485e865715 Mon Sep 17 00:00:00 2001 From: Derek Hammond Date: Tue, 3 Mar 2020 11:14:27 -0600 Subject: [PATCH 3/4] actual changes --- .../optimizely-sdk/lib/optimizely/index.js | 9 +++++-- .../lib/optimizely/index.tests.js | 25 +++++++++++-------- 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/packages/optimizely-sdk/lib/optimizely/index.js b/packages/optimizely-sdk/lib/optimizely/index.js index 0fd291933..2e547ae10 100644 --- a/packages/optimizely-sdk/lib/optimizely/index.js +++ b/packages/optimizely-sdk/lib/optimizely/index.js @@ -291,7 +291,12 @@ Optimizely.prototype.track = function(eventKey, userId, attributes, eventTags) { } if (!projectConfig.eventWithKeyExists(configObj, eventKey)) { - throw new Error(jsSdkUtils.sprintf(ERROR_MESSAGES.INVALID_EVENT_KEY, MODULE_NAME, eventKey)); + this.logger.log( + LOG_LEVEL.WARNING, + jsSdkUtils.sprintf(enums.LOG_MESSAGES.EVENT_KEY_NOT_FOUND, MODULE_NAME, eventKey) + ); + this.logger.log(LOG_LEVEL.WARNING, jsSdkUtils.sprintf(LOG_MESSAGES.NOT_TRACKING_USER, MODULE_NAME, userId)); + return; } // remove null values from eventTags @@ -313,7 +318,7 @@ Optimizely.prototype.track = function(eventKey, userId, attributes, eventTags) { this.logger.log(LOG_LEVEL.ERROR, e.message); this.errorHandler.handleError(e); var failedTrackLogMessage = jsSdkUtils.sprintf(LOG_MESSAGES.NOT_TRACKING_USER, MODULE_NAME, userId); - this.logger.log(LOG_LEVEL.INFO, failedTrackLogMessage); + this.logger.log(LOG_LEVEL.ERROR, failedTrackLogMessage); } }; diff --git a/packages/optimizely-sdk/lib/optimizely/index.tests.js b/packages/optimizely-sdk/lib/optimizely/index.tests.js index e5efd72d8..c5f8545a9 100644 --- a/packages/optimizely-sdk/lib/optimizely/index.tests.js +++ b/packages/optimizely-sdk/lib/optimizely/index.tests.js @@ -1530,21 +1530,26 @@ describe('lib/optimizely', function() { assert.strictEqual(logMessage, sprintf(ERROR_MESSAGES.INVALID_INPUT_FORMAT, 'OPTIMIZELY', 'user_id')); }); - it('should throw an error for invalid event key', function() { + it('should log a warning for an event key that is not in the datafile and a warning for not tracking user', function() { optlyInstance.track('invalidEventKey', 'testUser'); - sinon.assert.notCalled(eventDispatcher.dispatchEvent); + sinon.assert.calledTwice(createdLogger.log); - sinon.assert.calledOnce(errorHandler.handleError); - var errorMessage = errorHandler.handleError.lastCall.args[0].message; - assert.strictEqual(errorMessage, sprintf(ERROR_MESSAGES.INVALID_EVENT_KEY, 'OPTIMIZELY', 'invalidEventKey')); + var logCall1 = createdLogger.log.getCall(0); + sinon.assert.calledWithExactly( + logCall1, + LOG_LEVEL.WARNING, + sprintf(LOG_MESSAGES.EVENT_KEY_NOT_FOUND, 'OPTIMIZELY', 'invalidEventKey') + ); - sinon.assert.calledTwice(createdLogger.log); - var logMessage1 = createdLogger.log.args[0][1]; - assert.strictEqual(logMessage1, sprintf(ERROR_MESSAGES.INVALID_EVENT_KEY, 'OPTIMIZELY', 'invalidEventKey')); + var logCall2 = createdLogger.log.getCall(1); + sinon.assert.calledWithExactly( + logCall2, + LOG_LEVEL.WARNING, + sprintf(LOG_MESSAGES.NOT_TRACKING_USER, 'OPTIMIZELY', 'testUser') + ); - var logMessage2 = createdLogger.log.args[1][1]; - assert.strictEqual(logMessage2, sprintf(LOG_MESSAGES.NOT_TRACKING_USER, 'OPTIMIZELY', 'testUser')); + sinon.assert.notCalled(errorHandler.handleError); }); it('should throw an error for invalid attributes', function() { From 08bfecc704140b84cccea182d4eafd2750d88b5f Mon Sep 17 00:00:00 2001 From: Derek Hammond Date: Wed, 4 Mar 2020 10:57:45 -0600 Subject: [PATCH 4/4] update CHANGELOG and CONTRIBUTING instructions --- CONTRIBUTING.md | 25 +-- packages/optimizely-sdk/CHANGELOG.MD | 306 +++++++++++++++++---------- 2 files changed, 205 insertions(+), 126 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5d8b1dd19..101b4cd35 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -5,21 +5,22 @@ We welcome contributions and feedback! All contributors must sign our [Contribut ## Development process 1. Fork the repository and create your branch from master. -2. Please follow the [commit message guidelines](https://github.com/angular/angular/blob/master/CONTRIBUTING.md#-commit-message-guidelines) for each commit message. +2. Please follow the [commit message guidelines](https://github.com/angular/angular/blob/master/CONTRIBUTING.md#-commit-message-guidelines) for each commit message. 3. Make sure to add tests! -4. Run `npm run lint` to ensure there are no lint errors. -5. `git push` your changes to GitHub. -6. Open a PR from your fork into the master branch of the original repo -7. Make sure that all unit tests are passing and that there are no merge conflicts between your branch and `master`. -8. Open a pull request from `YOUR_NAME/branch_name` to `master`. -9. A repository maintainer will review your pull request and, if all goes well, squash and merge it! +4. Update relevant `CHANGELOG.md` if users should know about this change. +5. Run `npm run lint` to ensure there are no lint errors. +6. `git push` your changes to GitHub. +7. Open a PR from your fork into the master branch of the original repo +8. Make sure that all unit tests are passing and that there are no merge conflicts between your branch and `master`. +9. Open a pull request from `YOUR_NAME/branch_name` to `master`. +10. A repository maintainer will review your pull request and, if all goes well, squash and merge it! ## Pull request acceptance criteria -* **All code must have test coverage.** We use Mocha's chai assertion library and Sinon. Changes in functionality should have accompanying unit tests. Bug fixes should have accompanying regression tests. - * Tests are located in the `tests.js` file. -* Please don't change the `package.json` or `VERSION`. We'll take care of bumping the version when we next release. -* Lint your code with our `npm run lint` before submitting. +- **All code must have test coverage.** We use Mocha's chai assertion library and Sinon. Changes in functionality should have accompanying unit tests. Bug fixes should have accompanying regression tests. + - Tests are located in the `tests.js` file. +- Please don't change the `package.json` or `VERSION`. We'll take care of bumping the version when we next release. +- Lint your code with our `npm run lint` before submitting. ## Style @@ -45,7 +46,7 @@ All contributions are under the CLA mentioned above. For this project, Optimizel * See the License for the specific language governing permissions and * * limitations under the License. * ***************************************************************************/ - ``` +``` The YEAR above should be the year of the contribution. If work on the file has been done over multiple years, list each year in the section above. Example: Optimizely writes the file and releases it in 2014. No changes are made in 2015. Change made in 2016. YEAR should be “2014, 2016”. diff --git a/packages/optimizely-sdk/CHANGELOG.MD b/packages/optimizely-sdk/CHANGELOG.MD index 34e8056e8..82ceec884 100644 --- a/packages/optimizely-sdk/CHANGELOG.MD +++ b/packages/optimizely-sdk/CHANGELOG.MD @@ -1,4 +1,5 @@ # Changelog + All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) @@ -6,26 +7,33 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## [Unreleased] +- Changed `track()` to log a warning instead of an error when the event isn't in the datafile ([#418](https://github.com/optimizely/javascript-sdk/pull/418)) + ## [3.5.0] - February 20th, 2020 ### Bug fixes + - Fixed default event dispatcher not used in React Native entry point ([#383](https://github.com/optimizely/javascript-sdk/pull/383)) - Fixed errors in `getOptimizelyConfig` TypeScript type definitions ([#406](https://github.com/optimizely/javascript-sdk/pull/406)) ### New Features + - Promise returned from `close` tracks the state of in-flight event dispatcher requests ([#404](https://github.com/optimizely/javascript-sdk/pull/404)) ## [3.4.1] - January 28th, 2020 ### Bug fixes + - Added `getOptimizelyConfig` and related types to TypeScript type definitions([#390](https://github.com/optimizely/javascript-sdk/pull/390)). ## [3.4.0] - January 21th, 2020 ### Bug fixes + - Fixed incorrect payload for decision notification triggered by calling getVariation on a feature test in a mutex group([#375](https://github.com/optimizely/javascript-sdk/pull/375)). ### New Features + - Added a new API to get project configuration static data. - Call `getOptimizelyConfig()` to get a snapshot of project configuration static data. - It returns an `OptimizelyConfig` instance which includes a datafile revision number, all experiments, and feature flags mapped by their key values. @@ -33,13 +41,15 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - For details, refer to our documentation page: [https://docs.developers.optimizely.com/full-stack/docs/optimizelyconfig-javascript-node](https://docs.developers.optimizely.com/full-stack/docs/optimizelyconfig-javascript-node). ### Removed Features + - Removed support for `'launched'` experiment status - Previously, experiments with status `'running'` or `'launched'` would return non-`null` variations from `activate` and `getVariation`, and generate impression events from `activate` - Now, only `'running'` experiments will return non-`null` variations and generate impressions - ## [3.4.0-beta] - December 18th, 2019 + ### Bug fixes + - Fixed incorrect payload for decision notification triggered by calling getVariation on a feature test in a mutex group([#375](https://github.com/optimizely/javascript-sdk/pull/375)) ### New Features @@ -50,12 +60,15 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - For details, refer to a documention page: https://docs.developers.optimizely.com/full-stack/docs/optimizelyconfig-javascript-node ## [3.3.2] - November 14th, 2019 + ### Bug fixes + - Fixed error message that was being logged when a user was bucketed into empty space in an experiment or a mutual exclusion group. This is not an error. With the fix, the message indicates that the user was not included in any experiment ([#366](https://github.com/optimizely/javascript-sdk/pull/366)). ## [3.3.1] - October 25th, 2019 ### Bug fixes + - Fixed full screen error dialog appearing in local development for React Native apps when using the default logger. We now provide a default logger for React Native that does not call `console.error`. ## [3.3.0] - September 25th, 2019 @@ -95,13 +108,15 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## [3.2.2] - August 20th, 2019 ### Bug fixes + - Dont use pendingEventsDispatcher with user defined eventDispatcher ([#289](https://github.com/optimizely/javascript-sdk/issues/289)) -Note: This was supposed to be released in 3.2.1 but did not make it into the release. + Note: This was supposed to be released in 3.2.1 but did not make it into the release. - Updated lodash dependency to ^4.17.11 to address security vulnerabilities ([#296](https://github.com/optimizely/javascript-sdk/issues/296)) ## [3.2.1] - July 1st, 2019 ### Changed + - Updated lodash dependency to ^4.17.11 to address security vulnerabilities ([#296](https://github.com/optimizely/javascript-sdk/issues/296)) ## [3.2.0] - May 30th, 2019 @@ -109,6 +124,7 @@ Note: This was supposed to be released in 3.2.1 but did not make it into the rel ### New Features - Added support for automatic datafile management ([#261](https://github.com/optimizely/javascript-sdk/pull/261)), ([#266](https://github.com/optimizely/javascript-sdk/pull/266)), ([#267](https://github.com/optimizely/javascript-sdk/pull/267)), ([#268](https://github.com/optimizely/javascript-sdk/pull/268)), ([#270](https://github.com/optimizely/javascript-sdk/pull/270)), ([#272](https://github.com/optimizely/javascript-sdk/pull/272)) + - To use automatic datafile management, include `sdkKey` as a string property in the options object you pass to `createInstance`. - When sdkKey is provided, the SDK instance will download the datafile associated with that sdkKey immediately upon construction. When the download completes, the SDK instance will update itself to use the downloaded datafile. - Use the `onReady` method to wait until the download is complete and the SDK is ready to use. @@ -118,6 +134,7 @@ Note: This was supposed to be released in 3.2.1 but did not make it into the rel - Stop active downloads and cancel recurring downloads by calling the `close` method #### Create an instance with datafile management enabled + ```js const optimizely = require('@optimizely/optimizely-sdk'); const optimizelyClientInstance = optimizely.createInstance({ @@ -126,6 +143,7 @@ Note: This was supposed to be released in 3.2.1 but did not make it into the rel ``` #### Use `onReady` to wait until optimizelyClientInstance has a datafile + ```js const optimizely = require('@optimizely/optimizely-sdk'); const optimizelyClientInstance = optimizely.createInstance({ @@ -137,42 +155,48 @@ Note: This was supposed to be released in 3.2.1 but did not make it into the rel ``` #### Enable automatic updates, add notification listener for OPTIMIZELY_CONFIG_UPDATE notification type, and stop automatic updates + ```js const optimizely = require('@optimizely/optimizely-sdk'); const optimizelyClientInstance = optimizely.createInstance({ sdkKey: '12345', datafileOptions: { autoUpdate: true, - updateInterval: 600000 // 10 minutes in milliseconds + updateInterval: 600000, // 10 minutes in milliseconds }, }); optimizelyClientInstance.notificationCenter.addNotificationListener( optimizely.enums.NOTIFICATION_TYPES.OPTIMIZELY_CONFIG_UPDATE, () => { // optimizelyClientInstance has updated its Optimizely config - }, + } ); // Stop automatic updates - optimizelyClientInstance will use whatever datafile it currently has from now on optimizelyClientInstance.close(); ``` ### Changed + - Forced variation logic has been moved from the project config module to the decision service. Prefixes for forced-variation-related log messages will reflect this change ([#261](https://github.com/optimizely/javascript-sdk/pull/261)). - Update TypeScript definitions to account for new methods (`onReady`, `close`) and new properties on object accepted by createInstance (`datafileOptions`, `sdkKey`), ([#263](https://github.com/optimizely/javascript-sdk/pull/263)), ([#278](https://github.com/optimizely/javascript-sdk/pull/278)) - Allow react-sdk to be passed in as `clientEngine` ([#279](https://github.com/optimizely/javascript-sdk/pull/279)) ### Bug Fixes: + - Add logging message for `optimizely.track()` ([#281](https://github.com/optimizely/javascript-sdk/pull/281)) ## [3.2.0-beta] - May 16th, 2019 ### Bug Fixes: + - Clear timeout created in onReady call for timeout promise as soon as project config manager's ready promise fulfills ### New Features + - Added 60 second timeout for all datafile requests ### Changed + - Updated datafile request polling behavior: - Start update interval timer immediately after request - When update interval timer fires during request, wait until request completes, then immediately start next request @@ -191,47 +215,50 @@ Note: This was supposed to be released in 3.2.1 but did not make it into the rel - Add a notification listener for the `OPTIMIZELY_CONFIG_UPDATE` notification type to be notified when an instance updates its Optimizely config after obtaining a new datafile. - Stop active downloads and cancel pending downloads by calling the `close` method +#### Create an instance with datafile management enabled - #### Create an instance with datafile management enabled - ```js - const optimizely = require('@optimizely/optimizely-sdk'); - const optimizelyClientInstance = optimizely.createInstance({ - sdkKey: '12345', // Provide the sdkKey of your desired environment here - }); - ``` +```js +const optimizely = require('@optimizely/optimizely-sdk'); +const optimizelyClientInstance = optimizely.createInstance({ + sdkKey: '12345', // Provide the sdkKey of your desired environment here +}); +``` - #### Use `onReady` to wait until optimizelyClientInstance has a datafile - ```js - const optimizely = require('@optimizely/optimizely-sdk'); - const optimizelyClientInstance = optimizely.createInstance({ - sdkKey: '12345', - }); - optimizelyClientInstance.onReady().then(() => { - // optimizelyClientInstance is ready to use, with datafile downloaded from the Optimizely CDN - }); - ``` +#### Use `onReady` to wait until optimizelyClientInstance has a datafile - #### Enable automatic updates, add notification listener for OPTIMIZELY_CONFIG_UPDATE notification type, and stop automatic updates - ```js - const optimizely = require('@optimizely/optimizely-sdk'); - const optimizelyClientInstance = optimizely.createInstance({ - sdkKey: '12345', - datafileOptions: { - autoUpdate: true, - updateInterval: 600000 // 10 minutes in milliseconds - }, - }); - optimizelyClientInstance.notificationCenter.addNotificationListener( - optimizely.enums.NOTIFICATION_TYPES.OPTIMIZELY_CONFIG_UPDATE, - () => { - // optimizelyClientInstance has updated its Optimizely config - }, - ); - // Stop automatic updates - optimizelyClientInstance will use whatever datafile it currently has from now on - optimizelyClientInstance.close(); - ``` +```js +const optimizely = require('@optimizely/optimizely-sdk'); +const optimizelyClientInstance = optimizely.createInstance({ + sdkKey: '12345', +}); +optimizelyClientInstance.onReady().then(() => { + // optimizelyClientInstance is ready to use, with datafile downloaded from the Optimizely CDN +}); +``` + +#### Enable automatic updates, add notification listener for OPTIMIZELY_CONFIG_UPDATE notification type, and stop automatic updates + +```js +const optimizely = require('@optimizely/optimizely-sdk'); +const optimizelyClientInstance = optimizely.createInstance({ + sdkKey: '12345', + datafileOptions: { + autoUpdate: true, + updateInterval: 600000, // 10 minutes in milliseconds + }, +}); +optimizelyClientInstance.notificationCenter.addNotificationListener( + optimizely.enums.NOTIFICATION_TYPES.OPTIMIZELY_CONFIG_UPDATE, + () => { + // optimizelyClientInstance has updated its Optimizely config + } +); +// Stop automatic updates - optimizelyClientInstance will use whatever datafile it currently has from now on +optimizelyClientInstance.close(); +``` ### Changed + - Forced variation logic has been moved from the project config module to the decision service. Prefixes for forced-variation-related log messages will reflect this change. ## [3.1.0] - April 22nd, 2019 @@ -239,80 +266,80 @@ Note: This was supposed to be released in 3.2.1 but did not make it into the rel ### New Features: - Introduced Decision notification listener to be able to record: - - Variation assignments for users activated in an experiment. - - Feature access for users. - - Feature variable value for users. + - Variation assignments for users activated in an experiment. + - Feature access for users. + - Feature variable value for users. ### Changed -* New APIs for setting `logger` and `logLevel` on the optimizelySDK singleton ([#232](https://github.com/optimizely/javascript-sdk/pull/232)) -* `logger` and `logLevel` are now set globally for all instances of Optimizely. If you were passing -different loggers to individual instances of Optimizely, logging behavior may now be different. +- New APIs for setting `logger` and `logLevel` on the optimizelySDK singleton ([#232](https://github.com/optimizely/javascript-sdk/pull/232)) +- `logger` and `logLevel` are now set globally for all instances of Optimizely. If you were passing + different loggers to individual instances of Optimizely, logging behavior may now be different. #### Setting a ConsoleLogger ```js -var optimizelySDK = require('@optimizely/optimizely-sdk') +var optimizelySDK = require('@optimizely/optimizely-sdk'); // logger and logLevel are now set on the optimizelySDK singleton -optimizelySDK.setLogger(optimizelySDK.logging.createLogger()) +optimizelySDK.setLogger(optimizelySDK.logging.createLogger()); // valid levels: 'DEBUG', 'INFO', 'WARN', 'ERROR' -optimizelySDK.setLogLevel('WARN') +optimizelySDK.setLogLevel('WARN'); // enums can also be used -optimizelySDK.setLogLevel(optimizelySDK.enums.LOG_LEVEL.ERROR) +optimizelySDK.setLogLevel(optimizelySDK.enums.LOG_LEVEL.ERROR); ``` #### Disable logging ```js -var optimizelySDK = require('@optimizely/optimizely-sdk') +var optimizelySDK = require('@optimizely/optimizely-sdk'); -optimizelySDK.setLogger(null) +optimizelySDK.setLogger(null); ``` ### Bug Fixes -* Feature variable APIs now return default variable value when featureEnabled property is false. ([#249](https://github.com/optimizely/javascript-sdk/pull/249)) +- Feature variable APIs now return default variable value when featureEnabled property is false. ([#249](https://github.com/optimizely/javascript-sdk/pull/249)) ### Deprecated -* Activate notification listener is deprecated as of this release. Recommendation is to use the new Decision notification listener. Activate notification listener will be removed in the next major release. - +- Activate notification listener is deprecated as of this release. Recommendation is to use the new Decision notification listener. Activate notification listener will be removed in the next major release. ## [3.1.0-beta1] - March 5th, 2019 ### Changed - New APIs for setting `logger` and `logLevel` on the optimizelySDK singleton ([#232](https://github.com/optimizely/javascript-sdk/pull/232)) -- `logger` and `logLevel` are now set globally for all instances of Optimizely. If you were passing -different loggers to individual instances of Optimizely, logging behavior may now be different. +- `logger` and `logLevel` are now set globally for all instances of Optimizely. If you were passing + different loggers to individual instances of Optimizely, logging behavior may now be different. #### Setting a ConsoleLogger ```js -var optimizelySDK = require('@optimizely/optimizely-sdk') +var optimizelySDK = require('@optimizely/optimizely-sdk'); // logger and logLevel are now set on the optimizelySDK singleton -optimizelySDK.setLogger(optimizelySDK.logging.createLogger()) +optimizelySDK.setLogger(optimizelySDK.logging.createLogger()); // valid levels: 'DEBUG', 'INFO', 'WARN', 'ERROR' -optimizelySDK.setLogLevel('WARN') +optimizelySDK.setLogLevel('WARN'); // enums can also be used -optimizelySDK.setLogLevel(optimizely.enums.LOG_LEVEL.ERROR) +optimizelySDK.setLogLevel(optimizely.enums.LOG_LEVEL.ERROR); ``` #### Disable logging ```js -var optimizelySDK = require('@optimizely/optimizely-sdk') +var optimizelySDK = require('@optimizely/optimizely-sdk'); -optimizelySDK.setLogger(null) +optimizelySDK.setLogger(null); ``` ## [3.0.1] - February 21, 2019 ### Changed + - Expose default `loggers`, `errorHandlers`, `eventDispatcher` and `enums` on top level require. - `createLogger` and `createNoOpLogger` are available as methods on `optimizelySdk.logging` - Added `optimizelySdk.errorHandler` @@ -369,7 +396,8 @@ The 3.0 release improves event tracking and supports additional audience targeti ## [2.3.0] - November 14, 2018 ### New Features -* Allow sticky bucketing via passing in `attributes.$opt_experiment_bucket_map`, this more easily allows customers to do some async data fetching and ensure a user gets a specific variation. + +- Allow sticky bucketing via passing in `attributes.$opt_experiment_bucket_map`, this more easily allows customers to do some async data fetching and ensure a user gets a specific variation. ``` const userId = '123' @@ -389,79 +417,95 @@ var selectedVariationKey = optimizelyClient.activate('experiment-1', userId, use ## [2.2.0] - September 26, 2018 ### Fixed + - Track and activate should not remove null attributes ([#168](https://github.com/optimizely/javascript-sdk/pull/168)) - Track attributes with valid attribute types ([#166](https://github.com/optimizely/javascript-sdk/pull/166)) - Prevent SDK from initializing if the datafile version in invalid ([#161](https://github.com/optimizely/javascript-sdk/pull/161)) - Updating lerna to latest version ([#160](https://github.com/optimizely/javascript-sdk/pull/160)) ### Changed + - Change invalid experiment key to debug level ([#165](https://github.com/optimizely/javascript-sdk/pull/165)) ## [2.1.3] - August 21, 2018 ### Fixed + - Send all decisions for the same event in one snapshot. ([#155](https://github.com/optimizely/javascript-sdk/pull/155)) - Give Node.js consumers the unbundled package ([#133](https://github.com/optimizely/javascript-sdk/pull/133)) ### Deprecated + - The UMD build of the SDK now assigns the SDK namespace object to `window.optimizelySdk` rather than to `window.optimizelyClient`. The old name still works, but on its first access a deprecation warning is logged to the console. The alias will be removed in the 3.0.0 release. ([#152](https://github.com/optimizely/javascript-sdk/pull/152)) ## [2.1.2] - June 25, 2018 ### Fixed + - Failure to log success message when event dispatched ([#123](https://github.com/optimizely/javascript-sdk/pull/123)) - Fix: Don't call success message when event fails to send ([#123](https://github.com/optimizely/javascript-sdk/pull/123)) ## [2.0.5] - June 25, 2018 ### Fixed + - Failure to log success message when event dispatched ([#123](https://github.com/optimizely/javascript-sdk/pull/123)) - Fix: Don't call success message when event fails to send ([#123](https://github.com/optimizely/javascript-sdk/pull/123)) ## 2.1.1 + June 19, 2018 -* Fix: send impression event for Feature Test with Feature disabled ([#117](https://github.com/optimizely/javascript-sdk/pull/117)) +- Fix: send impression event for Feature Test with Feature disabled ([#117](https://github.com/optimizely/javascript-sdk/pull/117)) ## 2.0.4 + June 19, 2018 -* Fix: send impression event for Feature Test with Feature disabled ([#117](https://github.com/optimizely/javascript-sdk/pull/117)) +- Fix: send impression event for Feature Test with Feature disabled ([#117](https://github.com/optimizely/javascript-sdk/pull/117)) ## 2.1.0 + May 24, 2018 -* Introduces support for bot filtering. +- Introduces support for bot filtering. ## 2.0.3 + May 24, 2018 -* Remove [`request`](https://www.npmjs.com/package/request) dependency ([#98](https://github.com/optimizely/javascript-sdk/pull/98)) -* Add package-lock.json ([#100](https://github.com/optimizely/javascript-sdk/pull/100)) -* Input validation in Activate, Track, and GetVariation methods ([#91](https://github.com/optimizely/javascript-sdk/pull/91) by [@mfahadahmed](https://github.com/mfahadahmed)) +- Remove [`request`](https://www.npmjs.com/package/request) dependency ([#98](https://github.com/optimizely/javascript-sdk/pull/98)) +- Add package-lock.json ([#100](https://github.com/optimizely/javascript-sdk/pull/100)) +- Input validation in Activate, Track, and GetVariation methods ([#91](https://github.com/optimizely/javascript-sdk/pull/91) by [@mfahadahmed](https://github.com/mfahadahmed)) ## 2.0.1 + April 16th, 2018 -* Improve browser entry point by pointing to the browser index file instead of the webpack-compiled bundle. ([@DullReferenceException](https://github.com/DullReferenceException) in [#88](https://github.com/optimizely/javascript-sdk/pull/88)) +- Improve browser entry point by pointing to the browser index file instead of the webpack-compiled bundle. ([@DullReferenceException](https://github.com/DullReferenceException) in [#88](https://github.com/optimizely/javascript-sdk/pull/88)) ## 2.0.0 + April 11th, 2018 This major release of the Optimizely SDK introduces APIs for Feature Management. It also introduces some breaking changes listed below. ### New Features -* Introduces the `isFeatureEnabled` API to determine whether to show a feature to a user or not. + +- Introduces the `isFeatureEnabled` API to determine whether to show a feature to a user or not. + ``` var enabled = optimizelyClient.isFeatureEnabled('my_feature_key', 'user_1', userAttributes); ``` -* You can also get all the enabled features for the user by calling the following method which returns a list of strings representing the feature keys: +- You can also get all the enabled features for the user by calling the following method which returns a list of strings representing the feature keys: + ``` var enabledFeatures = optimizelyClient.getEnabledFeatures('user_1', userAttributes); ``` -* Introduces Feature Variables to configure or parameterize your feature. There are four variable types: `Integer`, `String`, `Double`, `Boolean`. +- Introduces Feature Variables to configure or parameterize your feature. There are four variable types: `Integer`, `String`, `Double`, `Boolean`. + ``` var stringVariable = optimizelyClient.getFeatureVariableString('my_feature_key', 'string_variable_key', 'user_1'); var integerVariable = optimizelyClient.getFeatureVariableInteger('my_feature_key', 'integer_variable_key', 'user_1'); @@ -470,7 +514,9 @@ var booleanVariable = optimizelyClient.getFeatureVariableBoolean('my_feature_key ``` ### Breaking changes -* The `track` API with revenue value as a stand-alone parameter has been removed. The revenue value should be passed in as an entry of the event tags map. The key for the revenue tag is `revenue` and will be treated by Optimizely as the key for analyzing revenue data in results. + +- The `track` API with revenue value as a stand-alone parameter has been removed. The revenue value should be passed in as an entry of the event tags map. The key for the revenue tag is `revenue` and will be treated by Optimizely as the key for analyzing revenue data in results. + ``` var eventTags = { 'revenue': 1200 @@ -478,25 +524,31 @@ var eventTags = { optimizelyClient.track('event_key', 'user_id', userAttributes, eventTags); ``` -* The package name has changed from `optimizely-client-sdk` to `optimizely-sdk` as we have consolidated both Node and JavaScript SDKs into one. + +- The package name has changed from `optimizely-client-sdk` to `optimizely-sdk` as we have consolidated both Node and JavaScript SDKs into one. ## 2.0.0-beta1 + March 29th, 2018 This major release of the Optimizely SDK introduces APIs for Feature Management. It also introduces some breaking changes listed below. ### New Features -* Introduces the `isFeatureEnabled` API to determine whether to show a feature to a user or not. + +- Introduces the `isFeatureEnabled` API to determine whether to show a feature to a user or not. + ``` var enabled = optimizelyClient.isFeatureEnabled('my_feature_key', 'user_1', userAttributes); ``` -* You can also get all the enabled features for the user by calling the following method which returns a list of strings representing the feature keys: +- You can also get all the enabled features for the user by calling the following method which returns a list of strings representing the feature keys: + ``` var enabledFeatures = optimizelyClient.getEnabledFeatures('user_1', userAttributes); ``` -* Introduces Feature Variables to configure or parameterize your feature. There are four variable types: `Integer`, `String`, `Double`, `Boolean`. +- Introduces Feature Variables to configure or parameterize your feature. There are four variable types: `Integer`, `String`, `Double`, `Boolean`. + ``` var stringVariable = optimizelyClient.getFeatureVariableString('my_feature_key', 'string_variable_key', 'user_1'); var integerVariable = optimizelyClient.getFeatureVariableInteger('my_feature_key', 'integer_variable_key', 'user_1'); @@ -505,7 +557,9 @@ var booleanVariable = optimizelyClient.getFeatureVariableBoolean('my_feature_key ``` ### Breaking changes -* The `track` API with revenue value as a stand-alone parameter has been removed. The revenue value should be passed in as an entry of the event tags map. The key for the revenue tag is `revenue` and will be treated by Optimizely as the key for analyzing revenue data in results. + +- The `track` API with revenue value as a stand-alone parameter has been removed. The revenue value should be passed in as an entry of the event tags map. The key for the revenue tag is `revenue` and will be treated by Optimizely as the key for analyzing revenue data in results. + ``` var eventTags = { 'revenue': 1200 @@ -513,71 +567,84 @@ var eventTags = { optimizelyClient.track('event_key', 'user_id', userAttributes, eventTags); ``` -* The package name has changed from `optimizely-client-sdk` to `optimizely-sdk` as we have consolidated both Node and JavaScript SDKs into one. + +- The package name has changed from `optimizely-client-sdk` to `optimizely-sdk` as we have consolidated both Node and JavaScript SDKs into one. ## 1.6.0 -* Bump optimizely-server-sdk to version 1.5.0, which includes: +- Bump optimizely-server-sdk to version 1.5.0, which includes: - Implemented IP anonymization. - Implemented bucketing IDs. - Implemented notification listeners. ## 1.5.1 -* Bump optimizely-server-sdk to version 1.4.2, which includes: + +- Bump optimizely-server-sdk to version 1.4.2, which includes: - Bug fix to filter out undefined values in attributes and event tags - Remove a duplicated test ## 1.5.0 -* Bump optimizely-server-sdk to version 1.4.0, which includes: + +- Bump optimizely-server-sdk to version 1.4.0, which includes: - Add support for numeric metrics. - Add getForcedVariation and setForcedVariation methods for client-side variation setting - Bug fix for filtering out null attribute and event tag values ## 1.4.3 -* Default skipJSONValidation to true -* Bump optimizely-server-sdk to version 1.3.3, which includes: + +- Default skipJSONValidation to true +- Bump optimizely-server-sdk to version 1.3.3, which includes: - Removed JSON Schema Validator from Optimizely constructor - Updated SDK to use new event endpoint - Minor bug fixes ## 1.4.2 -* Minor performance improvements. + +- Minor performance improvements. ## 1.4.1 -* Switched to karma/browserstack for cross-browser testing -* Removed es6-promise -* Bump optimizely-server-sdk to version 1.3.1, which includes: + +- Switched to karma/browserstack for cross-browser testing +- Removed es6-promise +- Bump optimizely-server-sdk to version 1.3.1, which includes: - Minor performance improvements. ## 1.4.0 -* Reduce lodash footprint. -* Bump optimizely-server-sdk to version 1.3.0, which includes: + +- Reduce lodash footprint. +- Bump optimizely-server-sdk to version 1.3.0, which includes: - Introduced user profile service. - Minor performance and readibility improvements. ## 1.3.5 -* Bump optimizely-server-sdk to version 1.2.3, which includes: + +- Bump optimizely-server-sdk to version 1.2.3, which includes: - Switched to json-schema library which has a smaller footprint. - Refactored order of bucketing logic. - Refactor lodash dependencies. - Fixed error on validation for objects with undefined values for attributes. ## 1.3.4 -* Bump optimizely-server-sdk to version 1.2.2, which includes: + +- Bump optimizely-server-sdk to version 1.2.2, which includes: - Use the 'name' field for tracking event tags instead of 'id'. ## 1.3.3 -* Include index.js in package.json files to make sure it gets published regardless of node environment. + +- Include index.js in package.json files to make sure it gets published regardless of node environment. ## 1.3.2 -* Bump to 1.3.2 to re-publish to npm + +- Bump to 1.3.2 to re-publish to npm ## 1.3.1 -* Bump optimizely-server-sdk to version 1.2.1, which includes: + +- Bump optimizely-server-sdk to version 1.2.1, which includes: - Gracefully handle empty traffic allocation ranges. ## 1.3.0 -* Bump optimizely-server-sdk to version 1.2.0, which includes: + +- Bump optimizely-server-sdk to version 1.2.0, which includes: - Introduce support for event tags. - Add optional eventTags argument to track method signature. - Removed optional eventValue argument from track method signature. @@ -585,45 +652,56 @@ optimizelyClient.track('event_key', 'user_id', userAttributes, eventTags); - Allow log level config on createInstance method. ## 1.2.2 -* Remove .npmignore to consolidate with .gitignore. -* Add dist and lib directories to "files" in package.json. + +- Remove .npmignore to consolidate with .gitignore. +- Add dist and lib directories to "files" in package.json. ## 1.2.1 -* Fix webpack build error. + +- Fix webpack build error. ## 1.2.0 -* Bump optimizely-server-sdk to version 1.1.0, which includes: + +- Bump optimizely-server-sdk to version 1.1.0, which includes: - Add optional sessionId argument to activate and track method signatures. - Add sessionId and revision to event ticket. - Add 'Launched' status where user gets bucketed but event is not sent to Optimizely. ## 1.1.1 -* Bump to optimizely-server-sdk to version 1.0.1, which includes: + +- Bump to optimizely-server-sdk to version 1.0.1, which includes: - Fix bug so conversion event is not sent if user is not bucketed into any experiment. - Bump bluebird version from 3.3.5 to 3.4.6. - Update event endpoint from p13nlog.dz.optimizely to logx.optimizely. ## 1.1.0 -* Add global variable name export for use in non-CommonJS environments -* Remove redundant lodash core dependency to reduce bundle bloat + +- Add global variable name export for use in non-CommonJS environments +- Remove redundant lodash core dependency to reduce bundle bloat ## 1.0.0 -* Introduce support for Full Stack projects in Optimizely X with no breaking changes from previous version. -* Introduce more graceful exception handling in instantiation and core methods. -* Update whitelisting to take precedence over audience condition evaluation. -* Fix bug activating/tracking with attributes not in the datafile. + +- Introduce support for Full Stack projects in Optimizely X with no breaking changes from previous version. +- Introduce more graceful exception handling in instantiation and core methods. +- Update whitelisting to take precedence over audience condition evaluation. +- Fix bug activating/tracking with attributes not in the datafile. ## 0.1.4 -* Add functionality for New Optimizely endpoint. + +- Add functionality for New Optimizely endpoint. ## 0.1.3 -* Add environment detection to event builder so it can distinguish between events sent from node or the browser. + +- Add environment detection to event builder so it can distinguish between events sent from node or the browser. ## 0.1.2 -* Add CORS param to prevent browsers from logging cors errors in the console when dispatching events. + +- Add CORS param to prevent browsers from logging cors errors in the console when dispatching events. ## 0.1.1 -* Remove percentageIncluded field from JSON schema, which is not needed. + +- Remove percentageIncluded field from JSON schema, which is not needed. ## 0.1.0 -* Beta release of the Javascript SDK for our Optimizely testing solution + +- Beta release of the Javascript SDK for our Optimizely testing solution