Skip to content

Commit be648ef

Browse files
committed
reproduce bug
1 parent c18c3b3 commit be648ef

2 files changed

Lines changed: 93 additions & 3 deletions

File tree

Submodule engine-test-data updated 199 files

tests/engine/unit/engine.test.ts

Lines changed: 92 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,29 @@ import {
77
shouldApplyOverride
88
} from '../../../flagsmith-engine/index.js';
99
import { CONSTANTS } from '../../../flagsmith-engine/features/constants.js';
10-
import { FeatureModel, FeatureStateModel } from '../../../flagsmith-engine/features/models.js';
10+
import {
11+
FeatureModel,
12+
FeatureSegment,
13+
FeatureStateModel,
14+
MultivariateFeatureOptionModel,
15+
MultivariateFeatureStateValueModel
16+
} from '../../../flagsmith-engine/features/models.js';
1117
import { TraitModel } from '../../../flagsmith-engine/identities/traits/models.js';
1218
import {
1319
environment,
1420
environmentWithSegmentOverride,
1521
feature1,
1622
identity,
1723
identityInSegment,
24+
segment,
1825
segmentConditionProperty,
19-
segmentConditionStringValue
26+
segmentConditionStringValue,
27+
traitMatchingSegment
2028
} from './utils.js';
2129
import { getEvaluationContext } from '../../../flagsmith-engine/evaluation/evaluationContext/mappers.js';
2230
import { TARGETING_REASONS } from '../../../flagsmith-engine/features/types.js';
2331
import { EvaluationContext } from '../../../flagsmith-engine/evaluation/evaluationContext/evaluationContext.types.js';
32+
import { EvaluationContextWithMetadata } from '../../../flagsmith-engine/evaluation/models.js';
2433
import { IDENTITY_OVERRIDE_SEGMENT_NAME } from '../../../flagsmith-engine/segments/constants.js';
2534

2635
test('test_get_evaluation_result_without_any_override', () => {
@@ -356,3 +365,84 @@ test('evaluateFeatures with multivariate evaluation', () => {
356365
const flags = evaluateFeatures(context as any, {});
357366
expect(flags['Multivariate Feature'].value).toBe('variant_b');
358367
});
368+
369+
test('local evaluation returns correct multivariate value for segment override with 100% weight', () => {
370+
// Given
371+
// a feature with two multivariate variants where the segment override
372+
// assigns 100% weight to the second variant
373+
const env = environment();
374+
const seg = segment();
375+
376+
const mvFeature = new FeatureModel(10, 'mv_feature', CONSTANTS.STANDARD);
377+
378+
const controlOption = new MultivariateFeatureOptionModel('control', 1);
379+
const variantOption = new MultivariateFeatureOptionModel('variant_b', 2);
380+
381+
const envFs = new FeatureStateModel(mvFeature, true, 10, 'default');
382+
envFs.multivariateFeatureStateValues = [
383+
new MultivariateFeatureStateValueModel(controlOption, 0, 1),
384+
new MultivariateFeatureStateValueModel(variantOption, 100, 2)
385+
];
386+
env.featureStates.push(envFs);
387+
388+
const overrideFs = new FeatureStateModel(mvFeature, true, 11, 'default');
389+
overrideFs.featureSegment = new FeatureSegment(0);
390+
overrideFs.multivariateFeatureStateValues = [
391+
new MultivariateFeatureStateValueModel(controlOption, 0, 1),
392+
new MultivariateFeatureStateValueModel(variantOption, 100, 2)
393+
];
394+
seg.featureStates.push(overrideFs);
395+
env.project.segments = [seg];
396+
397+
// When
398+
// evaluating flags for an identity that matches the segment
399+
const context = getEvaluationContext(env, identityInSegment(), [traitMatchingSegment()]);
400+
const result = getEvaluationResult(context as EvaluationContextWithMetadata);
401+
const flag = result.flags['mv_feature'];
402+
403+
// Then
404+
// the flag value should be the 100%-weighted variant, not the base default
405+
expect(flag).toBeDefined();
406+
expect(flag.value).toBe('variant_b');
407+
});
408+
409+
test('getEvaluationContext maps multivariate variants onto segment override feature states', () => {
410+
// Given
411+
// a segment override feature state with multivariate values
412+
const env = environment();
413+
const seg = segment();
414+
415+
const mvFeature = new FeatureModel(10, 'mv_feature', CONSTANTS.STANDARD);
416+
env.featureStates.push(new FeatureStateModel(mvFeature, true, 10, 'default'));
417+
418+
const overrideFs = new FeatureStateModel(mvFeature, true, 11, 'default');
419+
overrideFs.featureSegment = new FeatureSegment(0);
420+
overrideFs.multivariateFeatureStateValues = [
421+
new MultivariateFeatureStateValueModel(
422+
new MultivariateFeatureOptionModel('variant_value', 1),
423+
100,
424+
1
425+
)
426+
];
427+
seg.featureStates.push(overrideFs);
428+
env.project.segments = [seg];
429+
430+
// When
431+
// mapping the environment model to an evaluation context
432+
const context = getEvaluationContext(env, identityInSegment(), [traitMatchingSegment()]);
433+
434+
// Then
435+
// the segment override should include the variants array
436+
const segmentOverrides = Object.values(context.segments || {});
437+
const segWithOverrides = segmentOverrides.find(
438+
s => s.overrides && s.overrides.some((o: any) => o.name === 'mv_feature')
439+
);
440+
expect(segWithOverrides).toBeDefined();
441+
442+
const mvOverride = segWithOverrides!.overrides!.find((o: any) => o.name === 'mv_feature');
443+
expect(mvOverride).toBeDefined();
444+
expect((mvOverride as any).variants).toBeDefined();
445+
expect((mvOverride as any).variants).toHaveLength(1);
446+
expect((mvOverride as any).variants[0].value).toBe('variant_value');
447+
expect((mvOverride as any).variants[0].weight).toBe(100);
448+
});

0 commit comments

Comments
 (0)