- Add hub_test.go: register/unregister, join/leave room, broadcast, exclude sender, send to user, multiple clients same user (6 tests) - Add handler_messages_test.go: send message, missing fields, edit ownership check, soft delete (4 tests) - Add handler_realtime_test.go: typing broadcast, read receipts, reactions add/remove, delivered status (5 tests) - Add e2e_chat_ws_test.go: auth valid, missing token, invalid token, ping/pong - Add e2e_chat_messages_test.go: 2-client message flow, typing indicator - Create CHAT_FEATURE_PARITY.md: 25-feature checklist (all OK or IMPROVED)
173 lines
4.2 KiB
Go
173 lines
4.2 KiB
Go
package chat
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"testing"
|
|
"time"
|
|
|
|
"veza-backend-api/internal/models"
|
|
|
|
"github.com/google/uuid"
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
func TestHandleTyping_BroadcastsToOthers(t *testing.T) {
|
|
handler, hub, db := setupTestHandler(t)
|
|
ctx := context.Background()
|
|
|
|
user1 := uuid.New()
|
|
user2 := uuid.New()
|
|
roomID := uuid.New()
|
|
|
|
db.Exec("CREATE TABLE IF NOT EXISTS room_members (user_id TEXT, room_id TEXT, role TEXT DEFAULT 'member', is_muted INTEGER DEFAULT 0)")
|
|
|
|
client1 := newTestClient(hub, user1)
|
|
client2 := newTestClient(hub, user2)
|
|
hub.Register(client1)
|
|
hub.Register(client2)
|
|
hub.JoinRoom(client1, roomID)
|
|
hub.JoinRoom(client2, roomID)
|
|
time.Sleep(20 * time.Millisecond)
|
|
|
|
isTyping := true
|
|
msg := &IncomingMessage{
|
|
Type: TypeTyping,
|
|
ConversationID: &roomID,
|
|
IsTyping: &isTyping,
|
|
}
|
|
|
|
handler.HandleTyping(ctx, client1, msg)
|
|
time.Sleep(20 * time.Millisecond)
|
|
|
|
// client1 gets ActionConfirmed, client2 gets UserTyping broadcast
|
|
assert.GreaterOrEqual(t, len(client1.send), 1)
|
|
assert.GreaterOrEqual(t, len(client2.send), 1)
|
|
|
|
typingResp := <-client2.send
|
|
var parsed map[string]interface{}
|
|
json.Unmarshal(typingResp, &parsed)
|
|
assert.Equal(t, TypeUserTyping, parsed["type"])
|
|
assert.Equal(t, true, parsed["is_typing"])
|
|
}
|
|
|
|
func TestHandleMarkAsRead_PersistsReceipt(t *testing.T) {
|
|
handler, hub, db := setupTestHandler(t)
|
|
ctx := context.Background()
|
|
|
|
userID := uuid.New()
|
|
roomID := uuid.New()
|
|
msgID := uuid.New()
|
|
|
|
client := newTestClient(hub, userID)
|
|
hub.Register(client)
|
|
hub.JoinRoom(client, roomID)
|
|
time.Sleep(20 * time.Millisecond)
|
|
|
|
msg := &IncomingMessage{
|
|
Type: TypeMarkAsRead,
|
|
ConversationID: &roomID,
|
|
MessageID: &msgID,
|
|
}
|
|
|
|
handler.HandleMarkAsRead(ctx, client, msg)
|
|
time.Sleep(20 * time.Millisecond)
|
|
|
|
var count int64
|
|
db.Model(&models.ReadReceipt{}).Where("user_id = ? AND message_id = ?", userID, msgID).Count(&count)
|
|
assert.Equal(t, int64(1), count)
|
|
}
|
|
|
|
func TestHandleAddReaction_PersistsAndBroadcasts(t *testing.T) {
|
|
handler, hub, db := setupTestHandler(t)
|
|
ctx := context.Background()
|
|
|
|
userID := uuid.New()
|
|
roomID := uuid.New()
|
|
msgID := uuid.New()
|
|
|
|
client := newTestClient(hub, userID)
|
|
hub.Register(client)
|
|
hub.JoinRoom(client, roomID)
|
|
time.Sleep(20 * time.Millisecond)
|
|
|
|
msg := &IncomingMessage{
|
|
Type: TypeAddReaction,
|
|
ConversationID: &roomID,
|
|
MessageID: &msgID,
|
|
Emoji: "👍",
|
|
}
|
|
|
|
handler.HandleAddReaction(ctx, client, msg)
|
|
time.Sleep(20 * time.Millisecond)
|
|
|
|
var count int64
|
|
db.Model(&models.MessageReaction{}).Where("user_id = ? AND message_id = ?", userID, msgID).Count(&count)
|
|
assert.Equal(t, int64(1), count)
|
|
|
|
// Check broadcast
|
|
assert.GreaterOrEqual(t, len(client.send), 1)
|
|
}
|
|
|
|
func TestHandleRemoveReaction_DeletesFromDB(t *testing.T) {
|
|
handler, hub, db := setupTestHandler(t)
|
|
ctx := context.Background()
|
|
|
|
userID := uuid.New()
|
|
roomID := uuid.New()
|
|
msgID := uuid.New()
|
|
|
|
reaction := &models.MessageReaction{
|
|
ID: uuid.New(),
|
|
UserID: userID,
|
|
MessageID: msgID,
|
|
Emoji: "👍",
|
|
CreatedAt: time.Now(),
|
|
}
|
|
db.Create(reaction)
|
|
|
|
client := newTestClient(hub, userID)
|
|
hub.Register(client)
|
|
hub.JoinRoom(client, roomID)
|
|
time.Sleep(20 * time.Millisecond)
|
|
|
|
msg := &IncomingMessage{
|
|
Type: TypeRemoveReaction,
|
|
ConversationID: &roomID,
|
|
MessageID: &msgID,
|
|
}
|
|
|
|
handler.HandleRemoveReaction(ctx, client, msg)
|
|
time.Sleep(20 * time.Millisecond)
|
|
|
|
var count int64
|
|
db.Model(&models.MessageReaction{}).Where("user_id = ? AND message_id = ?", userID, msgID).Count(&count)
|
|
assert.Equal(t, int64(0), count)
|
|
}
|
|
|
|
func TestHandleDelivered_PersistsStatus(t *testing.T) {
|
|
handler, hub, db := setupTestHandler(t)
|
|
ctx := context.Background()
|
|
|
|
userID := uuid.New()
|
|
roomID := uuid.New()
|
|
msgID := uuid.New()
|
|
|
|
client := newTestClient(hub, userID)
|
|
hub.Register(client)
|
|
hub.JoinRoom(client, roomID)
|
|
time.Sleep(20 * time.Millisecond)
|
|
|
|
msg := &IncomingMessage{
|
|
Type: TypeDelivered,
|
|
ConversationID: &roomID,
|
|
MessageID: &msgID,
|
|
}
|
|
|
|
handler.HandleDelivered(ctx, client, msg)
|
|
time.Sleep(20 * time.Millisecond)
|
|
|
|
var count int64
|
|
db.Model(&models.DeliveredStatus{}).Where("user_id = ? AND message_id = ?", userID, msgID).Count(&count)
|
|
assert.Equal(t, int64(1), count)
|
|
}
|