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 { 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 { 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 { 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'); });