feat(widget): implement chatwoot widget core handlers

This commit is contained in:
2026-06-04 21:28:29 +08:00
parent de6a05e0e6
commit 67a6ae762e
5 changed files with 649 additions and 77 deletions
+85 -1
View File
@@ -94,6 +94,15 @@ func setupWidgetHandlerTest(t *testing.T) (*gorm.DB, *gin.Engine, *WidgetHandler
widgetGroup.POST("/offline_message", handler.SubmitOfflineMessage)
}
chatwootWidgetGroup := router.Group("/api/v1/widget")
{
chatwootWidgetGroup.POST("/config", handler.Config)
chatwootWidgetGroup.GET("/messages", handler.GetLatestMessages)
chatwootWidgetGroup.POST("/messages", handler.SendMessage)
chatwootWidgetGroup.POST("/conversations", handler.CreateConversation)
chatwootWidgetGroup.GET("/contact", handler.GetContact)
}
return db, router, handler
}
@@ -194,6 +203,81 @@ func TestWidgetHandler_Init_InvalidWebsiteToken(t *testing.T) {
assert.Equal(t, http.StatusBadRequest, w.Code)
}
func TestWidgetHandler_ChatwootConfig_Success(t *testing.T) {
db, router, _ := setupWidgetHandlerTest(t)
_, _ = seedWidgetHandlerData(t, db)
w := httptest.NewRecorder()
req, _ := http.NewRequest("POST", "/api/v1/widget/config?website_token=handler_ws_token_123", nil)
router.ServeHTTP(w, req)
assert.Equal(t, http.StatusOK, w.Code)
var resp map[string]interface{}
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp))
config := resp["website_channel_config"].(map[string]interface{})
assert.NotEmpty(t, config["auth_token"])
assert.Equal(t, "handler_ws_token_123", config["website_token"])
assert.Equal(t, "Handler Widget Inbox", config["website_name"])
contact := resp["contact"].(map[string]interface{})
assert.NotEmpty(t, contact["id"])
assert.NotEmpty(t, contact["pubsub_token"])
}
func TestWidgetHandler_ChatwootMessages_AuthTokenAndNestedPayload(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))
contact := configResp["contact"].(map[string]interface{})
authToken := contact["pubsub_token"].(string)
body := map[string]interface{}{
"message": map[string]interface{}{"content": "Hello from Chatwoot widget"},
}
bodyJSON, _ := json.Marshal(body)
wMessage := httptest.NewRecorder()
reqMessage, _ := http.NewRequest("POST", "/api/v1/widget/messages", bytes.NewReader(bodyJSON))
reqMessage.Header.Set("Content-Type", "application/json")
reqMessage.Header.Set("X-Auth-Token", authToken)
router.ServeHTTP(wMessage, reqMessage)
require.Equal(t, http.StatusOK, wMessage.Code)
var messageResp map[string]interface{}
require.NoError(t, json.Unmarshal(wMessage.Body.Bytes(), &messageResp))
assert.Nil(t, messageResp["message"])
assert.Equal(t, "Hello from Chatwoot widget", messageResp["content"])
assert.NotEmpty(t, messageResp["conversation_id"])
wIndex := httptest.NewRecorder()
reqIndex, _ := http.NewRequest("GET", "/api/v1/widget/messages", nil)
reqIndex.Header.Set("X-Auth-Token", authToken)
router.ServeHTTP(wIndex, reqIndex)
require.Equal(t, http.StatusOK, wIndex.Code)
var indexResp map[string]interface{}
require.NoError(t, json.Unmarshal(wIndex.Body.Bytes(), &indexResp))
payload := indexResp["payload"].([]interface{})
require.Len(t, payload, 1)
firstMessage := payload[0].(map[string]interface{})
assert.Equal(t, "Hello from Chatwoot widget", firstMessage["content"])
wContact := httptest.NewRecorder()
reqContact, _ := http.NewRequest("GET", "/api/v1/widget/contact", nil)
reqContact.Header.Set("X-Auth-Token", authToken)
router.ServeHTTP(wContact, reqContact)
require.Equal(t, http.StatusOK, wContact.Code)
}
// ========== SendMessage Handler Tests ==========
func TestWidgetHandler_SendMessage_Success(t *testing.T) {
@@ -679,4 +763,4 @@ func TestWidgetHandler_Init_HMACInvalid(t *testing.T) {
var resp map[string]interface{}
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp))
assert.NotEmpty(t, resp["widget_token"])
}
}