f4e35974c6
Deploy staging to test server / deploy (push) Failing after 14m49s
This reverts commita55c69115d, reversing changes made to02c9c9f3d6.
95 lines
6.3 KiB
TypeScript
95 lines
6.3 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 paymentPage = 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 paymentManagement = readFileSync(new URL("src/components/admin/payment-management.tsx", root), "utf8");
|
|
const packageManagement = readFileSync(new URL("src/components/admin/package-management.tsx", root), "utf8");
|
|
const adminApp = readFileSync(new URL("src/components/admin/admin-app.tsx", root), "utf8");
|
|
const globalsCss = readFileSync(new URL("src/app/globals.css", root), "utf8");
|
|
|
|
test("支付后台接口使用 self-hosted PostgreSQL 联表且不依赖 Supabase builder", () => {
|
|
assert.match(route, /requireAdminSession\("read"\)/);
|
|
assert.match(route, /queryAdminRows<PaymentOrderRow>/);
|
|
assert.match(route, /from public\.payment_orders o/);
|
|
assert.match(route, /left join public\.payment_packages p on p\.id = o\.package_id/);
|
|
assert.match(route, /left join identity\.users u on u\.id = o\.user_id/);
|
|
assert.match(route, /count\(\*\) over\(\)::text as total_count/);
|
|
assert.match(route, /order by o\.created_at desc, o\.order_no asc/);
|
|
assert.doesNotMatch(route, /createAdminSupabaseClient|auth\.admin|\.from\(|\.range\(|count: "exact"/);
|
|
assert.doesNotMatch(route, /userId|user_id:|raw_notify_payload|SUPABASE_SERVICE_ROLE_KEY/);
|
|
});
|
|
|
|
test("支付接口使用参数化筛选、独立日期统计与 ISO 日期输出", () => {
|
|
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, /\$\$\{values\.length\}/);
|
|
assert.match(route, /statsValues/);
|
|
assert.match(route, /created_at\.toISOString\(\)/);
|
|
assert.match(route, /paid_at\?\.toISOString\(\) \?\? null/);
|
|
assert.match(route, /支付记录服务暂时不可用/);
|
|
assert.match(route, /hasMore/);
|
|
});
|
|
|
|
test("支付管理页只保留概览、默认折叠的 Z-Pay 配置与支付记录", () => {
|
|
assert.match(paymentPage, /PaymentManagement/);
|
|
for (const component of ["List", "Card", "Collapse", "Table", "Form", "Tag", "Alert", "Statistic"]) assert.match(paymentManagement, new RegExp(`\\b${component}\\b`));
|
|
assert.match(paymentManagement, /支付概览/);
|
|
assert.match(paymentManagement, /<Collapse[\s\S]*defaultActiveKey=\{\[\]\}[\s\S]*label: "Z-Pay(易支付)渠道配置"/);
|
|
assert.match(paymentManagement, /children: \([\s\S]*测试可用性(当前已保存配置)[\s\S]*保存配置[\s\S]*<Form<EpaySettingsForm>/);
|
|
assert.match(paymentManagement, /支付记录/);
|
|
assert.match(paymentManagement, /\/api\/admin\/payments/);
|
|
assert.doesNotMatch(paymentManagement, /套餐列表|套餐设置|添加套餐|\/api\/admin\/packages|PackageManagement/);
|
|
});
|
|
|
|
test("套餐管理是支付管理之后的独立资源和页面", () => {
|
|
assert.match(adminApp, /name: "payments", list: "\/admin\/payments"[\s\S]*name: "packages", list: "\/admin\/packages", meta: \{ label: "套餐管理"[\s\S]*name: "users"/);
|
|
assert.match(adminApp, /ShoppingOutlined/);
|
|
assert.match(packagesPage, /PackageManagement/);
|
|
assert.doesNotMatch(packagesPage, /redirect/);
|
|
assert.match(packageManagement, /<List title="套餐管理">/);
|
|
assert.match(packageManagement, /<Card title="套餐设置"/);
|
|
});
|
|
|
|
test("套餐完整设置、加载重试及新增编辑停用操作保留", () => {
|
|
for (const field of ["名称", "描述", "价格(元)", "点数", "排序", "启用"]) assert.match(packageManagement, new RegExp(field));
|
|
assert.match(packageManagement, /套餐列表读取失败/);
|
|
assert.match(packageManagement, /loadPackages\(\)/);
|
|
assert.match(packageManagement, />重试<\/Button>/);
|
|
assert.match(packageManagement, /<Modal/);
|
|
assert.match(packageManagement, /title=\{editingPackage \? "编辑套餐" : "添加套餐"\}/);
|
|
assert.match(packageManagement, /priceCents: Math\.round\(values\.priceYuan \* 100\)/);
|
|
for (const method of ["POST", "PATCH", "DELETE"]) assert.match(packageManagement, new RegExp(`method: .*${method}`));
|
|
assert.match(packageManagement, /message\.success/);
|
|
assert.match(packageManagement, /message\.error/);
|
|
assert.match(packageManagement, /packageForm\.resetFields\(\)/);
|
|
assert.match(packagesRoute, /requireAdminSession\("read"\)/);
|
|
assert.match(packagesRoute, /requireAdminSession\("write"\)/);
|
|
});
|
|
|
|
test("套餐 API 使用直接参数化 PostgreSQL CRUD、UUID 校验与未找到响应", () => {
|
|
assert.match(packagesRoute, /queryAdminRows<PackageRow>/);
|
|
assert.match(packagesRoute, /from public\.payment_packages[\s\S]*order by sort_order, created_at/);
|
|
assert.match(packagesRoute, /insert into public\.payment_packages[\s\S]*values \(\$1, \$2, \$3, \$4, \$5, \$6, \$7\)[\s\S]*returning/);
|
|
assert.match(packagesRoute, /created_by[\s\S]*auth\.user\.id/);
|
|
assert.match(packagesRoute, /updateSchema = schema\.extend\(\{ id: z\.string\(\)\.uuid\(\) \}\)/);
|
|
assert.match(packagesRoute, /update public\.payment_packages[\s\S]*where id = \$1[\s\S]*returning/);
|
|
assert.match(packagesRoute, /set enabled = false, updated_at = clock_timestamp\(\)[\s\S]*returning id/);
|
|
assert.match(packagesRoute, /套餐不存在" \}, \{ status: 404 \}/g);
|
|
assert.match(packagesRoute, /created_at\.toISOString\(\)/);
|
|
assert.match(packagesRoute, /updated_at\.toISOString\(\)/);
|
|
assert.doesNotMatch(packagesRoute, /createAdminSupabaseClient|\.from\(|\.insert\(|\.update\(|\.eq\(|\.select\(/);
|
|
});
|
|
|
|
test("后台使用独立的全视口纵向滚动容器而不修改全局聊天溢出边界", () => {
|
|
assert.match(adminApp, /<div className="admin-app-shell">[\s\S]*<ConfigProvider/);
|
|
assert.match(globalsCss, /html, body \{[^}]*overflow: hidden;/);
|
|
assert.match(globalsCss, /\.admin-app-shell \{ height: 100dvh; min-height: 0; overflow-y: auto; \}/);
|
|
assert.match(globalsCss, /\.admin-app-shell > \*, \.admin-app-shell \.ant-layout \{ min-height: 100%; \}/);
|
|
});
|