1
+ import * as td from 'testdouble' ;
2
+
3
+ import {
4
+ MOCK_PRECOMPUTED_WIRE_FILE ,
5
+ MOCK_DEOBFUSCATED_PRECOMPUTED_RESPONSE_FILE ,
6
+ readMockConfigurationWireResponse ,
7
+ } from '../../test/testHelpers' ;
8
+ import { logger } from '../application-logger' ;
9
+ import { IAssignmentLogger } from '../assignment-logger' ;
10
+ import { IBanditLogger } from '../bandit-logger' ;
11
+ import { Configuration } from '../configuration' ;
12
+ import { MemoryOnlyConfigurationStore } from '../configuration-store/memory.store' ;
13
+ import { FormatEnum , VariationType , Variation } from '../interfaces' ;
14
+ import { BanditActions } from '../types' ;
15
+
16
+ import EppoClient from './eppo-client' ;
17
+
18
+ describe ( 'EppoClient Precomputed Mode' , ( ) => {
19
+ // Read both configurations for test reference
20
+ const precomputedConfigurationWire = readMockConfigurationWireResponse ( MOCK_PRECOMPUTED_WIRE_FILE ) ;
21
+ const initialConfiguration = Configuration . fromString ( precomputedConfigurationWire ) ;
22
+
23
+ // We only use deobfuscated configuration as a reference, not for creating a client
24
+ const deobfuscatedPrecomputedWire = readMockConfigurationWireResponse ( MOCK_DEOBFUSCATED_PRECOMPUTED_RESPONSE_FILE ) ;
25
+
26
+ let client : EppoClient ;
27
+ let mockAssignmentLogger : jest . Mocked < IAssignmentLogger > ;
28
+ let mockBanditLogger : jest . Mocked < IBanditLogger > ;
29
+
30
+ beforeEach ( ( ) => {
31
+ mockAssignmentLogger = { logAssignment : jest . fn ( ) } as jest . Mocked < IAssignmentLogger > ;
32
+ mockBanditLogger = { logBanditAction : jest . fn ( ) } as jest . Mocked < IBanditLogger > ;
33
+
34
+ // Create EppoClient with precomputed configuration
35
+ client = new EppoClient ( {
36
+ sdkKey : 'test-key' ,
37
+ sdkName : 'test-sdk' ,
38
+ sdkVersion : '1.0.0' ,
39
+ configuration : {
40
+ initialConfiguration,
41
+ initializationStrategy : 'none' ,
42
+ enablePolling : false ,
43
+ } ,
44
+ } ) ;
45
+
46
+ client . setAssignmentLogger ( mockAssignmentLogger ) ;
47
+ client . setBanditLogger ( mockBanditLogger ) ;
48
+ } ) ;
49
+
50
+ it ( 'correctly evaluates string flag' , ( ) => {
51
+ const result = client . getStringAssignment ( 'string-flag' , 'test-subject-key' , { } , 'default' ) ;
52
+ expect ( result ) . toBe ( 'red' ) ;
53
+ expect ( mockAssignmentLogger . logAssignment ) . toHaveBeenCalledTimes ( 1 ) ;
54
+ } ) ;
55
+
56
+ it ( 'correctly evaluates boolean flag' , ( ) => {
57
+ const result = client . getBooleanAssignment ( 'boolean-flag' , 'test-subject-key' , { } , false ) ;
58
+ expect ( result ) . toBe ( true ) ;
59
+ expect ( mockAssignmentLogger . logAssignment ) . toHaveBeenCalledTimes ( 1 ) ;
60
+ } ) ;
61
+
62
+ it ( 'correctly evaluates integer flag' , ( ) => {
63
+ const result = client . getIntegerAssignment ( 'integer-flag' , 'test-subject-key' , { } , 0 ) ;
64
+ expect ( result ) . toBe ( 42 ) ;
65
+ expect ( mockAssignmentLogger . logAssignment ) . toHaveBeenCalledTimes ( 1 ) ;
66
+ } ) ;
67
+
68
+ it ( 'correctly evaluates numeric flag' , ( ) => {
69
+ const result = client . getNumericAssignment ( 'numeric-flag' , 'test-subject-key' , { } , 0 ) ;
70
+ expect ( result ) . toBe ( 3.14 ) ;
71
+ expect ( mockAssignmentLogger . logAssignment ) . toHaveBeenCalledTimes ( 1 ) ;
72
+ } ) ;
73
+
74
+ it ( 'correctly evaluates JSON flag' , ( ) => {
75
+ const result = client . getJSONAssignment ( 'json-flag' , 'test-subject-key' , { } , { } ) ;
76
+ expect ( result ) . toEqual ( { key : 'value' , number : 123 } ) ;
77
+ expect ( mockAssignmentLogger . logAssignment ) . toHaveBeenCalledTimes ( 1 ) ;
78
+ } ) ;
79
+
80
+ it ( 'correctly evaluates flag with extra logging' , ( ) => {
81
+ const result = client . getStringAssignment ( 'string-flag-with-extra-logging' , 'test-subject-key' , { } , 'default' ) ;
82
+ expect ( result ) . toBe ( 'red' ) ;
83
+ expect ( mockAssignmentLogger . logAssignment ) . toHaveBeenCalledTimes ( 1 ) ;
84
+ } ) ;
85
+
86
+ it ( 'logs bandit evaluation for flag with bandit data' , ( ) => {
87
+ const banditActions = {
88
+ 'show_red_button' : {
89
+ expectedConversion : 0.23 ,
90
+ expectedRevenue : 15.75 ,
91
+ category : 'promotion' ,
92
+ placement : 'home_screen'
93
+ }
94
+ } ;
95
+
96
+ const result = client . getBanditAction ( 'string-flag' , 'test-subject-key' , { } , banditActions , 'default' ) ;
97
+
98
+ expect ( result . variation ) . toBe ( 'red' ) ;
99
+ expect ( result . action ) . toBe ( 'show_red_button' ) ;
100
+ expect ( mockBanditLogger . logBanditAction ) . toHaveBeenCalledTimes ( 1 ) ;
101
+
102
+ const call = mockBanditLogger . logBanditAction . mock . calls [ 0 ] [ 0 ] ;
103
+ expect ( call . bandit ) . toBe ( 'recommendation-model-v1' ) ;
104
+ expect ( call . action ) . toBe ( 'show_red_button' ) ;
105
+ expect ( call . modelVersion ) . toBe ( 'v2.3.1' ) ;
106
+ expect ( call . actionProbability ) . toBe ( 0.85 ) ;
107
+ expect ( call . optimalityGap ) . toBe ( 0.12 ) ;
108
+ } ) ;
109
+
110
+ it ( 'returns default values for nonexistent flags' , ( ) => {
111
+ const stringResult = client . getStringAssignment ( 'nonexistent-flag' , 'test-subject-key' , { } , 'default-string' ) ;
112
+ expect ( stringResult ) . toBe ( 'default-string' ) ;
113
+
114
+ const boolResult = client . getBooleanAssignment ( 'nonexistent-flag' , 'test-subject-key' , { } , true ) ;
115
+ expect ( boolResult ) . toBe ( true ) ;
116
+
117
+ const intResult = client . getIntegerAssignment ( 'nonexistent-flag' , 'test-subject-key' , { } , 100 ) ;
118
+ expect ( intResult ) . toBe ( 100 ) ;
119
+ } ) ;
120
+
121
+ it ( 'correctly handles assignment details' , ( ) => {
122
+ const details = client . getStringAssignmentDetails ( 'string-flag' , 'test-subject-key' , { } , 'default' ) ;
123
+
124
+ expect ( details . variation ) . toBe ( 'red' ) ;
125
+ expect ( details . evaluationDetails . variationKey ) . toBe ( 'variation-123' ) ;
126
+
127
+ // Assignment should be logged
128
+ expect ( mockAssignmentLogger . logAssignment ) . toHaveBeenCalledTimes ( 1 ) ;
129
+ const call = mockAssignmentLogger . logAssignment . mock . calls [ 0 ] [ 0 ] ;
130
+ expect ( call . allocation ) . toBe ( 'allocation-123' ) ;
131
+ expect ( call . featureFlag ) . toBe ( 'string-flag' ) ;
132
+ expect ( call . subject ) . toBe ( 'test-subject-key' ) ;
133
+ } ) ;
134
+ } ) ;
0 commit comments