72 lines
2.8 KiB
TypeScript
72 lines
2.8 KiB
TypeScript
import assert from "node:assert/strict";
|
||
import { readFileSync } from "node:fs";
|
||
import { fileURLToPath } from "node:url";
|
||
import test from "node:test";
|
||
|
||
const management = readFileSync(
|
||
fileURLToPath(new URL("../src/components/admin/feature-pricing-management.tsx", import.meta.url)),
|
||
"utf8",
|
||
);
|
||
const simulator = readFileSync(
|
||
fileURLToPath(new URL("../src/components/admin/pricing-simulator.tsx", import.meta.url)),
|
||
"utf8",
|
||
);
|
||
const labels = readFileSync(
|
||
fileURLToPath(new URL("../src/lib/admin/feature-pricing-labels.ts", import.meta.url)),
|
||
"utf8",
|
||
);
|
||
const readPolicyMigration = readFileSync(
|
||
fileURLToPath(new URL("../supabase/migrations/20260831020000_feature_pricing_admin_runtime_read_policy.sql", import.meta.url)),
|
||
"utf8",
|
||
);
|
||
const source = readFileSync(
|
||
fileURLToPath(new URL("../src/lib/feature-pricing.ts", import.meta.url)),
|
||
"utf8",
|
||
);
|
||
|
||
test("feature pricing resolver calls the server-side RPC and validates its row", () => {
|
||
assert.match(source, /rpc\("resolve_feature_pricing"/);
|
||
assert.match(source, /p_feature_key: featureKey/);
|
||
assert.match(source, /p_model_id: modelId/);
|
||
assert.match(source, /feature_pricing_invalid_response/);
|
||
});
|
||
|
||
test("feature pricing resolver has explicit fail-closed errors", () => {
|
||
assert.match(source, /error\.message/);
|
||
assert.match(source, /feature_pricing_unavailable/);
|
||
assert.match(source, /class FeaturePricingError/);
|
||
});
|
||
|
||
|
||
test("feature pricing admin uses readable labels while preserving stable values", () => {
|
||
for (const [value, label] of [
|
||
["chat.standard", "标准咨询"],
|
||
["chat.premium", "高级咨询"],
|
||
["rectification", "生时校正"],
|
||
["report.full", "完整报告"],
|
||
["report.export", "报告导出"],
|
||
["profile.extra", "额外档案"],
|
||
["standard", "标准模型"],
|
||
["premium", "高级模型"],
|
||
["internal", "内部模型"],
|
||
]) {
|
||
assert.match(labels, new RegExp(`value: "${value.replace(".", "\\.")}"`));
|
||
assert.match(labels, new RegExp(label));
|
||
}
|
||
assert.match(management, /FEATURE_PRICING_OPTIONS/);
|
||
assert.match(management, /MODEL_TIER_OPTIONS/);
|
||
assert.match(management, /featurePricingLabel/);
|
||
assert.match(management, /modelTierLabel/);
|
||
assert.match(management, /草稿(draft)/);
|
||
assert.match(management, /已发布(published)/);
|
||
assert.match(simulator, /featurePricingLabel/);
|
||
assert.match(simulator, /modelTierLabel/);
|
||
});
|
||
|
||
test("admin runtime can list feature pricing rows through an explicit read-only RLS policy", () => {
|
||
assert.match(readPolicyMigration, /grant select on table public\.feature_pricing to admin_runtime/);
|
||
assert.match(readPolicyMigration, /create policy feature_pricing_admin_read on public\.feature_pricing/);
|
||
assert.match(readPolicyMigration, /for select to admin_runtime using \(true\)/);
|
||
assert.doesNotMatch(readPolicyMigration, /for (?:insert|update|delete|all)/);
|
||
});
|