XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFEServerManager

【Java】我的世界XFE服务器管理器

公开
关注 0 Fork 0 Star 0
UTF-8
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { afterEach, describe, expect, it, vi } from 'vitest';
import { ServerProvider } from '../context/server-context';
import { ApiClient } from '../lib/api';
import { I18nProvider } from '../lib/i18n';
import type { CurrencyDefinition, EconomyAccount, EconomyWorkspace } from '../types';
import { EconomyPage } from './economy';

const timestamp = '2026-09-04T00:00:00Z';
const currency: CurrencyDefinition = {
  id: '00000000-0000-0000-0000-000000000100', code: 'coins', name: '金币', symbol: '⛃',
  icon: 'item:minecraft:emerald', fractionDigits: 2, initialBalance: '0.00', minimumBalance: '0.00',
  maximumBalance: '1000000000000.00', playerTransferAllowed: true, enabled: true, primary: true,
  revision: 0, createdBy: 'owner', createdAt: timestamp, updatedAt: timestamp,
};
const workspace: EconomyWorkspace = { currencies: [currency], overview: { observedAt: timestamp, currencies: [{
  currencyId: currency.id, code: currency.code, name: currency.name, symbol: currency.symbol, icon: currency.icon,
  fractionDigits: 2, enabled: true, primary: true, accountCount: 1, totalSupply: '25.00',
  minimumBalance: '25.00', maximumBalance: '25.00', transactionCount: 1, transferVolume24h: '0.00',
}] } };
const account: EconomyAccount = { playerId: '00000000-0000-0000-0000-000000000200', playerName: 'Steve',
  updatedAt: timestamp, balances: [{ currencyId: currency.id, currencyCode: 'coins', currencyName: '金币',
    symbol: '⛃', icon: currency.icon, fractionDigits: 2, amount: '25.00', revision: 1,
    currencyEnabled: true, updatedAt: timestamp }] };
const targetAccount: EconomyAccount = { ...account, playerId: '00000000-0000-0000-0000-000000000201',
  playerName: 'Alex', balances: [{ ...account.balances[0], amount: '5.00', revision: 2 }] };

function client(writable = true): ApiClient {
  const api = new ApiClient();
  vi.spyOn(api, 'session').mockResolvedValue({ authenticated: true, csrfToken: 'csrf', actor: {
    id: 'owner', displayName: 'Owner', roles: writable ? ['owner'] : ['observer'],
    permissions: writable ? ['economy_read', 'economy_manage'] : ['economy_read'], totpVerified: true,
  } });
  vi.spyOn(api, 'status').mockResolvedValue({ sampledAt: timestamp, uptimeSeconds: 1, playersOnline: 1 });
  vi.spyOn(api, 'features').mockResolvedValue({ consoleEnabled: false, moderationEnabled: false,
    claimsEnabled: false, worldTrackingEnabled: false, rollbackEnabled: false, joinExperienceEnabled: true });
  vi.spyOn(api, 'subscribe').mockReturnValue(() => undefined);
  vi.spyOn(api, 'economy').mockResolvedValue(workspace);
  vi.spyOn(api, 'economyAccounts').mockResolvedValue({ items: [account] });
  vi.spyOn(api, 'economyTransactions').mockResolvedValue({ items: [] });
  vi.spyOn(api, 'createCurrency').mockResolvedValue({ currency });
  vi.spyOn(api, 'adjustEconomy').mockResolvedValue({ currency, transaction: {
    id: '00000000-0000-0000-0000-000000000300', currencyId: currency.id, currencyCode: 'coins',
    kind: 'deposit', sourcePlayerName: '', targetPlayerId: account.playerId, targetPlayerName: account.playerName,
    amount: '5.00', sourceBalanceBefore: '', sourceBalanceAfter: '', targetBalanceBefore: '25.00',
    targetBalanceAfter: '30.00', reason: '测试奖励', actor: 'owner', origin: 'web', correlationId: 'test', createdAt: timestamp,
  }, targetBalance: account.balances[0] });
  vi.spyOn(api, 'transferEconomy').mockResolvedValue({ currency, transaction: {
    id: '00000000-0000-0000-0000-000000000301', currencyId: currency.id, currencyCode: 'coins',
    kind: 'transfer', sourcePlayerId: account.playerId, sourcePlayerName: account.playerName,
    targetPlayerId: targetAccount.playerId, targetPlayerName: targetAccount.playerName, amount: '2.00',
    sourceBalanceBefore: '25.00', sourceBalanceAfter: '23.00', targetBalanceBefore: '5.00',
    targetBalanceAfter: '7.00', reason: '测试转账', actor: 'owner', origin: 'web', correlationId: 'test', createdAt: timestamp,
  }, sourceBalance: account.balances[0], targetBalance: targetAccount.balances[0] });
  return api;
}

function renderEconomy(api: ApiClient) {
  return render(<I18nProvider><ServerProvider client={api}><EconomyPage /></ServerProvider></I18nProvider>);
}

describe('economy workspace', () => {
  afterEach(() => vi.restoreAllMocks());

  it('creates a currency through the guarded editor', async () => {
    const api = client(); const user = userEvent.setup(); renderEconomy(api);
    await user.click(await screen.findByRole('button', { name: '添加货币' }));
    await user.type(await screen.findByLabelText(/^货币代码/), 'gems');
    await user.type(screen.getByLabelText('显示名称'), '宝石');
    await user.type(screen.getByLabelText('符号'), '◆');
    await user.click(screen.getByRole('button', { name: /保存并生效/ }));
    await waitFor(() => expect(api.createCurrency).toHaveBeenCalledTimes(1));
    expect(vi.mocked(api.createCurrency).mock.calls[0][0]).toMatchObject({ code: 'gems', name: '宝石', symbol: '◆' });
  });

  it('adjusts an account with its current optimistic revision', async () => {
    const api = client(); const user = userEvent.setup(); renderEconomy(api);
    await user.click(await screen.findByRole('button', { name: /账户与调整/ }));
    expect((await screen.findAllByText('Steve')).length).toBeGreaterThan(0);
    await user.type(screen.getAllByLabelText(/^金额/)[0], '5');
    await user.type(screen.getAllByLabelText('审计原因')[0], '测试奖励');
    await user.click(screen.getByRole('button', { name: '执行调整' }));
    await waitFor(() => expect(api.adjustEconomy).toHaveBeenCalledWith(expect.objectContaining({
      playerId: account.playerId, currency: currency.id, amount: '5', expectedRevision: 1,
    }))); 
  });

  it('allows an audited management transfer when player self-pay is disabled', async () => {
    const api = client(); const user = userEvent.setup();
    vi.mocked(api.economy).mockResolvedValue({ ...workspace,
      currencies: [{ ...currency, playerTransferAllowed: false }] });
    vi.mocked(api.economyAccounts).mockResolvedValue({ items: [account, targetAccount] });
    renderEconomy(api);
    await user.click(await screen.findByRole('button', { name: /账户与调整/ }));
    expect((await screen.findAllByText('Alex')).length).toBeGreaterThan(0);
    await user.type(screen.getAllByLabelText(/^金额/)[1], '2');
    await user.type(screen.getAllByLabelText('审计原因')[1], '测试转账');
    await user.click(screen.getByRole('button', { name: '确认转账' }));
    await waitFor(() => expect(api.transferEconomy).toHaveBeenCalledWith(expect.objectContaining({
      sourcePlayerId: account.playerId, targetPlayerId: targetAccount.playerId,
      currency: currency.id, amount: '2', expectedSourceRevision: 1,
    })));
  });
});