-
Notifications
You must be signed in to change notification settings - Fork 83
feat(api): Decision Notification Listener for isFeatureEnabled and getEnabledFeatures APIs. #245
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(api): Decision Notification Listener for isFeatureEnabled and getEnabledFeatures APIs. #245
Conversation
…getEnabledFeatures APIs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good. Minor feedback. Please address and this will be good to merge.
*/ | ||
exports.NOTIFICATION_TYPES = { | ||
ACTIVATE: 'ACTIVATE:experiment, user_id,attributes, variation, event', | ||
TRACK: 'TRACK:event_key, user_id, attributes, event_tags, event', | ||
ON_DECISION: 'ON_DECISION:type, userId, attributes, decisionInfo', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit. It is DECISION and not ON_DECISION.
this.logger.log(LOG_LEVEL.INFO, sprintf(LOG_MESSAGES.FEATURE_NOT_ENABLED_FOR_USER, MODULE_NAME, featureKey, userId)); | ||
featureEnabled = false; | ||
} else { | ||
this.logger.log(LOG_LEVEL.INFO, sprintf(LOG_MESSAGES.FEATURE_ENABLED_FOR_USER, MODULE_NAME, featureKey, userId)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should there be featureEnabled = true
here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The possible values of variation.featureEnabled are true, false or undefined. For falsy values, we explicitly set it to false. Otherwise the value is already true.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have changed this condition to explicitly check for true.
@@ -2519,6 +2521,199 @@ describe('lib/optimizely', function() { | |||
}; | |||
sinon.assert.calledWith(trackListener, expectedArgument); | |||
}); | |||
|
|||
describe('OnDecision Listener', function() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit Decision Listener
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Make attributes default to {}
if not provided
{ | ||
type: DECISION_INFO_TYPES.FEATURE, | ||
userId: userId, | ||
attributes: attributes, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
make sure attributes defaults to {}
if not defined.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch.
@jordangarcia can you take a look again? |
if (!!variation) { | ||
featureEnabled = variation.featureEnabled; | ||
if (decision.decisionSource === DECISION_SOURCES.EXPERIMENT) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
DECISION_SOURCES.EXPERIMENT is experiment (lower case) and not EXPERIMENT (upper case). Similarly, DECISION_SOURCES.ROLLOUT is rollout (lower case) and not ROLLOUT (upper case). We should update that,
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Capitalized decision source values.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm confused about this comment. @aliabbasrizvi are you saying that the values (not the enum key) should be lower case or upper case.
This PR is changing it from lowercase to uppercase.
It's unclear what we want the final state to be (uppercase or lowercase)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, should have been clear. The value should be EXPERIMENT/ROLLOUT.
@jordangarcia can you re-review |
this.logger.log(LOG_LEVEL.INFO, sprintf(LOG_MESSAGES.FEATURE_ENABLED_FOR_USER, MODULE_NAME, featureKey, userId)); | ||
} else { | ||
this.logger.log(LOG_LEVEL.INFO, sprintf(LOG_MESSAGES.FEATURE_NOT_ENABLED_FOR_USER, MODULE_NAME, featureKey, userId)); | ||
featureEnabled = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shouldn't this value already be false?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it can be undefined when featureEnabled property is missing from the variation as specified in this test
describe('when the variation is missing the toggle', function() { |
featureEnabled = false; | ||
} | ||
|
||
var decisionSource = decision.decisionSource || DECISION_SOURCES.ROLLOUT; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In what cases is the decision.decisionSource
not a truthy value?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When the user was not bucketed into an experiment or a rollout, DecisionSource returned as null from decision service. But as per the comments in feature variables PR #246 this implementation has been changed. Updating it accordingly.
optlyInstance.notificationCenter.addNotificationListener(enums.NOTIFICATION_TYPES.DECISION, decisionListener); | ||
var result = optlyInstance.getEnabledFeatures('test_user', attributes); | ||
assert.strictEqual(result.length, 3); | ||
assert.isAbove(result.indexOf('test_feature_2'), -1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use
assert.deepEqual(result, ['test_feature2', 'test_feature_for_experiment', 'shared_feature'])
assert.isAbove(result.indexOf('test_feature_for_experiment'), -1); | ||
assert.isAbove(result.indexOf('shared_feature'), -1); | ||
|
||
assert.isTrue(decisionListener.getCall(0).calledWith({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use sinon assertion here
sinon.assert.calledWithExactly(spy.getCall(1), arg1, arg2, ...);
This will give a better error message than assert.isTrue
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a few minor changes to the test, and a couple questions. Please answer and I will re-review
…if the user is not evaluated into the experiment.
…istener-feature-enabled # Conflicts: # packages/optimizely-sdk/lib/optimizely/index.js # packages/optimizely-sdk/lib/optimizely/index.tests.js # packages/optimizely-sdk/lib/utils/enums/index.js
@ mfahadahmed this needs to be rebased before it can be merged. |
…istener-feature-enabled # Conflicts: # packages/optimizely-sdk/lib/optimizely/index.js
This reverts commit 9c3ec8a.
Summary
Test plan