- Seller KYC via Stripe Identity (start verification, status check, webhook) - Support ticket system (backend handler + frontend form page) - E2E payout flow integration test (sale → payment → balance → payout) - Migrations: seller_kyc columns, support_tickets table - Frontend: SupportPage with SUMI design, lazy loading, routing Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
128 lines
3.5 KiB
Go
128 lines
3.5 KiB
Go
package handlers
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"go.uber.org/zap"
|
|
"gorm.io/driver/sqlite"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
func setupSupportTestRouter(t *testing.T) (*gin.Engine, *gorm.DB) {
|
|
t.Helper()
|
|
gin.SetMode(gin.TestMode)
|
|
|
|
db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
|
|
require.NoError(t, err)
|
|
|
|
// Create support_tickets table for SQLite
|
|
require.NoError(t, db.Exec(`
|
|
CREATE TABLE IF NOT EXISTS support_tickets (
|
|
id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(16)))),
|
|
user_id TEXT,
|
|
email TEXT NOT NULL,
|
|
subject TEXT NOT NULL,
|
|
message TEXT NOT NULL,
|
|
category TEXT DEFAULT 'general',
|
|
status TEXT DEFAULT 'open',
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
)
|
|
`).Error)
|
|
|
|
router := gin.New()
|
|
handler := NewSupportHandler(db, zap.NewNop())
|
|
router.POST("/api/v1/support/tickets", handler.SubmitTicket)
|
|
|
|
return router, db
|
|
}
|
|
|
|
func TestSupportHandler_SubmitTicket_Success(t *testing.T) {
|
|
router, db := setupSupportTestRouter(t)
|
|
|
|
body, _ := json.Marshal(map[string]string{
|
|
"email": "user@example.com",
|
|
"subject": "Payment issue",
|
|
"message": "I have a problem with my payment for order #123. Please help.",
|
|
"category": "payment",
|
|
})
|
|
|
|
req := httptest.NewRequest(http.MethodPost, "/api/v1/support/tickets", bytes.NewReader(body))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
w := httptest.NewRecorder()
|
|
router.ServeHTTP(w, req)
|
|
|
|
assert.Equal(t, http.StatusCreated, w.Code)
|
|
|
|
var resp map[string]interface{}
|
|
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp))
|
|
data := resp["data"].(map[string]interface{})
|
|
assert.NotEmpty(t, data["ticket_id"])
|
|
assert.Contains(t, data["message"], "submitted")
|
|
|
|
// Verify in DB
|
|
var count int64
|
|
db.Table("support_tickets").Count(&count)
|
|
assert.Equal(t, int64(1), count)
|
|
}
|
|
|
|
func TestSupportHandler_SubmitTicket_MissingFields(t *testing.T) {
|
|
router, _ := setupSupportTestRouter(t)
|
|
|
|
body, _ := json.Marshal(map[string]string{
|
|
"email": "user@example.com",
|
|
// Missing subject and message
|
|
})
|
|
|
|
req := httptest.NewRequest(http.MethodPost, "/api/v1/support/tickets", bytes.NewReader(body))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
w := httptest.NewRecorder()
|
|
router.ServeHTTP(w, req)
|
|
|
|
assert.NotEqual(t, http.StatusCreated, w.Code)
|
|
}
|
|
|
|
func TestSupportHandler_SubmitTicket_InvalidEmail(t *testing.T) {
|
|
router, _ := setupSupportTestRouter(t)
|
|
|
|
body, _ := json.Marshal(map[string]string{
|
|
"email": "not-an-email",
|
|
"subject": "Test subject",
|
|
"message": "This is a test message with enough characters.",
|
|
})
|
|
|
|
req := httptest.NewRequest(http.MethodPost, "/api/v1/support/tickets", bytes.NewReader(body))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
w := httptest.NewRecorder()
|
|
router.ServeHTTP(w, req)
|
|
|
|
assert.NotEqual(t, http.StatusCreated, w.Code)
|
|
}
|
|
|
|
func TestSupportHandler_SubmitTicket_DefaultCategory(t *testing.T) {
|
|
router, db := setupSupportTestRouter(t)
|
|
|
|
body, _ := json.Marshal(map[string]string{
|
|
"email": "user@example.com",
|
|
"subject": "General question",
|
|
"message": "I have a question about the platform features.",
|
|
})
|
|
|
|
req := httptest.NewRequest(http.MethodPost, "/api/v1/support/tickets", bytes.NewReader(body))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
w := httptest.NewRecorder()
|
|
router.ServeHTTP(w, req)
|
|
|
|
assert.Equal(t, http.StatusCreated, w.Code)
|
|
|
|
// Verify default category
|
|
var ticket SupportTicket
|
|
db.Table("support_tickets").First(&ticket)
|
|
assert.Equal(t, "general", ticket.Category)
|
|
}
|