package server import ( "encoding/json" "net/http" "testing" ) // TestProfilePayloadCarriesCustomStatusEmoji: редактор профиля читает это поле // у `GET /users/@me` и вызывает `.trim()`, поэтому поле обязано приходить // всегда — пустая строка, а не отсутствие ключа (иначе открытие настроек // падает с «Cannot read properties of undefined»). func TestProfilePayloadCarriesCustomStatusEmoji(t *testing.T) { srv, _ := newTestServer(t) cookie := registerAndLogin(t, srv, "profile_emoji", "profile-emoji@example.com") rec := doJSON(t, srv, http.MethodGet, "/api/v1/users/@me", "", cookie) payload := decodeResponse[struct { User struct { CustomStatus string `json:"custom_status"` CustomStatusEmoji string `json:"custom_status_emoji"` } `json:"user"` }](t, rec) if payload.User.CustomStatus != "" || payload.User.CustomStatusEmoji != "" { t.Fatalf("у нового пользователя статус пустой: %+v", payload.User) } if rec.Body.String() == "" || !jsonHasKey(rec.Body.Bytes(), "custom_status_emoji") { t.Fatalf("в ответе нет custom_status_emoji: %s", rec.Body.String()) } updated := doJSON(t, srv, http.MethodPatch, "/api/v1/users/@me", `{"custom_status":"Пишу код","custom_status_emoji":"💻"}`, cookie) if updated.Code != http.StatusOK { t.Fatalf("PATCH профиля = %d, body = %s", updated.Code, updated.Body.String()) } after := decodeResponse[struct { User struct { CustomStatus string `json:"custom_status"` CustomStatusEmoji string `json:"custom_status_emoji"` } `json:"user"` }](t, updated) if after.User.CustomStatus != "Пишу код" || after.User.CustomStatusEmoji != "💻" { t.Fatalf("статус не сохранился: %+v", after.User) } } // jsonHasKey проверяет наличие ключа в JSON-ответе (в т.ч. с пустым значением). func jsonHasKey(body []byte, key string) bool { var decoded map[string]any if err := json.Unmarshal(body, &decoded); err != nil { return false } user, ok := decoded["user"].(map[string]any) if !ok { return false } _, present := user[key] return present }