Files
digital-psychology/apps/api/internal/integration/analytics_ops_test.go
T
jackyu66gitandCursor 7ab9add5dd
ci / h5 (push) Canceled after 0s
ci / api (push) Canceled after 0s
ci / ess-docs (push) Canceled after 0s
feat(ops): ECR-007 行为分析与 ECR-008 内容运营后台
落地埋点 ingest/数据看板、首页宫格 CMS 与测评上下架;含账号引导、问答流式与免责声明去重,以及 review P1 审计同事务修复。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-07 02:26:16 +08:00

90 lines
3.0 KiB
Go

package integration_test
import (
"encoding/json"
"net/http"
"testing"
"time"
)
func TestAnalyticsOpsB(t *testing.T) {
r, _ := setupAPI(t)
sid := "s_test_" + time.Now().Format("150405")
now := time.Now().UTC().Format(time.RFC3339Nano)
env, key := doJSON(t, r, http.MethodPost, "/api/v1/analytics/events", map[string]any{
"items": []map[string]any{
{"name": "session_start", "session_id": sid, "client_ts": now, "props": map[string]any{"cold": true}},
{"name": "page_view", "session_id": sid, "page_path": "/portrait", "client_ts": now},
{"name": "page_view", "session_id": sid, "page_path": "/ask", "client_ts": now},
{"name": "page_leave", "session_id": sid, "page_path": "/portrait", "client_ts": now,
"props": map[string]any{"dwell_ms": 1500}},
{"name": "ui_click", "session_id": sid, "client_ts": now,
"props": map[string]any{"element_id": "home_cta", "page_path": "/"}},
{"name": "portrait_completed", "session_id": sid, "client_ts": now},
{"name": "session_end", "session_id": sid, "client_ts": now,
"props": map[string]any{"exit_page": "/ask", "duration_ms": 8000}},
},
}, "")
var accepted struct {
Accepted int `json:"accepted"`
}
if err := json.Unmarshal(env.Data, &accepted); err != nil || accepted.Accepted < 6 {
t.Fatalf("accepted=%v err=%v body=%s", accepted, err, string(env.Data))
}
_ = key
loginEnv, code := doAdminJSON(t, r, http.MethodPost, "/api/v1/admin/auth/login", map[string]string{
"username": "admin", "password": "change-me",
}, "")
if code != http.StatusOK || loginEnv.Code != 0 {
t.Fatalf("admin login http=%d code=%d", code, loginEnv.Code)
}
var login struct {
Token string `json:"token"`
}
_ = json.Unmarshal(loginEnv.Data, &login)
if login.Token == "" {
t.Fatal("missing admin token")
}
from := time.Now().UTC().Add(-24 * time.Hour).Format("2006-01-02")
to := time.Now().UTC().Format("2006-01-02")
q := "?from=" + from + "&to=" + to
ov, code := doAdminJSON(t, r, http.MethodGet, "/api/v1/admin/analytics/overview"+q, nil, login.Token)
if code != http.StatusOK || ov.Code != 0 {
t.Fatalf("overview http=%d code=%d msg=%s", code, ov.Code, ov.Message)
}
var overview map[string]any
_ = json.Unmarshal(ov.Data, &overview)
if sessions, _ := overview["sessions"].(float64); sessions < 1 {
t.Fatalf("expected sessions>=1 got %v", overview)
}
pg, code := doAdminJSON(t, r, http.MethodGet, "/api/v1/admin/analytics/pages"+q, nil, login.Token)
if code != http.StatusOK || pg.Code != 0 {
t.Fatalf("pages http=%d code=%d", code, pg.Code)
}
ex, code := doAdminJSON(t, r, http.MethodGet, "/api/v1/admin/analytics/exits"+q, nil, login.Token)
if code != http.StatusOK || ex.Code != 0 {
t.Fatalf("exits http=%d code=%d", code, ex.Code)
}
var exits struct {
Items []struct {
ExitPage string `json:"exit_page"`
Count int `json:"count"`
} `json:"items"`
}
_ = json.Unmarshal(ex.Data, &exits)
found := false
for _, it := range exits.Items {
if it.ExitPage == "/ask" && it.Count >= 1 {
found = true
}
}
if !found {
t.Fatalf("expected exit /ask in %v", exits.Items)
}
}