Skip to content

Commit a2305dc

Browse files
committed
[FSSDK-12369] Add mandatory enforcement test: forced decision beats 100% local holdout
1 parent a810ce4 commit a2305dc

1 file changed

Lines changed: 37 additions & 0 deletions

File tree

lib/core/decision_service/index.spec.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3063,6 +3063,43 @@ describe('DecisionService', () => {
30633063
expect(value[0].result.decisionSource).toBe(DECISION_SOURCES.HOLDOUT);
30643064
expect(value[0].result.experiment?.id).toBe('local_holdout_id');
30653065
});
3066+
3067+
it('forced decision beats a 100% traffic local holdout: forced decision takes precedence over local holdout', async () => {
3068+
// exp_1 has id '2001', key 'exp_1', variation key 'variation_1' (id '5001')
3069+
// Local holdout targets '2001' with 100% traffic allocation.
3070+
// User also has a forced decision set for exp_1.
3071+
// Expected: forced decision wins; decisionSource is FEATURE_TEST, not HOLDOUT.
3072+
const config = createProjectConfig(makeLocalHoldoutDatafile('2001'));
3073+
const { decisionService } = getDecisionService();
3074+
3075+
// bucket should NOT be called for local_holdout_id because forced decision short-circuits first
3076+
mockBucket.mockImplementation((params: BucketerParams) => {
3077+
if (params.experimentId === 'local_holdout_id') {
3078+
// returning holdout variation here to prove the test fails if ordering is wrong
3079+
return { result: 'local_holdout_variation_id', reasons: [] };
3080+
}
3081+
return { result: null, reasons: [] };
3082+
});
3083+
3084+
const user = new OptimizelyUserContext({
3085+
optimizely: {} as any,
3086+
userId: 'user1',
3087+
attributes: { age: 15 },
3088+
});
3089+
3090+
// Set forced decision for exp_1 → variation_1
3091+
user.setForcedDecision(
3092+
{ flagKey: 'flag_1', ruleKey: 'exp_1' },
3093+
{ variationKey: 'variation_1' }
3094+
);
3095+
3096+
const feature = config.featureKeyMap['flag_1'];
3097+
const value = await decisionService.resolveVariationsForFeatureList('async', config, [feature], user, {}).get();
3098+
3099+
// Forced decision must win — source must be FEATURE_TEST, not HOLDOUT
3100+
expect(value[0].result.decisionSource).toBe(DECISION_SOURCES.FEATURE_TEST);
3101+
expect(value[0].result.variation?.key).toBe('variation_1');
3102+
});
30663103
});
30673104
});
30683105

0 commit comments

Comments
 (0)