258 lines
9.6 KiB
TypeScript
258 lines
9.6 KiB
TypeScript
import { afterEach, expect, test, vi } from "vitest";
|
|
import { setAccessToken, setSelectedAppCode } from "@/shared/api/request";
|
|
import { getVipConfig, getVipProgram, grantVipTrialCard, updateVipConfig, updateVipProgram } from "./api";
|
|
|
|
afterEach(() => {
|
|
setAccessToken("");
|
|
setSelectedAppCode("lalu");
|
|
vi.unstubAllGlobals();
|
|
});
|
|
|
|
test("vip program and level APIs normalize snake case responses", async () => {
|
|
setSelectedAppCode("fami");
|
|
vi.stubGlobal(
|
|
"fetch",
|
|
vi
|
|
.fn()
|
|
.mockResolvedValueOnce(
|
|
envelope({
|
|
config: {
|
|
app_code: "fami",
|
|
config_version: 3,
|
|
grant_mode: "trial_card",
|
|
level_count: 9,
|
|
program_type: "tiered_privilege_v1",
|
|
status: "active",
|
|
trial_card_enabled: true,
|
|
upgrade_expiry_policy: "replace_from_now",
|
|
},
|
|
benefits: [
|
|
{
|
|
auto_equip: false,
|
|
benefit_code: "anti_kick",
|
|
benefit_type: "function",
|
|
execution_scope: "room",
|
|
metadata_json: "{}",
|
|
name: "防踢",
|
|
resource_id: 0,
|
|
resource_type: "",
|
|
sort_order: 320,
|
|
status: "active",
|
|
trial_enabled: true,
|
|
unlock_level: 9,
|
|
},
|
|
],
|
|
}),
|
|
)
|
|
.mockResolvedValueOnce(
|
|
envelope({
|
|
levels: [
|
|
{
|
|
benefits: [
|
|
{
|
|
benefit_code: "anti_kick",
|
|
benefit_type: "function",
|
|
unlock_level: 9,
|
|
name: "防踢",
|
|
resource_id: 0,
|
|
resource_type: "",
|
|
execution_scope: "room",
|
|
auto_equip: false,
|
|
metadata_json: "{}",
|
|
sort_order: 10,
|
|
status: "active",
|
|
trial_enabled: true,
|
|
},
|
|
{
|
|
auto_equip: false,
|
|
benefit_code: "daily_coin_rebate",
|
|
benefit_type: "function",
|
|
execution_scope: "wallet",
|
|
metadata_json: "{}",
|
|
name: "金币返现",
|
|
resource_id: 0,
|
|
resource_type: "",
|
|
sort_order: 20,
|
|
status: "active",
|
|
trial_enabled: true,
|
|
unlock_level: 6,
|
|
},
|
|
],
|
|
duration_ms: 2592000000,
|
|
level: 9,
|
|
name: "VIP9",
|
|
price_coin: 9000,
|
|
reward_resource_group_id: 99,
|
|
sort_order: 90,
|
|
status: "active",
|
|
},
|
|
],
|
|
server_time_ms: 1780000000000,
|
|
}),
|
|
),
|
|
);
|
|
|
|
const program = await getVipProgram();
|
|
const config = await getVipConfig();
|
|
|
|
expect(program).toMatchObject({
|
|
appCode: "fami",
|
|
benefitInheritancePolicy: "target_only",
|
|
configVersion: 3,
|
|
grantMode: "trial_card",
|
|
levelCount: 9,
|
|
programType: "tiered_privilege_v1",
|
|
trialCardEnabled: true,
|
|
upgradeExpiryPolicy: "replace_from_now",
|
|
});
|
|
expect(program.benefits).toEqual([
|
|
expect.objectContaining({ benefitCode: "anti_kick", executionScope: "room", unlockLevel: 9 }),
|
|
]);
|
|
expect(config.levels[0]).toMatchObject({
|
|
durationMs: 2592000000,
|
|
level: 9,
|
|
priceCoin: 9000,
|
|
rewardResourceGroupId: 99,
|
|
});
|
|
expect(config.levels[0].benefits[0]).toEqual({
|
|
benefitCode: "anti_kick",
|
|
benefitType: "function",
|
|
unlockLevel: 9,
|
|
name: "防踢",
|
|
resourceId: 0,
|
|
resourceType: "",
|
|
executionScope: "room",
|
|
autoEquip: false,
|
|
metadataJson: "{}",
|
|
sortOrder: 10,
|
|
status: "active",
|
|
trialEnabled: true,
|
|
});
|
|
expect(config.levels[0].benefits[1]).toMatchObject({
|
|
benefitCode: "daily_coin_rebate",
|
|
trialEnabled: false,
|
|
});
|
|
expect(requestHeaders(vi.mocked(fetch).mock.calls[0][1])["X-App-Code"]).toBe("fami");
|
|
});
|
|
|
|
test("vip updates and trial grant use generated contract paths", async () => {
|
|
setSelectedAppCode("fami");
|
|
vi.stubGlobal(
|
|
"fetch",
|
|
vi
|
|
.fn()
|
|
.mockResolvedValueOnce(
|
|
envelope({ appCode: "fami", levelCount: 9, programType: "tiered_privilege_v1", status: "active" }),
|
|
)
|
|
.mockResolvedValueOnce(envelope({ levels: [] }))
|
|
.mockResolvedValueOnce(envelope({ transactionId: "trial_1" }, 201)),
|
|
);
|
|
|
|
await updateVipProgram({
|
|
benefitInheritancePolicy: "target_only",
|
|
downgradePurchasePolicy: "reject",
|
|
grantMode: "trial_card",
|
|
levelCount: 9,
|
|
programType: "tiered_privilege_v1",
|
|
sameLevelExpiryPolicy: "extend_remaining",
|
|
status: "active",
|
|
trialCardEnabled: true,
|
|
upgradeExpiryPolicy: "replace_from_now",
|
|
});
|
|
await updateVipConfig({
|
|
levels: [
|
|
{
|
|
benefits: [
|
|
{
|
|
benefitCode: "room_entry_notice",
|
|
benefitType: "function",
|
|
unlockLevel: 2,
|
|
name: "VIP进房通知",
|
|
resourceId: 0,
|
|
resourceType: "",
|
|
executionScope: "room",
|
|
autoEquip: false,
|
|
metadataJson: "{}",
|
|
sortOrder: 10,
|
|
status: "active",
|
|
trialEnabled: true,
|
|
},
|
|
{
|
|
benefitCode: "daily_coin_rebate",
|
|
benefitType: "function",
|
|
unlockLevel: 6,
|
|
name: "金币返现",
|
|
resourceId: 0,
|
|
resourceType: "",
|
|
executionScope: "wallet",
|
|
autoEquip: false,
|
|
metadataJson: "{}",
|
|
sortOrder: 20,
|
|
status: "active",
|
|
trialEnabled: true,
|
|
},
|
|
],
|
|
durationMs: 2592000000,
|
|
level: 2,
|
|
name: "VIP2",
|
|
priceCoin: 2000,
|
|
requiredRechargeCoinAmount: 0,
|
|
rewardResourceGroupId: 22,
|
|
sortOrder: 20,
|
|
status: "active",
|
|
},
|
|
],
|
|
});
|
|
await grantVipTrialCard({
|
|
commandId: "vip-trial-card-grant-test",
|
|
durationMs: 20 * 24 * 60 * 60 * 1000,
|
|
level: 5,
|
|
reason: "manual",
|
|
targetUserId: "318705991371722752",
|
|
});
|
|
|
|
const [programUrl, programInit] = vi.mocked(fetch).mock.calls[0];
|
|
const [configUrl, configInit] = vi.mocked(fetch).mock.calls[1];
|
|
const [grantUrl, grantInit] = vi.mocked(fetch).mock.calls[2];
|
|
expect(String(programUrl)).toContain("/api/v1/admin/activity/vip-program");
|
|
expect(programInit?.method).toBe("PUT");
|
|
expect(requestBody(programInit)).toMatchObject({
|
|
config: {
|
|
levelCount: 9,
|
|
programType: "tiered_privilege_v1",
|
|
status: "active",
|
|
grantMode: "trial_card",
|
|
benefitInheritancePolicy: "target_only",
|
|
upgradeExpiryPolicy: "replace_from_now",
|
|
},
|
|
});
|
|
expect(String(configUrl)).toContain("/api/v1/admin/activity/vip-levels");
|
|
expect(configInit?.method).toBe("PUT");
|
|
expect(requestBody(configInit)).toMatchObject({
|
|
levels: [
|
|
expect.objectContaining({
|
|
benefits: [
|
|
expect.objectContaining({ benefitCode: "room_entry_notice" }),
|
|
expect.objectContaining({ benefitCode: "daily_coin_rebate", trialEnabled: false }),
|
|
],
|
|
}),
|
|
],
|
|
});
|
|
expect(String(grantUrl)).toContain("/api/v1/admin/activity/vip-trial-card-grants");
|
|
expect(grantInit?.method).toBe("POST");
|
|
expect(requestBody(grantInit)).toMatchObject({ durationMs: 1728000000, level: 5 });
|
|
expect(requestBody(grantInit)).not.toHaveProperty("resourceId");
|
|
});
|
|
|
|
function envelope(data: unknown, status = 200) {
|
|
return new Response(JSON.stringify({ code: 0, data }), { status });
|
|
}
|
|
|
|
function requestHeaders(init: RequestInit | undefined): Record<string, string> {
|
|
return (init?.headers || {}) as Record<string, string>;
|
|
}
|
|
|
|
function requestBody(init: RequestInit | undefined): Record<string, unknown> {
|
|
return JSON.parse(String(init?.body || "{}")) as Record<string, unknown>;
|
|
}
|