feat(ECR-014): MembershipPlan 套餐配置并 Closed
membership_plans 表、admin 套餐页、Grant/CreateOrder 读表; Loop continuous 自动 Approve/Closed。Next:ECR-015 RedemptionCode。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
package integration_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestMembershipPlans(t *testing.T) {
|
||||
r, _ := setupAPIPool(t)
|
||||
tok := adminLogin(t, r, "admin", "change-me")
|
||||
|
||||
_, code := doAdminJSON(t, r, http.MethodGet, "/api/v1/admin/membership-plans", nil, "")
|
||||
if code != http.StatusUnauthorized {
|
||||
t.Fatalf("expected 401, got %d", code)
|
||||
}
|
||||
|
||||
start := time.Now()
|
||||
env, code := doAdminJSON(t, r, http.MethodGet, "/api/v1/admin/membership-plans", nil, tok)
|
||||
if code != 200 || time.Since(start) > 500*time.Millisecond {
|
||||
t.Fatalf("list plans http=%d dur=%v msg=%s", code, time.Since(start), env.Message)
|
||||
}
|
||||
var list struct {
|
||||
Items []struct {
|
||||
Code string `json:"code"`
|
||||
DurationDays int `json:"duration_days"`
|
||||
AmountCents int `json:"amount_cents"`
|
||||
} `json:"items"`
|
||||
}
|
||||
_ = json.Unmarshal(env.Data, &list)
|
||||
if len(list.Items) < 3 {
|
||||
t.Fatalf("expected 3 plans, got %#v", list.Items)
|
||||
}
|
||||
|
||||
env, code = doAdminJSON(t, r, http.MethodPut, "/api/v1/admin/membership-plans/month", map[string]any{
|
||||
"title": "月卡测", "duration_days": 30, "amount_cents": 2600, "active": true,
|
||||
}, tok)
|
||||
if code != 200 {
|
||||
t.Fatalf("put failed %d %s", code, env.Message)
|
||||
}
|
||||
var plan struct {
|
||||
DurationDays int `json:"duration_days"`
|
||||
AmountCents int `json:"amount_cents"`
|
||||
}
|
||||
_ = json.Unmarshal(env.Data, &plan)
|
||||
if plan.DurationDays != 30 || plan.AmountCents != 2600 {
|
||||
t.Fatalf("unexpected plan %#v", plan)
|
||||
}
|
||||
|
||||
env, code = doAdminJSON(t, r, http.MethodGet, "/api/v1/admin/membership-plans/month", nil, tok)
|
||||
if code != 200 {
|
||||
t.Fatalf("get %d", code)
|
||||
}
|
||||
_ = json.Unmarshal(env.Data, &plan)
|
||||
if plan.DurationDays != 30 {
|
||||
t.Fatalf("get mismatch %#v", plan)
|
||||
}
|
||||
|
||||
_ = mustRegister(t, r)
|
||||
env, code = doAdminJSON(t, r, http.MethodGet, "/api/v1/admin/users", nil, tok)
|
||||
var users struct {
|
||||
Items []struct {
|
||||
ID string `json:"id"`
|
||||
} `json:"items"`
|
||||
}
|
||||
_ = json.Unmarshal(env.Data, &users)
|
||||
if len(users.Items) == 0 {
|
||||
t.Fatal("need user")
|
||||
}
|
||||
env, code = doAdminJSON(t, r, http.MethodPost, "/api/v1/admin/users/"+users.Items[0].ID+"/membership/grant",
|
||||
map[string]string{"plan": "month"}, tok)
|
||||
if code != 200 {
|
||||
t.Fatalf("grant %d %s", code, env.Message)
|
||||
}
|
||||
|
||||
env, code = doAdminJSON(t, r, http.MethodGet, "/api/v1/admin/audit-logs", nil, tok)
|
||||
if code != 200 {
|
||||
t.Fatalf("audit %d", code)
|
||||
}
|
||||
var audit struct {
|
||||
Items []struct {
|
||||
Action string `json:"action"`
|
||||
} `json:"items"`
|
||||
}
|
||||
_ = json.Unmarshal(env.Data, &audit)
|
||||
found := false
|
||||
for _, it := range audit.Items {
|
||||
if it.Action == "membership.plans.update" {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
t.Fatal("missing membership.plans.update audit")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user