Files
Jyotisha/frontend/tests/admin-payments-contract.test.ts
T
linmeng 9a20b748e0
Deploy staging to test server / deploy (push) Successful in 3m28s
feat: unify payment administration
2026-07-29 13:40:10 +08:00

72 lines
3.9 KiB
TypeScript

import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import test from "node:test";
const root = new URL("../", import.meta.url);
const route = readFileSync(new URL("src/app/api/admin/payments/route.ts", root), "utf8");
const packagesRoute = readFileSync(new URL("src/app/api/admin/packages/route.ts", root), "utf8");
const page = readFileSync(new URL("src/app/admin/payments/page.tsx", root), "utf8");
const packagesPage = readFileSync(new URL("src/app/admin/packages/page.tsx", root), "utf8");
const management = readFileSync(new URL("src/components/admin/payment-management.tsx", root), "utf8");
const migration = readFileSync(new URL("supabase/migrations/20260727030000_payment_admin_stats.sql", root), "utf8");
test("支付后台接口只允许管理员并查询平台订单", () => {
assert.match(route, /requireAdminSession\("read"\)/);
assert.doesNotMatch(route, /isAdminUser\(user\)/);
assert.match(route, /from\("payment_orders"\)/);
assert.match(route, /auth\.admin\.getUserById/);
assert.match(route, /payment_packages\(name\)/);
assert.match(route, /order_no|orderNo/);
assert.doesNotMatch(route, /SUPABASE_SERVICE_ROLE_KEY/);
assert.doesNotMatch(route, /raw_notify_payload/);
});
test("支付接口包含筛选、统计和分页契约", () => {
for (const field of ["status", "from", "to", "limit", "offset"]) assert.match(route, new RegExp(field));
for (const field of ["totalOrders", "paidOrders", "pendingOrders", "failedExpiredOrders", "paidAmountCents", "grantedCredits"]) assert.match(route, new RegExp(field));
assert.match(route, /max\(100\)/);
assert.match(route, /count: "exact"/);
assert.match(route, /hasMore/);
assert.match(migration, /get_payment_order_stats/);
assert.match(migration, /status = 'paid'/);
});
test("统一支付管理页面使用 Ant Design 与 Refine 并保留支付数据合同", () => {
assert.match(page, /PaymentManagement/);
for (const component of ["List", "Card", "Table", "Form", "Tag", "Alert", "Statistic"]) {
assert.match(management, new RegExp(`\\b${component}\\b`));
}
assert.match(management, /\/api\/admin\/payments/);
assert.match(management, /\/api\/admin\/packages/);
for (const field of ["orderNo", "userEmail", "packageName", "moneyCents", "credits", "status", "epayTradeNo", "createdAt", "paidAt"]) {
assert.match(management, new RegExp(field));
}
assert.match(management, /paymentLoading/);
assert.match(management, /paymentError/);
assert.match(management, /pagination=\{\{/);
assert.doesNotMatch(management, /standalone-page|admin-header|admin-section/);
});
test("套餐列表、Modal 与新增编辑停用操作收敛到支付管理页", () => {
assert.match(management, /<Card title="套餐列表" extra=\{<Button[\s\S]*?添加套餐<\/Button>\}>/);
assert.doesNotMatch(management, /<List[\s\S]{0,120}headerButtons/);
assert.match(management, /<Modal/);
assert.match(management, /title=\{editingPackage \? "编辑套餐" : "添加套餐"\}/);
assert.match(management, /价格(元)/);
assert.match(management, /priceCents: Math\.round\(values\.priceYuan \* 100\)/);
for (const method of ["POST", "PATCH", "DELETE"]) assert.match(management, new RegExp(`method: .*${method}`));
assert.match(management, /message\.success/);
assert.match(management, /message\.error/);
assert.match(management, /setPackagesLoading/);
assert.match(management, /packagesError/);
assert.match(management, /packageForm\.resetFields\(\)/);
assert.match(packagesRoute, /requireAdminSession\("read"\)/);
assert.match(packagesRoute, /requireAdminSession\("write"\)/);
});
test("旧套餐路由服务端重定向到统一支付管理页", () => {
assert.match(packagesPage, /import \{ redirect \} from "next\/navigation"/);
assert.match(packagesPage, /redirect\("\/admin\/payments"\)/);
assert.doesNotMatch(packagesPage, /use client|<form|\/api\/admin\/packages/);
});