Files
kanban/backend/notifications_test.go
egutierrez 2524340759 chore: auto-commit (21 archivos)
- app.md
- backend/dist/assets/index-D_Kep7Fb.js
- backend/dist/index.html
- backend/handlers.go
- backend/main.go
- frontend/src/App.tsx
- frontend/src/api.ts
- frontend/src/components/CardChatPanel.tsx
- frontend/src/components/LoginPage.tsx
- frontend/src/types.ts
- ...

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 18:17:04 +02:00

180 lines
5.3 KiB
Go

package main
import (
"reflect"
"sort"
"testing"
)
func TestExtractMentions(t *testing.T) {
cases := []struct {
in string
want []string
}{
{"hola @alice", []string{"alice"}},
{"@Bob y @bob mismo", []string{"bob"}},
{"sin menciones", nil},
{"email@foo.com no cuenta como @real_user", []string{"foo.com", "real_user"}},
{"@a-b-c y @d.e", []string{"a-b-c", "d.e"}},
}
for _, c := range cases {
got := extractMentions(c.in)
sort.Strings(got)
sort.Strings(c.want)
if !reflect.DeepEqual(got, c.want) {
t.Errorf("extractMentions(%q) = %v, want %v", c.in, got, c.want)
}
}
}
func mkUser(t *testing.T, db *DB, username string) string {
t.Helper()
u, err := db.CreateUser(username, "passw", username)
if err != nil {
t.Fatalf("CreateUser %q: %v", username, err)
}
return u.ID
}
func mkCard(t *testing.T, db *DB, columnID, requester, title, assigneeID string) string {
t.Helper()
c, err := db.CreateCard(columnID, requester, title, "", "")
if err != nil {
t.Fatalf("CreateCard: %v", err)
}
if assigneeID != "" {
if err := db.UpdateCardWithActor(c.ID, CardPatch{AssigneeID: &assigneeID, HasAssignee: true}, ""); err != nil {
t.Fatalf("assign: %v", err)
}
}
return c.ID
}
func TestCreateCardMessageAndNotify_AssigneeAndPreviousAuthors(t *testing.T) {
db := setupTestDB(t)
alice := mkUser(t, db, "alice")
bob := mkUser(t, db, "bob")
carol := mkUser(t, db, "carol")
col, err := db.CreateColumn("Todo")
if err != nil {
t.Fatalf("CreateColumn: %v", err)
}
card := mkCard(t, db, col.ID, "x", "card", bob)
// 1) alice writes; bob is assignee → bob gets assigned_chat.
_, notifs, _, err := db.CreateCardMessageAndNotify(card, alice, "hola", nil)
if err != nil {
t.Fatalf("create msg: %v", err)
}
if len(notifs) != 1 || notifs[0].UserID != bob || notifs[0].Kind != NotifKindAssignedChat {
t.Fatalf("expected single assigned_chat for bob, got %+v", notifs)
}
// 2) carol replies (carol is neither assignee nor previous author).
// alice (previous author) gets reply; bob (assignee) gets assigned_chat.
_, notifs, _, err = db.CreateCardMessageAndNotify(card, carol, "hola alice", nil)
if err != nil {
t.Fatalf("create msg: %v", err)
}
gotKinds := map[string]string{}
for _, n := range notifs {
gotKinds[n.UserID] = n.Kind
}
wantKinds := map[string]string{alice: NotifKindReply, bob: NotifKindAssignedChat}
if !reflect.DeepEqual(gotKinds, wantKinds) {
t.Fatalf("kinds = %+v, want %+v", gotKinds, wantKinds)
}
}
func TestCreateCardMessageAndNotify_MentionsBeatOtherKinds(t *testing.T) {
db := setupTestDB(t)
alice := mkUser(t, db, "alice")
bob := mkUser(t, db, "bob")
col, _ := db.CreateColumn("Todo")
card := mkCard(t, db, col.ID, "x", "card", bob) // bob is assignee
// alice mentions bob explicitly → kind must be 'mention', not 'assigned_chat'.
_, notifs, mentions, err := db.CreateCardMessageAndNotify(card, alice, "oye @bob mira esto", nil)
if err != nil {
t.Fatalf("create: %v", err)
}
if len(mentions) != 1 || mentions[0].UserID != bob {
t.Fatalf("mentions = %+v, want [bob]", mentions)
}
if len(notifs) != 1 || notifs[0].UserID != bob || notifs[0].Kind != NotifKindMention {
t.Fatalf("notifs = %+v, want single mention for bob", notifs)
}
}
func TestCreateCardMessageAndNotify_UnknownMentionsIgnored(t *testing.T) {
db := setupTestDB(t)
alice := mkUser(t, db, "alice")
col, _ := db.CreateColumn("Todo")
card := mkCard(t, db, col.ID, "x", "card", "")
_, notifs, mentions, err := db.CreateCardMessageAndNotify(card, alice, "hola @noexiste", nil)
if err != nil {
t.Fatalf("create: %v", err)
}
if len(mentions) != 0 || len(notifs) != 0 {
t.Fatalf("got mentions=%v notifs=%v, want empty", mentions, notifs)
}
}
func TestCreateCardMessageAndNotify_AuthorNeverSelfNotified(t *testing.T) {
db := setupTestDB(t)
alice := mkUser(t, db, "alice")
col, _ := db.CreateColumn("Todo")
card := mkCard(t, db, col.ID, "x", "card", alice) // alice is assignee
// alice mentions herself + is assignee → no notification.
_, notifs, _, err := db.CreateCardMessageAndNotify(card, alice, "monologo @alice", nil)
if err != nil {
t.Fatalf("create: %v", err)
}
if len(notifs) != 0 {
t.Fatalf("notifs = %+v, want empty (self)", notifs)
}
}
func TestListAndMarkRead(t *testing.T) {
db := setupTestDB(t)
alice := mkUser(t, db, "alice")
bob := mkUser(t, db, "bob")
col, _ := db.CreateColumn("Todo")
card := mkCard(t, db, col.ID, "x", "card", bob)
_, _, _, _ = db.CreateCardMessageAndNotify(card, alice, "1", nil)
_, _, _, _ = db.CreateCardMessageAndNotify(card, alice, "2", nil)
got, err := db.ListNotifications(bob, true, 0)
if err != nil {
t.Fatalf("list: %v", err)
}
if len(got) != 2 {
t.Fatalf("len = %d, want 2", len(got))
}
if n, _ := db.CountUnreadNotifications(bob); n != 2 {
t.Fatalf("unread count = %d, want 2", n)
}
if err := db.MarkNotificationRead(bob, got[0].ID); err != nil {
t.Fatalf("mark read: %v", err)
}
if n, _ := db.CountUnreadNotifications(bob); n != 1 {
t.Fatalf("unread count after mark = %d, want 1", n)
}
// idempotent
if err := db.MarkNotificationRead(bob, got[0].ID); err != nil {
t.Fatalf("mark read 2nd time: %v", err)
}
if n, _ := db.MarkAllNotificationsRead(bob); n != 1 {
t.Fatalf("mark all = %d, want 1", n)
}
if n, _ := db.CountUnreadNotifications(bob); n != 0 {
t.Fatalf("unread count after mark-all = %d, want 0", n)
}
}