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 { describe, expect, it, vi } from 'vitest';
import { App } from '../app';
import { ServerProvider } from '../context/server-context';
import { ApiClient } from '../lib/api';
import { I18nProvider } from '../lib/i18n';
import type { Role } from '../types';

function clientFor(role: Role, permissions: string[]): ApiClient {
  const client = new ApiClient();
  vi.spyOn(client, 'session').mockResolvedValue({
    authenticated: true,
    csrfToken: 'csrf',
    actor: { id: `${role}-id`, displayName: role, roles: [role], permissions, totpVerified: false },
  });
  vi.spyOn(client, 'status').mockResolvedValue({
    sampledAt: '2026-01-01T00:00:00Z', uptimeSeconds: 1, playersOnline: 1,
  });
  vi.spyOn(client, 'features').mockResolvedValue({
    consoleEnabled: false,
    moderationEnabled: false,
    claimsEnabled: false,
    worldTrackingEnabled: false,
    rollbackEnabled: false,
  });
  vi.spyOn(client, 'subscribe').mockReturnValue(() => undefined);
  return client;
}

function renderApp(client: ApiClient) {
  return render(<I18nProvider><ServerProvider client={client}><App /></ServerProvider></I18nProvider>);
}

describe('permission-aware management UI', () => {
  it('keeps observer player read access but does not expose mutation or inventory controls', async () => {
    localStorage.setItem('xfesm.locale', 'en-US');
    location.hash = '/players';
    const client = clientFor('observer', ['status_read', 'player_read', 'claim_read']);
    vi.spyOn(client, 'players').mockResolvedValue({
      items: [{ uuid: '11111111-1111-1111-1111-111111111111', name: 'Alex', online: true }],
    });

    renderApp(client);

    expect(await screen.findByText('Alex')).toBeInTheDocument();
    expect(screen.getByText('Read only')).toBeInTheDocument();
    expect(screen.queryByRole('button', { name: 'Manage' })).not.toBeInTheDocument();
    expect(screen.queryByRole('button', { name: 'Command policies' })).not.toBeInTheDocument();
    expect(screen.queryByRole('button', { name: 'Audit log' })).not.toBeInTheDocument();
  });

  it('shows helper direct messaging and hides every action the helper cannot perform', async () => {
    localStorage.setItem('xfesm.locale', 'en-US');
    location.hash = '/players';
    const client = clientFor('helper', ['status_read', 'player_read', 'player_message', 'claim_read']);
    vi.spyOn(client, 'players').mockResolvedValue({
      items: [{ uuid: '11111111-1111-1111-1111-111111111111', name: 'Alex', online: true }],
    });
    const inventory = vi.spyOn(client, 'playerInventory');
    const user = userEvent.setup();

    renderApp(client);
    await user.click(await screen.findByRole('button', { name: 'Manage' }));

    expect(screen.getByRole('option', { name: 'Direct message' })).toBeInTheDocument();
    expect(screen.getAllByRole('option')).toHaveLength(1);
    expect(screen.queryByRole('tab', { name: 'Inventory' })).not.toBeInTheDocument();
    expect(screen.queryByRole('tab', { name: 'Ender chest' })).not.toBeInTheDocument();
    expect(inventory).not.toHaveBeenCalled();
  });

  it('blocks direct navigation before an unauthorized policy request is sent', async () => {
    localStorage.setItem('xfesm.locale', 'en-US');
    location.hash = '/policies';
    const client = clientFor('observer', ['status_read', 'player_read', 'claim_read']);
    const policies = vi.spyOn(client, 'policies');

    renderApp(client);

    expect(await screen.findByRole('heading', { name: 'Access denied' })).toBeInTheDocument();
    await waitFor(() => expect(policies).not.toHaveBeenCalled());
  });
});