Skip to content

Commit d9f4b63

Browse files
committed
feat: fixed-tests
1 parent 10621ad commit d9f4b63

File tree

10 files changed

+74
-35
lines changed

10 files changed

+74
-35
lines changed

flagsmith-engine/evaluation/evaluationContext/evaluationContext.types.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ export interface SegmentContext {
175175
name: Name1;
176176
rules: Rules;
177177
overrides?: Overrides;
178+
metadata?: Metadata;
178179
[k: string]: unknown;
179180
}
180181
/**
@@ -225,6 +226,12 @@ export interface FeatureValue {
225226
weight: Weight;
226227
[k: string]: unknown;
227228
}
229+
/**
230+
* Additional metadata associated with the segment.
231+
*/
232+
export interface Metadata {
233+
[k: string]: string | number | boolean | null;
234+
}
228235
/**
229236
* Features to be evaluated in the context.
230237
*/

flagsmith-engine/evaluation/evaluationContext/mappers.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ import {
44
Traits,
55
EvaluationContext,
66
EnvironmentContext,
7-
IdentityContext
7+
IdentityContext,
8+
SegmentSource
89
} from '../models.js';
910
import { EnvironmentModel } from '../../environments/models.js';
1011
import { IdentityModel } from '../../identities/models.js';
@@ -74,7 +75,11 @@ function mapEnvironmentModelToEvaluationContext(environment: EnvironmentModel):
7475
value: fs.getValue(),
7576
priority: fs.featureSegment?.priority
7677
}))
77-
: []
78+
: [],
79+
metadata: {
80+
source: SegmentSource.API,
81+
flagsmith_id: segment.id
82+
}
7883
};
7984
}
8085

@@ -170,6 +175,9 @@ function mapIdentityOverridesToSegments(identityOverrides: IdentityModel[]): Seg
170175
]
171176
}
172177
],
178+
metadata: {
179+
source: SegmentSource.IDENTITY_OVERRIDE
180+
},
173181
overrides: overrides
174182
};
175183
}

flagsmith-engine/evaluation/evaluationResult/evaluationResult.types.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,5 +63,12 @@ export interface FlagResult {
6363
export interface SegmentResult {
6464
key: Key;
6565
name: Name1;
66+
metadata?: Metadata;
6667
[k: string]: unknown;
6768
}
69+
/**
70+
* Additional metadata associated with the segment.
71+
*/
72+
export interface Metadata {
73+
[k: string]: string | number | boolean | null;
74+
}

flagsmith-engine/evaluation/models.ts

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,7 @@ import type {
1313
FeatureValue as ContextFeatureValue,
1414
Traits,
1515
Features,
16-
Segments,
17-
EvaluationContext
16+
Segments
1817
} from './evaluationContext/evaluationContext.types.js';
1918

2019
import type {
@@ -54,19 +53,27 @@ export type SegmentConditionOperator = SegmentCondition['operator'];
5453
export type EvaluationReason = EvaluationContextResultFlagResult['reason'];
5554

5655
export type EvaluationResultSegments = EvaluationContextResult['segments'];
57-
export type EvaluationResultFlags = {
58-
feature_key: FeatureKey;
59-
name: FeatureName;
60-
enabled: FeatureEnabled;
61-
value: FeatureValue;
62-
reason: EvaluationReason;
63-
}[];
56+
export type EvaluationResultFlags = Record<
57+
string,
58+
{
59+
feature_key: FeatureKey;
60+
name: FeatureName;
61+
enabled: FeatureEnabled;
62+
value: FeatureValue;
63+
reason: EvaluationReason;
64+
}
65+
>;
6466

6567
export type EvaluationResult = {
66-
context: EvaluationContext;
6768
flags: EvaluationResultFlags;
6869
segments: EvaluationResultSegments;
6970
};
7071

7172
export { FlagResult } from './evaluationResult/evaluationResult.types.js';
73+
74+
export enum SegmentSource {
75+
API = 'api',
76+
IDENTITY_OVERRIDE = 'identity_override'
77+
}
78+
7279
export * from './evaluationContext/evaluationContext.types.js';

flagsmith-engine/index.ts

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { EvaluationContext, FeatureContext } from './evaluation/models.js';
1+
import { EvaluationContext, FeatureContext, SegmentSource } from './evaluation/models.js';
22
import { getIdentitySegments } from './segments/evaluators.js';
33
import { EvaluationResult, EvaluationResultFlags } from './evaluation/models.js';
44
import { TARGETING_REASONS } from './features/types.js';
@@ -9,6 +9,7 @@ export { TraitModel } from './identities/traits/models.js';
99
export { SegmentModel } from './segments/models.js';
1010
export { FeatureModel, FeatureStateModel } from './features/models.js';
1111
export { OrganisationModel } from './organisations/models.js';
12+
1213
type SegmentOverride = {
1314
feature: FeatureContext;
1415
segmentName: string;
@@ -30,7 +31,7 @@ export function getEvaluationResult(context: EvaluationContext): EvaluationResul
3031
const { segments, segmentOverrides } = evaluateSegments(context);
3132
const flags = evaluateFeatures(context, segmentOverrides);
3233

33-
return { context, flags, segments };
34+
return { flags, segments };
3435
}
3536

3637
/**
@@ -50,7 +51,14 @@ export function evaluateSegments(context: EvaluationContext): {
5051

5152
const segments = identitySegments.map(segment => ({
5253
key: segment.key,
53-
name: segment.name
54+
name: segment.name,
55+
...(segment.metadata
56+
? {
57+
metadata: {
58+
...segment.metadata
59+
}
60+
}
61+
: {})
5462
}));
5563
const segmentOverrides = processSegmentOverrides(identitySegments);
5664

@@ -103,7 +111,7 @@ export function evaluateFeatures(
103111
context: EvaluationContext,
104112
segmentOverrides: Record<string, SegmentOverride>
105113
): EvaluationResultFlags {
106-
const flags: EvaluationResultFlags = [];
114+
const flags: EvaluationResultFlags = {};
107115

108116
for (const feature of Object.values(context.features || {})) {
109117
const segmentOverride = segmentOverrides[feature.feature_key];
@@ -114,15 +122,15 @@ export function evaluateFeatures(
114122
? { value: finalFeature.value, reason: undefined }
115123
: evaluateFeatureValue(finalFeature, context.identity?.key);
116124

117-
flags.push({
125+
flags[finalFeature.name] = {
118126
feature_key: finalFeature.feature_key,
119127
name: finalFeature.name,
120128
enabled: finalFeature.enabled,
121129
value: evaluatedValue,
122130
reason:
123131
evaluatedReason ??
124132
getTargetingMatchReason({ type: 'SEGMENT', override: segmentOverride })
125-
});
133+
};
126134
}
127135

128136
return flags;

flagsmith-engine/segments/models.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import {
2323
Overrides
2424
} from '../evaluation/evaluationContext/evaluationContext.types.js';
2525
import { CONSTANTS } from '../features/constants.js';
26-
import { EvaluationResultSegments } from '../evaluation/models.js';
26+
import { EvaluationResultSegments, SegmentSource } from '../evaluation/models.js';
2727

2828
export const all = (iterable: Array<any>) => iterable.filter(e => !!e).length === iterable.length;
2929
export const any = (iterable: Array<any>) => iterable.filter(e => !!e).length > 0;
@@ -216,17 +216,17 @@ export class SegmentModel {
216216
}
217217

218218
for (const segmentResult of segmentResults) {
219+
if (segmentResult.metadata?.source === SegmentSource.IDENTITY_OVERRIDE) {
220+
continue;
221+
}
219222
const segmentContext = evaluationContext.segments[segmentResult.key];
220223
if (segmentContext) {
221224
const segment = new SegmentModel(parseInt(segmentContext.key), segmentContext.name);
222225
segment.rules = segmentContext.rules.map(rule => new SegmentRuleModel(rule.type));
223226
segment.featureStates = SegmentModel.createFeatureStatesFromOverrides(
224227
segmentContext.overrides || []
225228
);
226-
227-
if (!isNaN(segment.id)) {
228-
segmentModels.push(segment);
229-
}
229+
segmentModels.push(segment);
230230
}
231231
}
232232

sdk/models.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ export class Flags {
123123
analyticsProcessor?: AnalyticsProcessor
124124
): Flags {
125125
const flags: { [key: string]: Flag } = {};
126-
for (const flag of evaluationResult.flags) {
126+
for (const flag of Object.values(evaluationResult.flags)) {
127127
flags[flag.name] = new Flag({
128128
enabled: flag.enabled,
129129
value: flag.value ?? null,

tests/engine/e2e/engine.test.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ interface TestCase {
1313
context: EvaluationContext;
1414
result: {
1515
flags?: Record<string, any>;
16+
segments?: Record<string, any>;
1617
};
1718
}
1819

@@ -53,7 +54,8 @@ describe('Engine Integration Tests', () => {
5354
) as any[];
5455

5556
expect(sortedEngineFlags.length).toBe(sortedAPIFlags.length);
56-
57+
expect(engine_response.segments).toStrictEqual(testCase.result.segments);
58+
expect(engine_response.flags).toStrictEqual(testCase.result.flags);
5759
for (let i = 0; i < sortedEngineFlags.length; i++) {
5860
expect(sortedEngineFlags[i].value).toBe(sortedAPIFlags[i].value);
5961
expect(sortedEngineFlags[i].enabled).toBe(sortedAPIFlags[i].enabled);
Submodule engine-test-data updated 103 files

tests/engine/unit/engine.test.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ test('test_get_evaluation_result_without_any_override', () => {
2727
const context = getEvaluationContext(environment(), identity());
2828
const result = getEvaluationResult(context);
2929

30-
const flag = result.flags.find(f => f.name === feature1().name);
30+
const flag = Object.values(result.flags).find(f => f.name === feature1().name);
3131
expect(flag).toBeDefined();
3232
expect(flag?.name).toBe(feature1().name);
3333
expect(flag?.feature_key).toBe(feature1().id.toString());
@@ -46,9 +46,9 @@ test('test_get_evaluation_result_with_identity_override_and_no_segment_override'
4646
const context = getEvaluationContext(env, ident);
4747
const result = getEvaluationResult(context);
4848

49-
expect(result.flags.length).toBe(3);
49+
expect(Object.keys(result.flags).length).toBe(3);
5050

51-
for (const flag of result.flags) {
51+
for (const flag of Object.values(result.flags)) {
5252
const environmentFeature = Object.values(context.features || {}).find(
5353
f => f.name === flag.name
5454
);
@@ -73,7 +73,7 @@ test('test_identity_get_all_feature_states_with_traits', () => {
7373

7474
const result = getEvaluationResult(context);
7575

76-
const overriddenFlag = result.flags.find(f => f.value === 'segment_override');
76+
const overriddenFlag = Object.values(result.flags).find(f => f.value === 'segment_override');
7777
expect(overriddenFlag).toBeDefined();
7878
expect(overriddenFlag?.value).toBe('segment_override');
7979
expect(overriddenFlag?.reason).toEqual(
@@ -86,13 +86,13 @@ test('test_environment_get_all_feature_states', () => {
8686
const context = getEvaluationContext(env);
8787
const result = getEvaluationResult(context);
8888

89-
expect(result.flags.length).toBe(Object.keys(context.features || {}).length);
89+
expect(Object.keys(result.flags).length).toBe(Object.keys(context.features || {}).length);
9090

91-
result.flags.forEach(flag => {
91+
Object.values(result.flags).forEach(flag => {
9292
expect(flag.reason).toBe(TARGETING_REASONS.DEFAULT);
9393
});
9494

95-
for (const flag of result.flags) {
95+
for (const flag of Object.values(result.flags)) {
9696
const envFeature = Object.values(context.features || {}).find(f => f.name === flag.name);
9797
expect(flag.enabled).toBe(envFeature?.enabled);
9898
expect(flag.value).toBe(envFeature?.value);
@@ -362,6 +362,6 @@ test('evaluateFeatures with multivariate evaluation', () => {
362362
}
363363
};
364364

365-
const result = evaluateFeatures(context, {});
366-
expect(result[0].value).toBe('variant_b');
365+
const flags = evaluateFeatures(context, {});
366+
expect(flags['Multivariate Feature'].value).toBe('variant_b');
367367
});

0 commit comments

Comments
 (0)