package push import ( "strings" "testing" "glchat/internal/store" ) // input — сообщение по умолчанию: обычное сообщение в комнате сервера. // Набор проверок повторяет web/tests/desktopNotifications.test.ts: правила // push и нативных уведомлений обязаны совпадать. func input(overrides func(*NotificationInput)) NotificationInput { value := NotificationInput{ MessageType: store.MessageDefault, Content: "привет", Mentions: nil, AuthorID: 2, MeID: 1, IsDirect: false, ChannelName: "общий", ChannelID: 10, MessageID: 99, GuildID: 1, GuildName: "Сервер", AuthorName: "Аня", } if overrides != nil { overrides(&value) } return value } func TestNotificationForMention(t *testing.T) { payload := NotificationFor(input(func(in *NotificationInput) { in.Mentions = []uint64{1} })) if payload == nil { t.Fatal("упоминание не дало уведомления") } if payload.Title != "Упоминание в #общий" || payload.Body != "привет" { t.Fatalf("неожиданный текст: %+v", payload) } if payload.Kind != "mention" || payload.ChannelID != "10" || payload.Tag != "channel-10" { t.Fatalf("неожиданные поля: %+v", payload) } if payload.URL != "/app/1/10" { t.Fatalf("ссылка = %q, ожидалось /app/1/10", payload.URL) } } func TestNotificationForDirect(t *testing.T) { payload := NotificationFor(input(func(in *NotificationInput) { in.IsDirect = true in.GuildID = 0 in.GuildName = "" in.ChannelName = "Аня" })) if payload == nil { t.Fatal("личное сообщение не дало уведомления") } if payload.Title != "Личное сообщение — Аня" || payload.Kind != "direct" { t.Fatalf("неожиданный текст: %+v", payload) } if payload.URL != "/app/friends/10" { t.Fatalf("ссылка = %q, ожидалось /app/friends/10", payload.URL) } } func TestNotificationForSilentCases(t *testing.T) { cases := map[string]NotificationInput{ "обычное сообщение в комнате": input(nil), "своё сообщение": input(func(in *NotificationInput) { in.IsDirect = true in.AuthorID = in.MeID }), "системное сообщение": input(func(in *NotificationInput) { in.IsDirect = true in.MessageType = store.MessageSystem }), "получатель в клиенте": input(func(in *NotificationInput) { in.IsDirect = true in.Mentions = []uint64{1} in.Online = true }), "упоминание другого пользователя": input(func(in *NotificationInput) { in.Mentions = []uint64{777} }), "пустое сообщение без упоминаний": input(func(in *NotificationInput) { in.IsDirect = true in.Content = "" }), } for name, value := range cases { if payload := NotificationFor(value); payload != nil { t.Errorf("%s: уведомление не должно отправляться (%+v)", name, payload) } } } // Упоминание с пустым текстом (одно вложение) — как в клиенте: «Вложение». func TestNotificationForAttachmentOnly(t *testing.T) { payload := NotificationFor(input(func(in *NotificationInput) { in.IsDirect = true in.Content = "" in.Mentions = []uint64{1} })) if payload == nil || payload.Body != "Вложение" { t.Fatalf("ожидалось «Вложение», получили %+v", payload) } } func TestPreviewText(t *testing.T) { if got := previewText("**жирный**\n\n[ссылка](https://example.com) `код`"); got != "жирный ссылка код" { t.Fatalf("previewText = %q", got) } if got := previewText("```go\nfunc main() {}\n``` после"); got != "[код] после" { t.Fatalf("блок кода = %q", got) } long := previewText(strings.Repeat("а", 400)) if len([]rune(long)) > previewLimit { t.Fatalf("длина превью %d превышает лимит %d", len([]rune(long)), previewLimit) } if !strings.HasSuffix(long, "…") { t.Fatalf("длинный текст не обрезан: %q", long) } } func TestFormatOptionalID(t *testing.T) { if got := formatOptionalID(0); got != "" { t.Fatalf("нулевой идентификатор = %q, ожидалась пустая строка", got) } if got := formatOptionalID(42); got != "42" { t.Fatalf("идентификатор = %q", got) } }