1081 lines
44 KiB
Go
1081 lines
44 KiB
Go
package widget
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"gorm.io/gorm"
|
|
|
|
"github.com/gochat/gochat/internal/model"
|
|
)
|
|
|
|
// ---------- widgetConversationPayload (via GetConversations /widget/conversations) ----------
|
|
|
|
func TestWidgetHandler_Cov3_GetConversationsEmptyList_Cov3(t *testing.T) {
|
|
db, router, _ := setupWidgetHandlerTest(t)
|
|
seedWidgetHandlerData(t, db)
|
|
|
|
wConfig := httptest.NewRecorder()
|
|
reqConfig, _ := http.NewRequest("POST", "/api/v1/widget/config?website_token=handler_ws_token_123", nil)
|
|
router.ServeHTTP(wConfig, reqConfig)
|
|
require.Equal(t, http.StatusOK, wConfig.Code)
|
|
var configResp map[string]interface{}
|
|
require.NoError(t, json.Unmarshal(wConfig.Body.Bytes(), &configResp))
|
|
authToken := configResp["contact"].(map[string]interface{})["pubsub_token"].(string)
|
|
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("GET", "/widget/conversations", nil)
|
|
req.Header.Set("X-Auth-Token", authToken)
|
|
router.ServeHTTP(w, req)
|
|
require.Equal(t, http.StatusOK, w.Code)
|
|
|
|
var resp map[string]interface{}
|
|
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp))
|
|
convs, ok := resp["conversations"].([]interface{})
|
|
assert.True(t, ok, "should have conversations array")
|
|
assert.Empty(t, convs)
|
|
}
|
|
|
|
func TestWidgetHandler_Cov3_GetConversationsReturnsPayload_Cov3(t *testing.T) {
|
|
db, router, _ := setupWidgetHandlerTest(t)
|
|
_, inbox := seedWidgetHandlerData(t, db)
|
|
|
|
wConfig := httptest.NewRecorder()
|
|
reqConfig, _ := http.NewRequest("POST", "/api/v1/widget/config?website_token=handler_ws_token_123", nil)
|
|
router.ServeHTTP(wConfig, reqConfig)
|
|
require.Equal(t, http.StatusOK, wConfig.Code)
|
|
var configResp map[string]interface{}
|
|
require.NoError(t, json.Unmarshal(wConfig.Body.Bytes(), &configResp))
|
|
authToken := configResp["contact"].(map[string]interface{})["pubsub_token"].(string)
|
|
|
|
messageBody, _ := json.Marshal(map[string]interface{}{"message": map[string]interface{}{"content": "hello world"}})
|
|
wMsg := httptest.NewRecorder()
|
|
reqMsg, _ := http.NewRequest("POST", "/api/v1/widget/messages?cw_conversation="+authToken, bytes.NewReader(messageBody))
|
|
reqMsg.Header.Set("Content-Type", "application/json")
|
|
router.ServeHTTP(wMsg, reqMsg)
|
|
require.Equal(t, http.StatusOK, wMsg.Code, wMsg.Body.String())
|
|
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("GET", "/widget/conversations", nil)
|
|
req.Header.Set("X-Auth-Token", authToken)
|
|
router.ServeHTTP(w, req)
|
|
require.Equal(t, http.StatusOK, w.Code)
|
|
|
|
var resp map[string]interface{}
|
|
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp))
|
|
convs, ok := resp["conversations"].([]interface{})
|
|
assert.True(t, ok, "should have conversations array")
|
|
require.Len(t, convs, 1)
|
|
convMap := convs[0].(map[string]interface{})
|
|
assert.NotNil(t, convMap["id"])
|
|
assert.NotNil(t, convMap["uuid"])
|
|
assert.Equal(t, float64(inbox.ID), convMap["inbox_id"])
|
|
assert.NotNil(t, convMap["status"])
|
|
assert.NotNil(t, convMap["custom_attributes"])
|
|
}
|
|
|
|
func TestWidgetHandler_Cov3_GetConversationsNoToken_Cov3(t *testing.T) {
|
|
_, router, _ := setupWidgetHandlerTest(t)
|
|
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("GET", "/widget/conversations", nil)
|
|
router.ServeHTTP(w, req)
|
|
assert.Equal(t, http.StatusUnauthorized, w.Code)
|
|
}
|
|
|
|
func TestWidgetHandler_Cov3_GetConversationsInvalidToken_Cov3(t *testing.T) {
|
|
_, router, _ := setupWidgetHandlerTest(t)
|
|
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("GET", "/widget/conversations?widget_token=invalid", nil)
|
|
router.ServeHTTP(w, req)
|
|
// Invalid token returns 400 (generic error, not "invalid widget_token")
|
|
assert.True(t, w.Code == http.StatusUnauthorized || w.Code == http.StatusBadRequest, "expected 401 or 400, got %d", w.Code)
|
|
}
|
|
|
|
// ---------- CreateConversation ----------
|
|
|
|
func TestWidgetHandler_Cov3_CreateConversation_NoToken_Cov3(t *testing.T) {
|
|
_, router, _ := setupWidgetHandlerTest(t)
|
|
|
|
w := httptest.NewRecorder()
|
|
body, _ := json.Marshal(map[string]interface{}{"message": map[string]interface{}{"content": "hi"}})
|
|
req, _ := http.NewRequest("POST", "/api/v1/widget/conversations", bytes.NewReader(body))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
router.ServeHTTP(w, req)
|
|
assert.Equal(t, http.StatusUnauthorized, w.Code)
|
|
}
|
|
|
|
func TestWidgetHandler_Cov3_CreateConversation_InvalidBody_Cov3(t *testing.T) {
|
|
_, router, _ := setupWidgetHandlerTest(t)
|
|
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("POST", "/api/v1/widget/conversations", bytes.NewReader([]byte("not json")))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
req.Header.Set("X-Auth-Token", "some-token")
|
|
router.ServeHTTP(w, req)
|
|
assert.Equal(t, http.StatusBadRequest, w.Code)
|
|
}
|
|
|
|
func TestWidgetHandler_Cov3_CreateConversation_InvalidToken_Cov3(t *testing.T) {
|
|
_, router, _ := setupWidgetHandlerTest(t)
|
|
|
|
w := httptest.NewRecorder()
|
|
body, _ := json.Marshal(map[string]interface{}{"message": map[string]interface{}{"content": "hi"}})
|
|
req, _ := http.NewRequest("POST", "/api/v1/widget/conversations?cw_conversation=invalid-token", bytes.NewReader(body))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
router.ServeHTTP(w, req)
|
|
assert.Equal(t, http.StatusBadRequest, w.Code)
|
|
}
|
|
|
|
func TestWidgetHandler_Cov3_CreateConversation_Success_Cov3(t *testing.T) {
|
|
db, router, _ := setupWidgetHandlerTest(t)
|
|
_, inbox := seedWidgetHandlerData(t, db)
|
|
|
|
wConfig := httptest.NewRecorder()
|
|
reqConfig, _ := http.NewRequest("POST", "/api/v1/widget/config?website_token=handler_ws_token_123", nil)
|
|
router.ServeHTTP(wConfig, reqConfig)
|
|
require.Equal(t, http.StatusOK, wConfig.Code)
|
|
var configResp map[string]interface{}
|
|
require.NoError(t, json.Unmarshal(wConfig.Body.Bytes(), &configResp))
|
|
authToken := configResp["contact"].(map[string]interface{})["pubsub_token"].(string)
|
|
|
|
w := httptest.NewRecorder()
|
|
body, _ := json.Marshal(map[string]interface{}{"message": map[string]interface{}{"content": "new conversation message"}})
|
|
req, _ := http.NewRequest("POST", "/api/v1/widget/conversations?cw_conversation="+authToken, bytes.NewReader(body))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
router.ServeHTTP(w, req)
|
|
require.Equal(t, http.StatusOK, w.Code, w.Body.String())
|
|
|
|
var resp map[string]interface{}
|
|
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp))
|
|
assert.NotNil(t, resp["id"])
|
|
msgs, ok := resp["messages"].([]interface{})
|
|
assert.True(t, ok, "should have messages array")
|
|
if len(msgs) > 0 {
|
|
msg := msgs[0].(map[string]interface{})
|
|
assert.Equal(t, "new conversation message", msg["content"])
|
|
}
|
|
|
|
var conv model.Conversation
|
|
require.NoError(t, db.Where("inbox_id = ?", inbox.ID).First(&conv).Error)
|
|
}
|
|
|
|
// ---------- PublicGetContact ----------
|
|
|
|
func TestWidgetHandler_Cov3_PublicGetContact_Success_Cov3(t *testing.T) {
|
|
db, router, _ := setupWidgetHandlerTest(t)
|
|
_, inbox, channelAPI := seedPublicAPIInbox(t, db)
|
|
|
|
createBody, _ := json.Marshal(map[string]interface{}{
|
|
"name": "Test Contact",
|
|
"email": "test@example.com",
|
|
"phone_number": "+1234567890",
|
|
})
|
|
wCreate := httptest.NewRecorder()
|
|
reqCreate, _ := http.NewRequest("POST", "/public/api/v1/inboxes/"+channelAPI.Identifier+"/contacts", bytes.NewReader(createBody))
|
|
reqCreate.Header.Set("Content-Type", "application/json")
|
|
router.ServeHTTP(wCreate, reqCreate)
|
|
require.Equal(t, http.StatusOK, wCreate.Code, wCreate.Body.String())
|
|
|
|
var createResp map[string]interface{}
|
|
require.NoError(t, json.Unmarshal(wCreate.Body.Bytes(), &createResp))
|
|
sourceID := createResp["source_id"].(string)
|
|
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("GET", "/public/api/v1/inboxes/"+channelAPI.Identifier+"/contacts/"+sourceID, nil)
|
|
router.ServeHTTP(w, req)
|
|
require.Equal(t, http.StatusOK, w.Code, w.Body.String())
|
|
|
|
var resp map[string]interface{}
|
|
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp))
|
|
assert.Equal(t, sourceID, resp["source_id"])
|
|
assert.Equal(t, "Test Contact", resp["name"])
|
|
assert.Equal(t, "test@example.com", resp["email"])
|
|
assert.Equal(t, "+1234567890", resp["phone_number"])
|
|
assert.NotNil(t, resp["id"])
|
|
assert.NotNil(t, resp["pubsub_token"])
|
|
|
|
_ = inbox
|
|
}
|
|
|
|
func TestWidgetHandler_Cov3_PublicGetContact_NotFound_Cov3(t *testing.T) {
|
|
db, router, _ := setupWidgetHandlerTest(t)
|
|
_, _, channelAPI := seedPublicAPIInbox(t, db)
|
|
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("GET", "/public/api/v1/inboxes/"+channelAPI.Identifier+"/contacts/nonexistent-source-id", nil)
|
|
router.ServeHTTP(w, req)
|
|
assert.True(t, w.Code == http.StatusNotFound || w.Code == http.StatusBadRequest, "expected 404 or 400, got %d: %s", w.Code, w.Body.String())
|
|
}
|
|
|
|
func TestWidgetHandler_Cov3_PublicGetContact_InvalidInbox_Cov3(t *testing.T) {
|
|
_, router, _ := setupWidgetHandlerTest(t)
|
|
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("GET", "/public/api/v1/inboxes/nonexistent-inbox/contacts/some-id", nil)
|
|
router.ServeHTTP(w, req)
|
|
assert.True(t, w.Code == http.StatusNotFound || w.Code == http.StatusBadRequest, "expected 404 or 400, got %d: %s", w.Code, w.Body.String())
|
|
}
|
|
|
|
// ---------- uintFromPayload unit test ----------
|
|
|
|
func TestWidgetHandler_Cov3_UintFromPayload_Cov3(t *testing.T) {
|
|
assert.Equal(t, uint(42), uintFromPayload(uint(42)))
|
|
assert.Equal(t, uint(42), uintFromPayload(int(42)))
|
|
assert.Equal(t, uint(0), uintFromPayload(int(-1)))
|
|
assert.Equal(t, uint(42), uintFromPayload(int64(42)))
|
|
assert.Equal(t, uint(0), uintFromPayload(int64(-1)))
|
|
assert.Equal(t, uint(42), uintFromPayload(float64(42)))
|
|
assert.Equal(t, uint(0), uintFromPayload(float64(-1)))
|
|
assert.Equal(t, uint(0), uintFromPayload("not a number"))
|
|
assert.Equal(t, uint(0), uintFromPayload(nil))
|
|
assert.Equal(t, uint(0), uintFromPayload(uint(0)))
|
|
}
|
|
|
|
// ---------- GetCableToken ----------
|
|
|
|
func TestWidgetHandler_Cov3_GetCableToken_NoToken_Cov3(t *testing.T) {
|
|
_, router, _ := setupWidgetHandlerTest(t)
|
|
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("GET", "/widget/cable_token", nil)
|
|
router.ServeHTTP(w, req)
|
|
assert.Equal(t, http.StatusUnauthorized, w.Code)
|
|
}
|
|
|
|
func TestWidgetHandler_Cov3_GetCableToken_InvalidToken_Cov3(t *testing.T) {
|
|
_, router, _ := setupWidgetHandlerTest(t)
|
|
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("GET", "/widget/cable_token?widget_token=invalid", nil)
|
|
router.ServeHTTP(w, req)
|
|
assert.True(t, w.Code == http.StatusUnauthorized || w.Code == http.StatusBadRequest, "expected 401 or 400, got %d", w.Code)
|
|
}
|
|
|
|
func TestWidgetHandler_Cov3_GetCableToken_Success_Cov3(t *testing.T) {
|
|
db, router, _ := setupWidgetHandlerTest(t)
|
|
seedWidgetHandlerData(t, db)
|
|
|
|
wConfig := httptest.NewRecorder()
|
|
reqConfig, _ := http.NewRequest("POST", "/api/v1/widget/config?website_token=handler_ws_token_123", nil)
|
|
router.ServeHTTP(wConfig, reqConfig)
|
|
require.Equal(t, http.StatusOK, wConfig.Code)
|
|
var configResp map[string]interface{}
|
|
require.NoError(t, json.Unmarshal(wConfig.Body.Bytes(), &configResp))
|
|
authToken := configResp["contact"].(map[string]interface{})["pubsub_token"].(string)
|
|
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("GET", "/widget/cable_token?widget_token="+authToken, nil)
|
|
router.ServeHTTP(w, req)
|
|
require.Equal(t, http.StatusOK, w.Code, w.Body.String())
|
|
}
|
|
|
|
// ---------- GetContact no token (chatwoot route → 404) ----------
|
|
|
|
func TestWidgetHandler_Cov3_GetContact_NoToken_ChatwootRoute_Cov3(t *testing.T) {
|
|
_, router, _ := setupWidgetHandlerTest(t)
|
|
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("GET", "/api/v1/widget/contact", nil)
|
|
router.ServeHTTP(w, req)
|
|
assert.Equal(t, http.StatusNotFound, w.Code)
|
|
}
|
|
|
|
func TestWidgetHandler_Cov3_GetContact_NoToken_WidgetRoute_Cov3(t *testing.T) {
|
|
_, router, _ := setupWidgetHandlerTest(t)
|
|
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("GET", "/widget/contact", nil)
|
|
router.ServeHTTP(w, req)
|
|
// /widget/contact is not a registered route — 404 from router
|
|
assert.Equal(t, http.StatusNotFound, w.Code)
|
|
}
|
|
|
|
func TestWidgetHandler_Cov3_GetContact_Success_Cov3(t *testing.T) {
|
|
db, router, _ := setupWidgetHandlerTest(t)
|
|
seedWidgetHandlerData(t, db)
|
|
|
|
wConfig := httptest.NewRecorder()
|
|
reqConfig, _ := http.NewRequest("POST", "/api/v1/widget/config?website_token=handler_ws_token_123", nil)
|
|
router.ServeHTTP(wConfig, reqConfig)
|
|
require.Equal(t, http.StatusOK, wConfig.Code)
|
|
var configResp map[string]interface{}
|
|
require.NoError(t, json.Unmarshal(wConfig.Body.Bytes(), &configResp))
|
|
authToken := configResp["contact"].(map[string]interface{})["pubsub_token"].(string)
|
|
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("GET", "/api/v1/widget/contact?cw_conversation="+authToken, nil)
|
|
router.ServeHTTP(w, req)
|
|
require.Equal(t, http.StatusOK, w.Code, w.Body.String())
|
|
|
|
var resp map[string]interface{}
|
|
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp))
|
|
assert.NotNil(t, resp["id"])
|
|
}
|
|
|
|
// ---------- UpdateContact no token (chatwoot route → 404) ----------
|
|
|
|
func TestWidgetHandler_Cov3_UpdateContact_NoToken_ChatwootRoute_Cov3(t *testing.T) {
|
|
_, router, _ := setupWidgetHandlerTest(t)
|
|
|
|
body, _ := json.Marshal(map[string]interface{}{"name": "Test"})
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("PATCH", "/api/v1/widget/contact", bytes.NewReader(body))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
router.ServeHTTP(w, req)
|
|
assert.Equal(t, http.StatusNotFound, w.Code)
|
|
}
|
|
|
|
func TestWidgetHandler_Cov3_UpdateContact_Success_Cov3(t *testing.T) {
|
|
db, router, _ := setupWidgetHandlerTest(t)
|
|
seedWidgetHandlerData(t, db)
|
|
|
|
wConfig := httptest.NewRecorder()
|
|
reqConfig, _ := http.NewRequest("POST", "/api/v1/widget/config?website_token=handler_ws_token_123", nil)
|
|
router.ServeHTTP(wConfig, reqConfig)
|
|
require.Equal(t, http.StatusOK, wConfig.Code)
|
|
var configResp map[string]interface{}
|
|
require.NoError(t, json.Unmarshal(wConfig.Body.Bytes(), &configResp))
|
|
authToken := configResp["contact"].(map[string]interface{})["pubsub_token"].(string)
|
|
|
|
body, _ := json.Marshal(map[string]interface{}{"name": "Updated Name"})
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("PATCH", "/api/v1/widget/contact?cw_conversation="+authToken, bytes.NewReader(body))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
router.ServeHTTP(w, req)
|
|
require.Equal(t, http.StatusOK, w.Code, w.Body.String())
|
|
|
|
var resp map[string]interface{}
|
|
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp))
|
|
assert.NotNil(t, resp["id"])
|
|
assert.Equal(t, true, resp["has_name"])
|
|
}
|
|
|
|
// ---------- UpdateContact invalid body ----------
|
|
|
|
func TestWidgetHandler_Cov3_UpdateContact_InvalidBody_Cov3(t *testing.T) {
|
|
_, router, _ := setupWidgetHandlerTest(t)
|
|
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("PATCH", "/api/v1/widget/contact?cw_conversation=some-token", bytes.NewReader([]byte("not json")))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
router.ServeHTTP(w, req)
|
|
assert.Equal(t, http.StatusBadRequest, w.Code)
|
|
}
|
|
|
|
// ---------- DestroyContactCustomAttributes ----------
|
|
|
|
func TestWidgetHandler_Cov3_DestroyContactAttrs_NoToken_ChatwootRoute_Cov3(t *testing.T) {
|
|
_, router, _ := setupWidgetHandlerTest(t)
|
|
|
|
body, _ := json.Marshal(map[string]interface{}{"custom_attributes": []string{"key1"}})
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("POST", "/api/v1/widget/destroy_custom_attributes", bytes.NewReader(body))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
router.ServeHTTP(w, req)
|
|
assert.Equal(t, http.StatusNotFound, w.Code)
|
|
}
|
|
|
|
func TestWidgetHandler_Cov3_DestroyContactAttrs_InvalidBody_Cov3(t *testing.T) {
|
|
_, router, _ := setupWidgetHandlerTest(t)
|
|
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("POST", "/api/v1/widget/destroy_custom_attributes?cw_conversation=some-token", bytes.NewReader([]byte("not json")))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
router.ServeHTTP(w, req)
|
|
assert.Equal(t, http.StatusBadRequest, w.Code)
|
|
}
|
|
|
|
// ---------- SetUser ----------
|
|
|
|
func TestWidgetHandler_Cov3_SetUser_NoToken_Cov3(t *testing.T) {
|
|
_, router, _ := setupWidgetHandlerTest(t)
|
|
|
|
body, _ := json.Marshal(map[string]interface{}{"identifier": "test"})
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("PATCH", "/api/v1/widget/contact/set_user", bytes.NewReader(body))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
router.ServeHTTP(w, req)
|
|
assert.Equal(t, http.StatusUnauthorized, w.Code)
|
|
}
|
|
|
|
func TestWidgetHandler_Cov3_SetUser_InvalidBody_Cov3(t *testing.T) {
|
|
_, router, _ := setupWidgetHandlerTest(t)
|
|
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("PATCH", "/api/v1/widget/contact/set_user?cw_conversation=some-token", bytes.NewReader([]byte("not json")))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
router.ServeHTTP(w, req)
|
|
assert.Equal(t, http.StatusBadRequest, w.Code)
|
|
}
|
|
|
|
// ---------- ToggleTyping ----------
|
|
|
|
func TestWidgetHandler_Cov3_ToggleTyping_NoToken_Cov3(t *testing.T) {
|
|
_, router, _ := setupWidgetHandlerTest(t)
|
|
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("POST", "/widget/conversations/1/toggle_typing", nil)
|
|
router.ServeHTTP(w, req)
|
|
assert.Equal(t, http.StatusUnauthorized, w.Code)
|
|
}
|
|
|
|
func TestWidgetHandler_Cov3_ToggleTyping_InvalidID_Cov3(t *testing.T) {
|
|
_, router, _ := setupWidgetHandlerTest(t)
|
|
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("POST", "/widget/conversations/abc/toggle_typing?cw_conversation=some-token", nil)
|
|
router.ServeHTTP(w, req)
|
|
assert.Equal(t, http.StatusBadRequest, w.Code)
|
|
}
|
|
|
|
func TestWidgetHandler_Cov3_ToggleTyping_Success_Cov3(t *testing.T) {
|
|
db, router, _ := setupWidgetHandlerTest(t)
|
|
seedWidgetHandlerData(t, db)
|
|
|
|
wConfig := httptest.NewRecorder()
|
|
reqConfig, _ := http.NewRequest("POST", "/api/v1/widget/config?website_token=handler_ws_token_123", nil)
|
|
router.ServeHTTP(wConfig, reqConfig)
|
|
require.Equal(t, http.StatusOK, wConfig.Code)
|
|
var configResp map[string]interface{}
|
|
require.NoError(t, json.Unmarshal(wConfig.Body.Bytes(), &configResp))
|
|
authToken := configResp["contact"].(map[string]interface{})["pubsub_token"].(string)
|
|
|
|
// Send message to create conversation
|
|
messageBody, _ := json.Marshal(map[string]interface{}{"message": map[string]interface{}{"content": "hello"}})
|
|
wMsg := httptest.NewRecorder()
|
|
reqMsg, _ := http.NewRequest("POST", "/api/v1/widget/messages?cw_conversation="+authToken, bytes.NewReader(messageBody))
|
|
reqMsg.Header.Set("Content-Type", "application/json")
|
|
router.ServeHTTP(wMsg, reqMsg)
|
|
require.Equal(t, http.StatusOK, wMsg.Code)
|
|
|
|
// Toggle typing without conversation ID (uses latest conversation)
|
|
w := httptest.NewRecorder()
|
|
body, _ := json.Marshal(map[string]interface{}{"typing_status": "on"})
|
|
req, _ := http.NewRequest("POST", "/api/v1/widget/conversations/toggle_typing?cw_conversation="+authToken, bytes.NewReader(body))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
router.ServeHTTP(w, req)
|
|
assert.Equal(t, http.StatusOK, w.Code)
|
|
}
|
|
|
|
// ---------- UpdateLastSeen ----------
|
|
|
|
func TestWidgetHandler_Cov3_UpdateLastSeen_NoToken_ChatwootRoute_Cov3(t *testing.T) {
|
|
_, router, _ := setupWidgetHandlerTest(t)
|
|
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("POST", "/api/v1/widget/conversations/update_last_seen", nil)
|
|
router.ServeHTTP(w, req)
|
|
assert.Equal(t, http.StatusNotFound, w.Code)
|
|
}
|
|
|
|
func TestWidgetHandler_Cov3_UpdateLastSeen_Success_Cov3(t *testing.T) {
|
|
db, router, _ := setupWidgetHandlerTest(t)
|
|
seedWidgetHandlerData(t, db)
|
|
|
|
wConfig := httptest.NewRecorder()
|
|
reqConfig, _ := http.NewRequest("POST", "/api/v1/widget/config?website_token=handler_ws_token_123", nil)
|
|
router.ServeHTTP(wConfig, reqConfig)
|
|
require.Equal(t, http.StatusOK, wConfig.Code)
|
|
var configResp map[string]interface{}
|
|
require.NoError(t, json.Unmarshal(wConfig.Body.Bytes(), &configResp))
|
|
authToken := configResp["contact"].(map[string]interface{})["pubsub_token"].(string)
|
|
|
|
// Send message to create conversation
|
|
messageBody, _ := json.Marshal(map[string]interface{}{"message": map[string]interface{}{"content": "hello"}})
|
|
wMsg := httptest.NewRecorder()
|
|
reqMsg, _ := http.NewRequest("POST", "/api/v1/widget/messages?cw_conversation="+authToken, bytes.NewReader(messageBody))
|
|
reqMsg.Header.Set("Content-Type", "application/json")
|
|
router.ServeHTTP(wMsg, reqMsg)
|
|
require.Equal(t, http.StatusOK, wMsg.Code)
|
|
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("POST", "/api/v1/widget/conversations/update_last_seen?cw_conversation="+authToken, nil)
|
|
router.ServeHTTP(w, req)
|
|
assert.Equal(t, http.StatusOK, w.Code)
|
|
}
|
|
|
|
// ---------- ToggleStatus ----------
|
|
|
|
func TestWidgetHandler_Cov3_ToggleStatus_NoToken_Cov3(t *testing.T) {
|
|
_, router, _ := setupWidgetHandlerTest(t)
|
|
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("GET", "/api/v1/widget/conversations/toggle_status", nil)
|
|
router.ServeHTTP(w, req)
|
|
assert.Equal(t, http.StatusUnauthorized, w.Code)
|
|
}
|
|
|
|
func TestWidgetHandler_Cov3_ToggleStatus_Success_Cov3(t *testing.T) {
|
|
db, router, _ := setupWidgetHandlerTest(t)
|
|
seedWidgetHandlerData(t, db)
|
|
|
|
wConfig := httptest.NewRecorder()
|
|
reqConfig, _ := http.NewRequest("POST", "/api/v1/widget/config?website_token=handler_ws_token_123", nil)
|
|
router.ServeHTTP(wConfig, reqConfig)
|
|
require.Equal(t, http.StatusOK, wConfig.Code)
|
|
var configResp map[string]interface{}
|
|
require.NoError(t, json.Unmarshal(wConfig.Body.Bytes(), &configResp))
|
|
authToken := configResp["contact"].(map[string]interface{})["pubsub_token"].(string)
|
|
|
|
// Send message to create conversation
|
|
messageBody, _ := json.Marshal(map[string]interface{}{"message": map[string]interface{}{"content": "hello"}})
|
|
wMsg := httptest.NewRecorder()
|
|
reqMsg, _ := http.NewRequest("POST", "/api/v1/widget/messages?cw_conversation="+authToken, bytes.NewReader(messageBody))
|
|
reqMsg.Header.Set("Content-Type", "application/json")
|
|
router.ServeHTTP(wMsg, reqMsg)
|
|
require.Equal(t, http.StatusOK, wMsg.Code)
|
|
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("GET", "/api/v1/widget/conversations/toggle_status?cw_conversation="+authToken, nil)
|
|
router.ServeHTTP(w, req)
|
|
assert.Equal(t, http.StatusOK, w.Code)
|
|
}
|
|
|
|
// ---------- SetConversationCustomAttributes ----------
|
|
|
|
func TestWidgetHandler_Cov3_SetConvAttrs_NoToken_ChatwootRoute_Cov3(t *testing.T) {
|
|
_, router, _ := setupWidgetHandlerTest(t)
|
|
|
|
body, _ := json.Marshal(map[string]interface{}{"custom_attributes": map[string]any{"key": "val"}})
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("POST", "/api/v1/widget/conversations/set_custom_attributes", bytes.NewReader(body))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
router.ServeHTTP(w, req)
|
|
assert.Equal(t, http.StatusNotFound, w.Code)
|
|
}
|
|
|
|
func TestWidgetHandler_Cov3_SetConvAttrs_InvalidBody_Cov3(t *testing.T) {
|
|
_, router, _ := setupWidgetHandlerTest(t)
|
|
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("POST", "/api/v1/widget/conversations/set_custom_attributes?cw_conversation=some-token", bytes.NewReader([]byte("not json")))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
router.ServeHTTP(w, req)
|
|
assert.Equal(t, http.StatusBadRequest, w.Code)
|
|
}
|
|
|
|
// ---------- DestroyConversationCustomAttributes ----------
|
|
|
|
func TestWidgetHandler_Cov3_DestroyConvAttrs_NoToken_ChatwootRoute_Cov3(t *testing.T) {
|
|
_, router, _ := setupWidgetHandlerTest(t)
|
|
|
|
body, _ := json.Marshal(map[string]interface{}{"custom_attribute": []string{"key1"}})
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("POST", "/api/v1/widget/conversations/destroy_custom_attributes", bytes.NewReader(body))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
router.ServeHTTP(w, req)
|
|
assert.Equal(t, http.StatusNotFound, w.Code)
|
|
}
|
|
|
|
func TestWidgetHandler_Cov3_DestroyConvAttrs_InvalidBody_Cov3(t *testing.T) {
|
|
_, router, _ := setupWidgetHandlerTest(t)
|
|
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("POST", "/api/v1/widget/conversations/destroy_custom_attributes?cw_conversation=some-token", bytes.NewReader([]byte("not json")))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
router.ServeHTTP(w, req)
|
|
assert.Equal(t, http.StatusBadRequest, w.Code)
|
|
}
|
|
|
|
// ---------- ListInboxMembers ----------
|
|
|
|
func TestWidgetHandler_Cov3_ListInboxMembers_NoToken_ChatwootRoute_Cov3(t *testing.T) {
|
|
_, router, _ := setupWidgetHandlerTest(t)
|
|
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("GET", "/api/v1/widget/inbox_members", nil)
|
|
router.ServeHTTP(w, req)
|
|
assert.Equal(t, http.StatusNotFound, w.Code)
|
|
}
|
|
|
|
func TestWidgetHandler_Cov3_ListInboxMembers_Success_Cov3(t *testing.T) {
|
|
db, router, _ := setupWidgetHandlerTest(t)
|
|
seedWidgetHandlerData(t, db)
|
|
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("GET", "/api/v1/widget/inbox_members?website_token=handler_ws_token_123", nil)
|
|
router.ServeHTTP(w, req)
|
|
require.Equal(t, http.StatusOK, w.Code, w.Body.String())
|
|
}
|
|
|
|
// ---------- ListCampaigns ----------
|
|
|
|
func TestWidgetHandler_Cov3_ListCampaigns_NoToken_ChatwootRoute_Cov3(t *testing.T) {
|
|
_, router, _ := setupWidgetHandlerTest(t)
|
|
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("GET", "/api/v1/widget/campaigns", nil)
|
|
router.ServeHTTP(w, req)
|
|
assert.Equal(t, http.StatusNotFound, w.Code)
|
|
}
|
|
|
|
func TestWidgetHandler_Cov3_ListCampaigns_Success_Cov3(t *testing.T) {
|
|
db, router, _ := setupWidgetHandlerTest(t)
|
|
seedWidgetHandlerData(t, db)
|
|
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("GET", "/api/v1/widget/campaigns?website_token=handler_ws_token_123", nil)
|
|
router.ServeHTTP(w, req)
|
|
require.Equal(t, http.StatusOK, w.Code, w.Body.String())
|
|
}
|
|
|
|
// ---------- CreateEvent ----------
|
|
|
|
func TestWidgetHandler_Cov3_CreateEvent_InvalidBody_Cov3(t *testing.T) {
|
|
_, router, _ := setupWidgetHandlerTest(t)
|
|
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("POST", "/api/v1/widget/events", bytes.NewReader([]byte("not json")))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
router.ServeHTTP(w, req)
|
|
assert.Equal(t, http.StatusBadRequest, w.Code)
|
|
}
|
|
|
|
func TestWidgetHandler_Cov3_CreateEvent_Success_Cov3(t *testing.T) {
|
|
db, router, _ := setupWidgetHandlerTest(t)
|
|
seedWidgetHandlerData(t, db)
|
|
|
|
body, _ := json.Marshal(map[string]interface{}{"name": "page_view", "website_token": "handler_ws_token_123"})
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("POST", "/api/v1/widget/events?website_token=handler_ws_token_123", bytes.NewReader(body))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
router.ServeHTTP(w, req)
|
|
assert.True(t, w.Code == http.StatusNoContent || w.Code == http.StatusBadRequest, "expected 204 or 400, got %d: %s", w.Code, w.Body.String())
|
|
}
|
|
|
|
// ---------- AddLabel ----------
|
|
|
|
func TestWidgetHandler_Cov3_AddLabel_NoToken_ChatwootRoute_Cov3(t *testing.T) {
|
|
_, router, _ := setupWidgetHandlerTest(t)
|
|
|
|
body, _ := json.Marshal(map[string]interface{}{"label": "test"})
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("POST", "/api/v1/widget/labels", bytes.NewReader(body))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
router.ServeHTTP(w, req)
|
|
assert.Equal(t, http.StatusNotFound, w.Code)
|
|
}
|
|
|
|
func TestWidgetHandler_Cov3_AddLabel_InvalidBody_Cov3(t *testing.T) {
|
|
_, router, _ := setupWidgetHandlerTest(t)
|
|
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("POST", "/api/v1/widget/labels?cw_conversation=some-token", bytes.NewReader([]byte("not json")))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
router.ServeHTTP(w, req)
|
|
assert.Equal(t, http.StatusBadRequest, w.Code)
|
|
}
|
|
|
|
// ---------- RemoveLabel ----------
|
|
|
|
func TestWidgetHandler_Cov3_RemoveLabel_NoToken_ChatwootRoute_Cov3(t *testing.T) {
|
|
_, router, _ := setupWidgetHandlerTest(t)
|
|
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("DELETE", "/api/v1/widget/labels/1", nil)
|
|
router.ServeHTTP(w, req)
|
|
assert.Equal(t, http.StatusNotFound, w.Code)
|
|
}
|
|
|
|
// ---------- SendTranscript ----------
|
|
|
|
func TestWidgetHandler_Cov3_SendTranscript_NoToken_Cov3(t *testing.T) {
|
|
_, router, _ := setupWidgetHandlerTest(t)
|
|
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("POST", "/api/v1/widget/conversations/transcript", nil)
|
|
router.ServeHTTP(w, req)
|
|
assert.Equal(t, http.StatusUnauthorized, w.Code)
|
|
}
|
|
|
|
// ---------- AddDyteParticipantToMeeting ----------
|
|
|
|
func TestWidgetHandler_Cov3_AddDyte_InvalidBody_Cov3(t *testing.T) {
|
|
_, router, _ := setupWidgetHandlerTest(t)
|
|
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("POST", "/api/v1/widget/integrations/dyte/add_participant_to_meeting", bytes.NewReader([]byte("not json")))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
router.ServeHTTP(w, req)
|
|
assert.Equal(t, http.StatusBadRequest, w.Code)
|
|
}
|
|
|
|
// ---------- SubmitOfflineMessage ----------
|
|
|
|
func TestWidgetHandler_Cov3_SubmitOfflineMessage_NoWebsiteToken_Cov3(t *testing.T) {
|
|
_, router, _ := setupWidgetHandlerTest(t)
|
|
|
|
body, _ := json.Marshal(map[string]interface{}{"message": "hello"})
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("POST", "/widget/offline_message", bytes.NewReader(body))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
router.ServeHTTP(w, req)
|
|
assert.Equal(t, http.StatusBadRequest, w.Code)
|
|
}
|
|
|
|
func TestWidgetHandler_Cov3_SubmitOfflineMessage_InvalidWebsiteToken_Cov3(t *testing.T) {
|
|
_, router, _ := setupWidgetHandlerTest(t)
|
|
|
|
body, _ := json.Marshal(map[string]interface{}{"message": "hello"})
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("POST", "/widget/offline_message?website_token=invalid", bytes.NewReader(body))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
router.ServeHTTP(w, req)
|
|
assert.Equal(t, http.StatusNotFound, w.Code)
|
|
}
|
|
|
|
// ---------- Public API endpoints ----------
|
|
|
|
func TestWidgetHandler_Cov3_PublicInboxShow_NotFound_Cov3(t *testing.T) {
|
|
_, router, _ := setupWidgetHandlerTest(t)
|
|
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("GET", "/public/api/v1/inboxes/nonexistent", nil)
|
|
router.ServeHTTP(w, req)
|
|
assert.True(t, w.Code == http.StatusNotFound || w.Code == http.StatusBadRequest, "expected 404 or 400, got %d: %s", w.Code, w.Body.String())
|
|
}
|
|
|
|
func TestWidgetHandler_Cov3_PublicInboxShow_Success_Cov3(t *testing.T) {
|
|
db, router, _ := setupWidgetHandlerTest(t)
|
|
_, _, channelAPI := seedPublicAPIInbox(t, db)
|
|
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("GET", "/public/api/v1/inboxes/"+channelAPI.Identifier, nil)
|
|
router.ServeHTTP(w, req)
|
|
require.Equal(t, http.StatusOK, w.Code, w.Body.String())
|
|
}
|
|
|
|
func TestWidgetHandler_Cov3_PublicCreateContact_Success_Cov3(t *testing.T) {
|
|
db, router, _ := setupWidgetHandlerTest(t)
|
|
_, _, channelAPI := seedPublicAPIInbox(t, db)
|
|
|
|
body, _ := json.Marshal(map[string]interface{}{"name": "New Contact"})
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("POST", "/public/api/v1/inboxes/"+channelAPI.Identifier+"/contacts", bytes.NewReader(body))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
router.ServeHTTP(w, req)
|
|
require.Equal(t, http.StatusOK, w.Code, w.Body.String())
|
|
|
|
var resp map[string]interface{}
|
|
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp))
|
|
assert.NotNil(t, resp["source_id"])
|
|
assert.NotNil(t, resp["id"])
|
|
assert.Equal(t, "New Contact", resp["name"])
|
|
}
|
|
|
|
func TestWidgetHandler_Cov3_PublicUpdateContact_Success_Cov3(t *testing.T) {
|
|
db, router, _ := setupWidgetHandlerTest(t)
|
|
_, _, channelAPI := seedPublicAPIInbox(t, db)
|
|
|
|
// Create contact first
|
|
createBody, _ := json.Marshal(map[string]interface{}{"name": "Original"})
|
|
wCreate := httptest.NewRecorder()
|
|
reqCreate, _ := http.NewRequest("POST", "/public/api/v1/inboxes/"+channelAPI.Identifier+"/contacts", bytes.NewReader(createBody))
|
|
reqCreate.Header.Set("Content-Type", "application/json")
|
|
router.ServeHTTP(wCreate, reqCreate)
|
|
require.Equal(t, http.StatusOK, wCreate.Code)
|
|
var createResp map[string]interface{}
|
|
require.NoError(t, json.Unmarshal(wCreate.Body.Bytes(), &createResp))
|
|
sourceID := createResp["source_id"].(string)
|
|
|
|
// Update
|
|
updateBody, _ := json.Marshal(map[string]interface{}{"name": "Updated Name"})
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("PUT", "/public/api/v1/inboxes/"+channelAPI.Identifier+"/contacts/"+sourceID, bytes.NewReader(updateBody))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
router.ServeHTTP(w, req)
|
|
require.Equal(t, http.StatusOK, w.Code, w.Body.String())
|
|
|
|
var resp map[string]interface{}
|
|
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp))
|
|
assert.Equal(t, "Updated Name", resp["name"])
|
|
}
|
|
|
|
func TestWidgetHandler_Cov3_PublicListConversations_Success_Cov3(t *testing.T) {
|
|
db, router, _ := setupWidgetHandlerTest(t)
|
|
_, _, channelAPI := seedPublicAPIInbox(t, db)
|
|
|
|
// Create contact
|
|
createBody, _ := json.Marshal(map[string]interface{}{"name": "Test"})
|
|
wCreate := httptest.NewRecorder()
|
|
reqCreate, _ := http.NewRequest("POST", "/public/api/v1/inboxes/"+channelAPI.Identifier+"/contacts", bytes.NewReader(createBody))
|
|
reqCreate.Header.Set("Content-Type", "application/json")
|
|
router.ServeHTTP(wCreate, reqCreate)
|
|
require.Equal(t, http.StatusOK, wCreate.Code)
|
|
var createResp map[string]interface{}
|
|
require.NoError(t, json.Unmarshal(wCreate.Body.Bytes(), &createResp))
|
|
sourceID := createResp["source_id"].(string)
|
|
|
|
// List conversations (should be empty)
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("GET", "/public/api/v1/inboxes/"+channelAPI.Identifier+"/contacts/"+sourceID+"/conversations", nil)
|
|
router.ServeHTTP(w, req)
|
|
require.Equal(t, http.StatusOK, w.Code, w.Body.String())
|
|
}
|
|
|
|
func TestWidgetHandler_Cov3_PublicCreateConversation_Success_Cov3(t *testing.T) {
|
|
db, router, _ := setupWidgetHandlerTest(t)
|
|
_, _, channelAPI := seedPublicAPIInbox(t, db)
|
|
|
|
// Create contact
|
|
createBody, _ := json.Marshal(map[string]interface{}{"name": "Test"})
|
|
wCreate := httptest.NewRecorder()
|
|
reqCreate, _ := http.NewRequest("POST", "/public/api/v1/inboxes/"+channelAPI.Identifier+"/contacts", bytes.NewReader(createBody))
|
|
reqCreate.Header.Set("Content-Type", "application/json")
|
|
router.ServeHTTP(wCreate, reqCreate)
|
|
require.Equal(t, http.StatusOK, wCreate.Code)
|
|
var createResp map[string]interface{}
|
|
require.NoError(t, json.Unmarshal(wCreate.Body.Bytes(), &createResp))
|
|
sourceID := createResp["source_id"].(string)
|
|
|
|
// Create conversation
|
|
convBody, _ := json.Marshal(map[string]interface{}{"custom_attributes": map[string]any{"topic": "support"}})
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("POST", "/public/api/v1/inboxes/"+channelAPI.Identifier+"/contacts/"+sourceID+"/conversations", bytes.NewReader(convBody))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
router.ServeHTTP(w, req)
|
|
require.Equal(t, http.StatusOK, w.Code, w.Body.String())
|
|
|
|
var resp map[string]interface{}
|
|
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp))
|
|
assert.NotNil(t, resp["id"])
|
|
}
|
|
|
|
func TestWidgetHandler_Cov3_PublicToggleTyping_InvalidStatus_Cov3(t *testing.T) {
|
|
db, router, _ := setupWidgetHandlerTest(t)
|
|
_, _, channelAPI := seedPublicAPIInbox(t, db)
|
|
|
|
// Create contact
|
|
createBody, _ := json.Marshal(map[string]interface{}{"name": "Test"})
|
|
wCreate := httptest.NewRecorder()
|
|
reqCreate, _ := http.NewRequest("POST", "/public/api/v1/inboxes/"+channelAPI.Identifier+"/contacts", bytes.NewReader(createBody))
|
|
reqCreate.Header.Set("Content-Type", "application/json")
|
|
router.ServeHTTP(wCreate, reqCreate)
|
|
require.Equal(t, http.StatusOK, wCreate.Code)
|
|
var createResp map[string]interface{}
|
|
require.NoError(t, json.Unmarshal(wCreate.Body.Bytes(), &createResp))
|
|
sourceID := createResp["source_id"].(string)
|
|
|
|
// Create conversation
|
|
convBody, _ := json.Marshal(map[string]interface{}{})
|
|
wConv := httptest.NewRecorder()
|
|
reqConv, _ := http.NewRequest("POST", "/public/api/v1/inboxes/"+channelAPI.Identifier+"/contacts/"+sourceID+"/conversations", bytes.NewReader(convBody))
|
|
reqConv.Header.Set("Content-Type", "application/json")
|
|
router.ServeHTTP(wConv, reqConv)
|
|
require.Equal(t, http.StatusOK, wConv.Code)
|
|
var convResp map[string]interface{}
|
|
require.NoError(t, json.Unmarshal(wConv.Body.Bytes(), &convResp))
|
|
convID := convResp["id"].(float64)
|
|
|
|
// Toggle typing with invalid status → returns 200 immediately
|
|
body, _ := json.Marshal(map[string]interface{}{"typing_status": "invalid"})
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("POST", "/public/api/v1/inboxes/"+channelAPI.Identifier+"/contacts/"+sourceID+"/conversations/"+fmt.Sprint(uint(convID))+"/toggle_typing", bytes.NewReader(body))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
router.ServeHTTP(w, req)
|
|
assert.Equal(t, http.StatusOK, w.Code)
|
|
}
|
|
|
|
func TestWidgetHandler_Cov3_PublicToggleStatus_Success_Cov3(t *testing.T) {
|
|
db, router, _ := setupWidgetHandlerTest(t)
|
|
_, _, channelAPI := seedPublicAPIInbox(t, db)
|
|
|
|
// Create contact + conversation
|
|
createBody, _ := json.Marshal(map[string]interface{}{"name": "Test"})
|
|
wCreate := httptest.NewRecorder()
|
|
reqCreate, _ := http.NewRequest("POST", "/public/api/v1/inboxes/"+channelAPI.Identifier+"/contacts", bytes.NewReader(createBody))
|
|
reqCreate.Header.Set("Content-Type", "application/json")
|
|
router.ServeHTTP(wCreate, reqCreate)
|
|
require.Equal(t, http.StatusOK, wCreate.Code)
|
|
var createResp map[string]interface{}
|
|
require.NoError(t, json.Unmarshal(wCreate.Body.Bytes(), &createResp))
|
|
sourceID := createResp["source_id"].(string)
|
|
|
|
convBody, _ := json.Marshal(map[string]interface{}{})
|
|
wConv := httptest.NewRecorder()
|
|
reqConv, _ := http.NewRequest("POST", "/public/api/v1/inboxes/"+channelAPI.Identifier+"/contacts/"+sourceID+"/conversations", bytes.NewReader(convBody))
|
|
reqConv.Header.Set("Content-Type", "application/json")
|
|
router.ServeHTTP(wConv, reqConv)
|
|
require.Equal(t, http.StatusOK, wConv.Code)
|
|
var convResp map[string]interface{}
|
|
require.NoError(t, json.Unmarshal(wConv.Body.Bytes(), &convResp))
|
|
convID := convResp["id"].(float64)
|
|
|
|
// Toggle status
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("POST", "/public/api/v1/inboxes/"+channelAPI.Identifier+"/contacts/"+sourceID+"/conversations/"+fmt.Sprint(uint(convID))+"/toggle_status", nil)
|
|
router.ServeHTTP(w, req)
|
|
require.Equal(t, http.StatusOK, w.Code, w.Body.String())
|
|
}
|
|
|
|
func TestWidgetHandler_Cov3_PublicUpdateLastSeen_Success_Cov3(t *testing.T) {
|
|
db, router, _ := setupWidgetHandlerTest(t)
|
|
_, _, channelAPI := seedPublicAPIInbox(t, db)
|
|
|
|
// Create contact + conversation
|
|
createBody, _ := json.Marshal(map[string]interface{}{"name": "Test"})
|
|
wCreate := httptest.NewRecorder()
|
|
reqCreate, _ := http.NewRequest("POST", "/public/api/v1/inboxes/"+channelAPI.Identifier+"/contacts", bytes.NewReader(createBody))
|
|
reqCreate.Header.Set("Content-Type", "application/json")
|
|
router.ServeHTTP(wCreate, reqCreate)
|
|
require.Equal(t, http.StatusOK, wCreate.Code)
|
|
var createResp map[string]interface{}
|
|
require.NoError(t, json.Unmarshal(wCreate.Body.Bytes(), &createResp))
|
|
sourceID := createResp["source_id"].(string)
|
|
|
|
convBody, _ := json.Marshal(map[string]interface{}{})
|
|
wConv := httptest.NewRecorder()
|
|
reqConv, _ := http.NewRequest("POST", "/public/api/v1/inboxes/"+channelAPI.Identifier+"/contacts/"+sourceID+"/conversations", bytes.NewReader(convBody))
|
|
reqConv.Header.Set("Content-Type", "application/json")
|
|
router.ServeHTTP(wConv, reqConv)
|
|
require.Equal(t, http.StatusOK, wConv.Code)
|
|
var convResp map[string]interface{}
|
|
require.NoError(t, json.Unmarshal(wConv.Body.Bytes(), &convResp))
|
|
convID := convResp["id"].(float64)
|
|
|
|
// Update last seen
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("POST", "/public/api/v1/inboxes/"+channelAPI.Identifier+"/contacts/"+sourceID+"/conversations/"+fmt.Sprint(uint(convID))+"/update_last_seen", nil)
|
|
router.ServeHTTP(w, req)
|
|
assert.Equal(t, http.StatusOK, w.Code)
|
|
}
|
|
|
|
func TestWidgetHandler_Cov3_PublicListMessages_Success_Cov3(t *testing.T) {
|
|
db, router, _ := setupWidgetHandlerTest(t)
|
|
_, _, channelAPI := seedPublicAPIInbox(t, db)
|
|
|
|
// Create contact + conversation
|
|
createBody, _ := json.Marshal(map[string]interface{}{"name": "Test"})
|
|
wCreate := httptest.NewRecorder()
|
|
reqCreate, _ := http.NewRequest("POST", "/public/api/v1/inboxes/"+channelAPI.Identifier+"/contacts", bytes.NewReader(createBody))
|
|
reqCreate.Header.Set("Content-Type", "application/json")
|
|
router.ServeHTTP(wCreate, reqCreate)
|
|
require.Equal(t, http.StatusOK, wCreate.Code)
|
|
var createResp map[string]interface{}
|
|
require.NoError(t, json.Unmarshal(wCreate.Body.Bytes(), &createResp))
|
|
sourceID := createResp["source_id"].(string)
|
|
|
|
convBody, _ := json.Marshal(map[string]interface{}{})
|
|
wConv := httptest.NewRecorder()
|
|
reqConv, _ := http.NewRequest("POST", "/public/api/v1/inboxes/"+channelAPI.Identifier+"/contacts/"+sourceID+"/conversations", bytes.NewReader(convBody))
|
|
reqConv.Header.Set("Content-Type", "application/json")
|
|
router.ServeHTTP(wConv, reqConv)
|
|
require.Equal(t, http.StatusOK, wConv.Code)
|
|
var convResp map[string]interface{}
|
|
require.NoError(t, json.Unmarshal(wConv.Body.Bytes(), &convResp))
|
|
convID := convResp["id"].(float64)
|
|
|
|
// List messages
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("GET", "/public/api/v1/inboxes/"+channelAPI.Identifier+"/contacts/"+sourceID+"/conversations/"+fmt.Sprint(uint(convID))+"/messages", nil)
|
|
router.ServeHTTP(w, req)
|
|
require.Equal(t, http.StatusOK, w.Code, w.Body.String())
|
|
}
|
|
|
|
func TestWidgetHandler_Cov3_PublicCreateMessage_Success_Cov3(t *testing.T) {
|
|
db, router, _ := setupWidgetHandlerTest(t)
|
|
_, _, channelAPI := seedPublicAPIInbox(t, db)
|
|
|
|
// Create contact + conversation
|
|
createBody, _ := json.Marshal(map[string]interface{}{"name": "Test"})
|
|
wCreate := httptest.NewRecorder()
|
|
reqCreate, _ := http.NewRequest("POST", "/public/api/v1/inboxes/"+channelAPI.Identifier+"/contacts", bytes.NewReader(createBody))
|
|
reqCreate.Header.Set("Content-Type", "application/json")
|
|
router.ServeHTTP(wCreate, reqCreate)
|
|
require.Equal(t, http.StatusOK, wCreate.Code)
|
|
var createResp map[string]interface{}
|
|
require.NoError(t, json.Unmarshal(wCreate.Body.Bytes(), &createResp))
|
|
sourceID := createResp["source_id"].(string)
|
|
|
|
convBody, _ := json.Marshal(map[string]interface{}{})
|
|
wConv := httptest.NewRecorder()
|
|
reqConv, _ := http.NewRequest("POST", "/public/api/v1/inboxes/"+channelAPI.Identifier+"/contacts/"+sourceID+"/conversations", bytes.NewReader(convBody))
|
|
reqConv.Header.Set("Content-Type", "application/json")
|
|
router.ServeHTTP(wConv, reqConv)
|
|
require.Equal(t, http.StatusOK, wConv.Code)
|
|
var convResp map[string]interface{}
|
|
require.NoError(t, json.Unmarshal(wConv.Body.Bytes(), &convResp))
|
|
convID := convResp["id"].(float64)
|
|
|
|
// Create message
|
|
msgBody, _ := json.Marshal(map[string]interface{}{"content": "Hello from public API"})
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("POST", "/public/api/v1/inboxes/"+channelAPI.Identifier+"/contacts/"+sourceID+"/conversations/"+fmt.Sprint(uint(convID))+"/messages", bytes.NewReader(msgBody))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
router.ServeHTTP(w, req)
|
|
require.Equal(t, http.StatusOK, w.Code, w.Body.String())
|
|
|
|
var resp map[string]interface{}
|
|
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp))
|
|
assert.Equal(t, "Hello from public API", resp["content"])
|
|
}
|
|
|
|
func TestWidgetHandler_Cov3_PublicGetConversation_Success_Cov3(t *testing.T) {
|
|
db, router, _ := setupWidgetHandlerTest(t)
|
|
_, _, channelAPI := seedPublicAPIInbox(t, db)
|
|
|
|
// Create contact + conversation
|
|
createBody, _ := json.Marshal(map[string]interface{}{"name": "Test"})
|
|
wCreate := httptest.NewRecorder()
|
|
reqCreate, _ := http.NewRequest("POST", "/public/api/v1/inboxes/"+channelAPI.Identifier+"/contacts", bytes.NewReader(createBody))
|
|
reqCreate.Header.Set("Content-Type", "application/json")
|
|
router.ServeHTTP(wCreate, reqCreate)
|
|
require.Equal(t, http.StatusOK, wCreate.Code)
|
|
var createResp map[string]interface{}
|
|
require.NoError(t, json.Unmarshal(wCreate.Body.Bytes(), &createResp))
|
|
sourceID := createResp["source_id"].(string)
|
|
|
|
convBody, _ := json.Marshal(map[string]interface{}{})
|
|
wConv := httptest.NewRecorder()
|
|
reqConv, _ := http.NewRequest("POST", "/public/api/v1/inboxes/"+channelAPI.Identifier+"/contacts/"+sourceID+"/conversations", bytes.NewReader(convBody))
|
|
reqConv.Header.Set("Content-Type", "application/json")
|
|
router.ServeHTTP(wConv, reqConv)
|
|
require.Equal(t, http.StatusOK, wConv.Code)
|
|
var convResp map[string]interface{}
|
|
require.NoError(t, json.Unmarshal(wConv.Body.Bytes(), &convResp))
|
|
convID := convResp["id"].(float64)
|
|
|
|
// Get conversation
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("GET", "/public/api/v1/inboxes/"+channelAPI.Identifier+"/contacts/"+sourceID+"/conversations/"+fmt.Sprint(uint(convID)), nil)
|
|
router.ServeHTTP(w, req)
|
|
require.Equal(t, http.StatusOK, w.Code, w.Body.String())
|
|
|
|
var resp map[string]interface{}
|
|
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp))
|
|
assert.NotNil(t, resp["id"])
|
|
}
|
|
|
|
func TestWidgetHandler_Cov3_PublicUintParam_Invalid_Cov3(t *testing.T) {
|
|
db, router, _ := setupWidgetHandlerTest(t)
|
|
_, _, channelAPI := seedPublicAPIInbox(t, db)
|
|
|
|
// Create contact
|
|
createBody, _ := json.Marshal(map[string]interface{}{"name": "Test"})
|
|
wCreate := httptest.NewRecorder()
|
|
reqCreate, _ := http.NewRequest("POST", "/public/api/v1/inboxes/"+channelAPI.Identifier+"/contacts", bytes.NewReader(createBody))
|
|
reqCreate.Header.Set("Content-Type", "application/json")
|
|
router.ServeHTTP(wCreate, reqCreate)
|
|
require.Equal(t, http.StatusOK, wCreate.Code)
|
|
var createResp map[string]interface{}
|
|
require.NoError(t, json.Unmarshal(wCreate.Body.Bytes(), &createResp))
|
|
sourceID := createResp["source_id"].(string)
|
|
|
|
// Invalid conversation ID
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("GET", "/public/api/v1/inboxes/"+channelAPI.Identifier+"/contacts/"+sourceID+"/conversations/abc", nil)
|
|
router.ServeHTTP(w, req)
|
|
assert.Equal(t, http.StatusBadRequest, w.Code)
|
|
}
|
|
|
|
// Ensure imports are used
|
|
var _ = gorm.ErrRecordNotFound
|