@@ -6938,7 +6938,6 @@ func TestEvaluate(t *testing.T) {
69386938 if items ["value" ] != float64 (25 ) || items ["enabled" ] != false {
69396939 t .Errorf ("flag = %+v, want the resolved value" , items )
69406940 }
6941- // Omitted until the SDK API returns them: absent, never faked.
69426941 for _ , absent := range []string {"reason" , "variant" } {
69436942 if _ , ok := items [absent ]; ok {
69446943 t .Errorf ("flag = %+v, want %q omitted rather than invented" , items , absent )
@@ -6949,6 +6948,86 @@ func TestEvaluate(t *testing.T) {
69496948 }
69506949 })
69516950
6951+ t .Run ("json carries the reason and variant the SDK API returned" , func (t * testing.T ) {
6952+ // Given
6953+ f := evalEnv (t )
6954+ flags := sdkFlagsFrom (defaultFeatures ())
6955+ flags [0 ]["reason" ] = "DEFAULT"
6956+ flags [1 ]["reason" ] = "SPLIT; weight=30"
6957+ flags [1 ]["variant" ] = "treatment"
6958+ f .sdkEnvFlags ["WqXhZk8sVY3dGgTqZ9pJmN" ] = flags
6959+
6960+ // When
6961+ out , err := run ("" , "evaluate" , "--json" )
6962+
6963+ // Then
6964+ if err != nil {
6965+ t .Fatalf ("evaluate --json: %v\n output: %s" , err , out )
6966+ }
6967+ resolved , _ := evalDoc (t , out )["flags" ].(map [string ]any )
6968+ items , _ := resolved ["max_items" ].(map [string ]any )
6969+ if items ["reason" ] != "SPLIT; weight=30" || items ["variant" ] != "treatment" {
6970+ t .Errorf ("flag = %+v, want the reason and variant it resolved by" , items )
6971+ }
6972+ // A standard feature has no variant to report; the schema calls that null,
6973+ // and an EvaluationResult that is already a subset omits it.
6974+ banner , _ := resolved ["onboarding_banner" ].(map [string ]any )
6975+ if banner ["reason" ] != "DEFAULT" {
6976+ t .Errorf ("flag = %+v, want the reason it resolved by" , banner )
6977+ }
6978+ if _ , ok := banner ["variant" ]; ok {
6979+ t .Errorf ("flag = %+v, want no variant where none applied" , banner )
6980+ }
6981+ })
6982+
6983+ t .Run ("the table adds VARIANT when SDK API returns a variant" , func (t * testing.T ) {
6984+ // Given
6985+ f := evalEnv (t )
6986+ flags := sdkFlagsFrom (defaultFeatures ())
6987+ flags [0 ]["reason" ] = "DEFAULT"
6988+ flags [1 ]["reason" ] = "TARGETING_MATCH; segment=power users"
6989+ flags [1 ]["variant" ] = "treatment"
6990+ f .sdkEnvFlags ["WqXhZk8sVY3dGgTqZ9pJmN" ] = flags
6991+
6992+ // When
6993+ out , err := run ("" , "evaluate" )
6994+
6995+ // Then
6996+ if err != nil {
6997+ t .Fatalf ("evaluate: %v\n output: %s" , err , out )
6998+ }
6999+ for _ , want := range []string {
7000+ "VARIANT" , "REASON" ,
7001+ "TARGETING_MATCH; segment=power users" , "treatment" , "DEFAULT" ,
7002+ } {
7003+ if ! strings .Contains (out , want ) {
7004+ t .Errorf ("output = %q, want it to contain %q" , out , want )
7005+ }
7006+ }
7007+ })
7008+
7009+ t .Run ("the table drops the columns an SDK API left empty" , func (t * testing.T ) {
7010+ // Given
7011+ f := evalEnv (t )
7012+ flags := sdkFlagsFrom (defaultFeatures ())
7013+ flags [0 ]["reason" ], flags [1 ]["reason" ] = "DEFAULT" , "DEFAULT"
7014+ f .sdkEnvFlags ["WqXhZk8sVY3dGgTqZ9pJmN" ] = flags
7015+
7016+ // When
7017+ out , err := run ("" , "evaluate" )
7018+
7019+ // Then
7020+ if ! strings .Contains (out , "REASON" ) {
7021+ t .Errorf ("output = %q, want the reason column" , out )
7022+ }
7023+ if strings .Contains (out , "VARIANT" ) {
7024+ t .Errorf ("output = %q, want no variant column where nothing was bucketed" , out )
7025+ }
7026+ if err != nil {
7027+ t .Fatalf ("evaluate: %v\n output: %s" , err , out )
7028+ }
7029+ })
7030+
69527031 t .Run ("--js is the frontend SDK's hydration state" , func (t * testing.T ) {
69537032 // Given
69547033 f := evalEnv (t )
@@ -7172,6 +7251,32 @@ func TestEvaluate(t *testing.T) {
71727251 if strings .Contains (out , "onboarding_banner" ) {
71737252 t .Errorf ("output = %q, want only the named feature" , out )
71747253 }
7254+ for _ , absent := range []string {"Reason" , "Variant" } {
7255+ if strings .Contains (out , absent ) {
7256+ t .Errorf ("output = %q, want no %q the SDK API never reported" , out , absent )
7257+ }
7258+ }
7259+ })
7260+
7261+ t .Run ("a single feature's detail view says why it resolved" , func (t * testing.T ) {
7262+ // Given
7263+ f := evalEnv (t )
7264+ flags := sdkFlagsFrom (defaultFeatures ())
7265+ flags [1 ]["reason" ], flags [1 ]["variant" ] = "SPLIT; weight=30" , "treatment"
7266+ f .sdkEnvFlags ["WqXhZk8sVY3dGgTqZ9pJmN" ] = flags
7267+
7268+ // When
7269+ out , err := run ("" , "evaluate" , "max_items" )
7270+
7271+ // Then
7272+ if err != nil {
7273+ t .Fatalf ("evaluate max_items: %v\n output: %s" , err , out )
7274+ }
7275+ for _ , want := range []string {"Variant" , "treatment" , "Reason" , "SPLIT; weight=30" } {
7276+ if ! strings .Contains (out , want ) {
7277+ t .Errorf ("output = %q, want %q" , out , want )
7278+ }
7279+ }
71757280 })
71767281
71777282 t .Run ("an unknown feature errors with a hint" , func (t * testing.T ) {
@@ -7451,6 +7556,26 @@ func TestEvaluateIdentity(t *testing.T) {
74517556 }
74527557 })
74537558
7559+ t .Run ("an identity's variant and reason survive the identify call" , func (t * testing.T ) {
7560+ // Given
7561+ f := evalEnv (t )
7562+ flags := overridden ()
7563+ flags [1 ]["reason" ], flags [1 ]["variant" ] = "SPLIT; weight=50" , "treatment"
7564+ f .sdkIdentityFlags ["user-123" ] = flags
7565+
7566+ // When
7567+ out , err := run ("" , "evaluate" , "max_items" , "--identity" , "user-123" , "--json" )
7568+
7569+ // Then
7570+ if err != nil {
7571+ t .Fatalf ("evaluate --identity --json: %v\n output: %s" , err , out )
7572+ }
7573+ doc := evalDoc (t , out )
7574+ if doc ["reason" ] != "SPLIT; weight=50" || doc ["variant" ] != "treatment" {
7575+ t .Errorf ("doc = %+v, want the identity's reason and variant" , doc )
7576+ }
7577+ })
7578+
74547579 // The flag commands name this --identifier; eval names it --identity. Both
74557580 // spellings work here, so nobody has to remember which command uses which.
74567581 for _ , spelling := range []string {"--identity" , "--identifier" , "-i" } {
0 commit comments