//go:build integration package inttest import ( "context" "net/http" "net/http/httptest" "slices" "strings" "testing" "github.com/google/uuid" "go.uber.org/zap/zaptest" "scrabble/backend/internal/account" "scrabble/backend/internal/server" "scrabble/backend/internal/session" ) // TestTelegramAuthSeedsPromoVariantForNewUserOnly drives the sessions/telegram endpoint // to confirm a promo deep-link start-param widens a brand-new account's variant // preferences — English Scrabble on top of the default pair, but only for a // non-Russian-speaking arrival — that a new account with no such payload keeps the // default, and that an existing account is never re-seeded on a later login (the // new-user-only contract). func TestTelegramAuthSeedsPromoVariantForNewUserOnly(t *testing.T) { srv := server.New(":0", server.Deps{ Logger: zaptest.NewLogger(t), DB: testDB, Accounts: account.NewStore(testDB), Sessions: session.NewService(session.NewStore(testDB), session.NewCache()), Notifier: &captureNotifier{}, }) h := srv.Handler() post := func(ext, language, startParam string) { body := `{"external_id":"` + ext + `","language_code":"` + language + `","first_name":"Promo"` if startParam != "" { body += `,"start_param":"` + startParam + `"` } body += `}` rec := httptest.NewRecorder() req := httptest.NewRequest(http.MethodPost, "/api/v1/internal/sessions/telegram", strings.NewReader(body)) req.Header.Set("Content-Type", "application/json") h.ServeHTTP(rec, req) if rec.Code != http.StatusOK { t.Fatalf("telegram auth = %d: %s", rec.Code, rec.Body.String()) } } store := account.NewStore(testDB) reload := func(ext string) []string { acc, err := store.AccountByIdentity(context.Background(), account.KindTelegram, ext) if err != nil { t.Fatalf("lookup %s: %v", ext, err) } return acc.VariantPreferences } // An English-speaking arrival on a promo deep-link gains English Scrabble on top of // the default pair, so a native English player is not lost at the door. promoExt := "tg-" + uuid.NewString() post(promoExt, "en", "verudit_ru-scrabble_en") if got, want := reload(promoExt), []string{"erudit_ru", "scrabble_ru", "scrabble_en"}; !slices.Equal(got, want) { t.Errorf("english promo account variants = %v, want %v", got, want) } // A Russian-speaking arrival on the same link stays on the default pair: the two // Russian-alphabet games serve them, and English would only clutter New Game. ruExt := "tg-" + uuid.NewString() post(ruExt, "ru", "verudit_ru-scrabble_en") if got, want := reload(ruExt), []string{"erudit_ru", "scrabble_ru"}; !slices.Equal(got, want) { t.Errorf("russian promo account variants = %v, want %v", got, want) } // A brand-new account with no promo payload keeps the default. plainExt := "tg-" + uuid.NewString() post(plainExt, "en", "") if got, want := reload(plainExt), []string{"erudit_ru", "scrabble_ru"}; !slices.Equal(got, want) { t.Errorf("plain new account variants = %v, want %v", got, want) } // A later login of the promo account, even via a different payload, must not re-seed: // the seed is first-contact only. post(promoExt, "en", "vscrabble_ru") if got, want := reload(promoExt), []string{"erudit_ru", "scrabble_ru", "scrabble_en"}; !slices.Equal(got, want) { t.Errorf("existing account re-seeded = %v, want unchanged %v", got, want) } }