162 lines
4.1 KiB
TypeScript
162 lines
4.1 KiB
TypeScript
import { expect, test } from 'vitest';
|
|
|
|
import type {
|
|
ProfileMembership,
|
|
ProfileRechargeProduct,
|
|
ProfileWalletLedgerEntry,
|
|
} from '../../../packages/shared/src/contracts/runtime';
|
|
import {
|
|
buildMembershipLabel,
|
|
buildRechargeProductValueLabel,
|
|
buildWalletLedgerPresentation,
|
|
formatRechargePrice,
|
|
formatWalletLedgerAmount,
|
|
getWalletLedgerSourceLabel,
|
|
} from './rpgEntryProfileFundsViewModel';
|
|
|
|
function buildLedgerEntry(
|
|
overrides: Partial<ProfileWalletLedgerEntry> = {},
|
|
): ProfileWalletLedgerEntry {
|
|
return {
|
|
id: 'ledger-1',
|
|
amountDelta: 30,
|
|
balanceAfter: 80,
|
|
sourceType: 'invite_invitee_reward',
|
|
createdAt: '2026-06-03T00:00:00.000Z',
|
|
...overrides,
|
|
};
|
|
}
|
|
|
|
function buildRechargeProduct(
|
|
overrides: Partial<ProfileRechargeProduct> = {},
|
|
): ProfileRechargeProduct {
|
|
return {
|
|
productId: 'points_60',
|
|
title: '60泥点',
|
|
priceCents: 600,
|
|
kind: 'points',
|
|
pointsAmount: 60,
|
|
bonusPoints: 60,
|
|
durationDays: 0,
|
|
badgeLabel: '首充双倍',
|
|
description: '首充送60泥点',
|
|
tier: 'normal',
|
|
...overrides,
|
|
};
|
|
}
|
|
|
|
function buildMembership(
|
|
overrides: Partial<ProfileMembership> = {},
|
|
): ProfileMembership {
|
|
return {
|
|
status: 'normal',
|
|
tier: 'normal',
|
|
startedAt: null,
|
|
expiresAt: null,
|
|
updatedAt: null,
|
|
...overrides,
|
|
};
|
|
}
|
|
|
|
test('profile funds ViewModel formats ledger amount labels', () => {
|
|
expect(formatWalletLedgerAmount(-1)).toBe('-1');
|
|
expect(formatWalletLedgerAmount(0)).toBe('0');
|
|
expect(formatWalletLedgerAmount(30)).toBe('+30');
|
|
});
|
|
|
|
test('profile funds ViewModel resolves ledger source labels with raw fallback', () => {
|
|
expect(getWalletLedgerSourceLabel('asset_operation_consume')).toBe(
|
|
'资产操作消耗',
|
|
);
|
|
expect(getWalletLedgerSourceLabel('puzzle_author_incentive_claim')).toBe(
|
|
'拼图作者奖励',
|
|
);
|
|
expect(getWalletLedgerSourceLabel('future_source')).toBe('future_source');
|
|
expect(getWalletLedgerSourceLabel('')).toBe('未知来源');
|
|
});
|
|
|
|
test('profile funds ViewModel builds wallet ledger presentation', () => {
|
|
const incomeEntry = buildLedgerEntry({
|
|
id: 'ledger-income',
|
|
amountDelta: 30,
|
|
balanceAfter: 80,
|
|
sourceType: 'puzzle_author_incentive_claim',
|
|
});
|
|
const outcomeEntry = buildLedgerEntry({
|
|
id: 'ledger-outcome',
|
|
amountDelta: -1,
|
|
balanceAfter: 79,
|
|
sourceType: 'asset_operation_consume',
|
|
});
|
|
|
|
expect(
|
|
buildWalletLedgerPresentation(
|
|
{ entries: [incomeEntry, outcomeEntry] },
|
|
12,
|
|
),
|
|
).toEqual({
|
|
balance: 80,
|
|
balanceLabel: '80泥点',
|
|
entries: [
|
|
{
|
|
amountLabel: '+30',
|
|
balanceLabel: '余额 80',
|
|
createdAt: '2026-06-03T00:00:00.000Z',
|
|
id: 'ledger-income',
|
|
isIncome: true,
|
|
sourceLabel: '拼图作者奖励',
|
|
},
|
|
{
|
|
amountLabel: '-1',
|
|
balanceLabel: '余额 79',
|
|
createdAt: '2026-06-03T00:00:00.000Z',
|
|
id: 'ledger-outcome',
|
|
isIncome: false,
|
|
sourceLabel: '资产操作消耗',
|
|
},
|
|
],
|
|
});
|
|
|
|
expect(buildWalletLedgerPresentation({ entries: [] }, 12)).toEqual({
|
|
balance: 12,
|
|
balanceLabel: '12泥点',
|
|
entries: [],
|
|
});
|
|
});
|
|
|
|
test('profile funds ViewModel formats recharge product and membership labels', () => {
|
|
expect(formatRechargePrice(600)).toBe('¥6');
|
|
expect(formatRechargePrice(650)).toBe('¥6.50');
|
|
expect(buildRechargeProductValueLabel(buildRechargeProduct())).toBe(
|
|
'60+60泥点',
|
|
);
|
|
expect(
|
|
buildRechargeProductValueLabel(
|
|
buildRechargeProduct({
|
|
kind: 'membership',
|
|
pointsAmount: 0,
|
|
bonusPoints: 0,
|
|
durationDays: 30,
|
|
}),
|
|
),
|
|
).toBe('30天');
|
|
expect(buildMembershipLabel(buildMembership(), (value) => value)).toBe(
|
|
'普通用户',
|
|
);
|
|
expect(
|
|
buildMembershipLabel(
|
|
buildMembership({ status: 'active', expiresAt: null }),
|
|
(value) => value,
|
|
),
|
|
).toBe('会员已生效');
|
|
expect(
|
|
buildMembershipLabel(
|
|
buildMembership({
|
|
status: 'active',
|
|
expiresAt: '2026-06-03T00:00:00.000Z',
|
|
}),
|
|
() => '06/03 08:00',
|
|
),
|
|
).toBe('会员至 06/03 08:00');
|
|
});
|