Files
popiart-server/internal/server/billing_test.go
T
wtgoku baba209519 Expose gateway billing flows from the synced server baseline
The preserved local work adds PopiNewAPI billing checkout, gateway account binding, and matching web console/pricing surfaces on top of the current test-server baseline. During the merge, the start-end video helpers from the deployed baseline were kept alongside the actionGenerate prompt handling from the WIP.

Constraint: Current usable baseline is 7054436, already deployed on the test server.

Rejected: Commit the WIP before syncing the baseline | would have hidden conflicts with the deployed start-end-frame changes.

Confidence: medium

Scope-risk: broad

Directive: Do not deploy this commit to the test server without rechecking gateway credentials and billing checkout behavior in that environment.

Tested: go test ./...

Tested: make build

Tested: cd web && npm run build
2026-05-21 16:53:07 +08:00

92 lines
2.4 KiB
Go

package server
import (
"encoding/json"
"net/http"
"net/http/httptest"
"path/filepath"
"testing"
)
func TestHandleBillingCatalogReturnsSeededPlans(t *testing.T) {
server, err := NewWithConfig(Config{
SQLitePath: filepath.Join(t.TempDir(), "popiart.db"),
SkillhubDir: makeEmptySkillhub(t),
SessionSecret: "test-secret",
})
if err != nil {
t.Fatalf("NewWithConfig: %v", err)
}
req := httptest.NewRequest(http.MethodGet, "/v1/billing/catalog", nil)
rec := httptest.NewRecorder()
server.Handler().ServeHTTP(rec, req)
if rec.Code != http.StatusOK {
t.Fatalf("expected 200, got %d: %s", rec.Code, rec.Body.String())
}
var resp struct {
OK bool `json:"ok"`
Data struct {
Plans []billingPlan `json:"plans"`
} `json:"data"`
}
if err := json.Unmarshal(rec.Body.Bytes(), &resp); err != nil {
t.Fatalf("decode response: %v", err)
}
if !resp.OK {
t.Fatalf("expected ok response, got %s", rec.Body.String())
}
if len(resp.Data.Plans) != 2 {
t.Fatalf("expected 2 plans, got %d", len(resp.Data.Plans))
}
if resp.Data.Plans[0].ProductType != "subscription" {
t.Fatalf("expected first plan to be subscription, got %#v", resp.Data.Plans[0])
}
}
func TestHandleBillingSubscriptionReturnsUnbound(t *testing.T) {
server, err := NewWithConfig(Config{
SQLitePath: filepath.Join(t.TempDir(), "popiart.db"),
SkillhubDir: makeEmptySkillhub(t),
SessionSecret: "test-secret",
})
if err != nil {
t.Fatalf("NewWithConfig: %v", err)
}
sessionToken, _, ok, err := server.store.createSession("sk-billing-user")
if err != nil {
t.Fatalf("createSession: %v", err)
}
if !ok {
t.Fatal("expected session creation to succeed")
}
req := httptest.NewRequest(http.MethodGet, "/v1/billing/subscription", nil)
req.Header.Set("Authorization", "Bearer "+sessionToken)
rec := httptest.NewRecorder()
server.Handler().ServeHTTP(rec, req)
if rec.Code != http.StatusPreconditionFailed {
t.Fatalf("expected 412, got %d: %s", rec.Code, rec.Body.String())
}
var resp struct {
OK bool `json:"ok"`
Error struct {
Code string `json:"code"`
} `json:"error"`
}
if err := json.Unmarshal(rec.Body.Bytes(), &resp); err != nil {
t.Fatalf("decode error response: %v", err)
}
if resp.OK {
t.Fatalf("expected error response, got %s", rec.Body.String())
}
if resp.Error.Code != "BILLING_UNBOUND" {
t.Fatalf("expected BILLING_UNBOUND, got %q", resp.Error.Code)
}
}