/**
* @vitest-environment happy-dom
*/
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { cleanup, render, screen, waitFor, fireEvent } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { MemoryRouter } from 'react-router-dom';
import { type ReactNode } from 'react';
import { mockAgent, mockServerInfo } from '../test/fixtures';
import { api } from '../api/client';
import { downloadApiFile, downloadAuthedFile } from '../api/download';
import { getStoredAuth } from '../api/auth';
import { useWebSocket } from '../hooks/useWebSocket';
import { DEFAULT_FLEET_FILTERS } from '../help/fleetFilters';
import NeonCard from './NeonCard/NeonCard';
import { HelpTip, FieldHint } from './HelpTip';
import DownloadButton from './DownloadButton';
import AuthDownloadButton from './AuthDownloadButton';
import ErrorBoundary from './ErrorBoundary';
import SessionGate from './SessionGate';
import GaugeRing from './Charts/GaugeRing';
import HashrateChart from './Charts/HashrateChart';
import AgentRemoteActions from './Fleet/AgentRemoteActions';
import AgentListItem from './Fleet/AgentListItem';
import FleetToolbar from './Fleet/FleetToolbar';
import { LanDownloadQR } from './Fleet/LanDownloadQR';
import {
AlertBanner,
PoolStatusPanel,
AIActivityPanel,
EarningsEstimator,
FleetHealthCard,
ContributionBars,
UnderperformerList,
OSArchBreakdown,
LANGroupView,
} from './Fleet/FleetPanels';
import { ForgeLockedHint, ForgeFieldBadge, ForgeSectionHeader } from './Forge/ForgeFieldHints';
import {
PipelineFlow,
FleetPipelineStatus,
ActivityPulse,
ForgeCalibrateCompare,
RoadmapGrid,
} from './Visual/VisualComponents';
import MatrixStreamOverlay from './Visual/MatrixStreamOverlay';
import SystemStatusBar from './Visual/SystemStatusBar';
import FleetTopologyMap from './Visual/3D/FleetTopologyMap';
import Layout from './Layout/Layout';
import AmbientBackground from './Ambient/AmbientBackground';
import CursorFire from './Visual/CursorFire';
import MatrixRain from './Layout/MatrixRain';
vi.mock('../hooks/useWebSocket', () => ({
useWebSocket: vi.fn(),
}));
vi.mock('../context/ForgeContext', () => ({
useForge: vi.fn(() => ({ forging: false, stage: '' })),
}));
vi.mock('../api/download', () => ({
downloadApiFile: vi.fn(),
downloadAuthedFile: vi.fn(),
}));
vi.mock('../api/auth', () => ({
getStoredAuth: vi.fn(),
setStoredAuth: vi.fn(),
}));
vi.mock('qrcode', () => ({
default: {
toCanvas: vi.fn().mockResolvedValue(undefined),
},
}));
vi.mock('recharts', async () => {
const actual = await vi.importActual('recharts');
return {
...actual,
ResponsiveContainer: ({ children }: { children: ReactNode }) => (
{children}
),
};
});
vi.mock('@react-three/fiber', () => ({
Canvas: ({ children }: { children: ReactNode }) => {children}
,
useFrame: () => {},
}));
vi.mock('@react-three/drei', () => ({
OrbitControls: () => null,
Stars: () => null,
Line: () => null,
Sphere: () => null,
}));
const useWebSocketMock = vi.mocked(useWebSocket);
const downloadApiFileMock = vi.mocked(downloadApiFile);
const downloadAuthedFileMock = vi.mocked(downloadAuthedFile);
const getStoredAuthMock = vi.mocked(getStoredAuth);
function ThrowOnce({ shouldThrow }: { shouldThrow: boolean }) {
if (shouldThrow) throw new Error('render boom');
return child ok;
}
describe('NeonCard', () => {
afterEach(() => cleanup());
it('renders children with default brass accent and 3d class', () => {
render(Inner);
const card = screen.getByText('Inner').closest('.neon-card');
expect(card).toHaveClass('neon-card-brass', 'neon-card-3d');
expect(card?.querySelector('.neon-card-rim')).toBeTruthy();
});
it('applies accent, hud, tilt3d off, and custom className', () => {
render(
X
);
const card = screen.getByText('X').closest('.neon-card');
expect(card).toHaveClass('neon-card-cyan', 'hud-corners', 'extra');
expect(card).not.toHaveClass('neon-card-3d');
});
});
describe('HelpTip', () => {
afterEach(() => cleanup());
it('returns null for unknown field', () => {
const { container } = render();
expect(container.firstChild).toBeNull();
});
it('shows help popup on hover for known field', async () => {
render();
expect(screen.getByRole('button', { name: /Help: calibrate_wallet/ })).toBeInTheDocument();
await userEvent.setup().hover(screen.getByRole('button'));
await waitFor(() => {
expect(screen.getByRole('tooltip')).toHaveTextContent(/Monero payout address/i);
});
});
it('FieldHint export is deprecated no-op', () => {
const { container } = render();
expect(container.firstChild).toBeNull();
});
});
describe('DownloadButton', () => {
afterEach(() => cleanup());
beforeEach(() => {
downloadApiFileMock.mockReset();
});
it('downloads on click and shows busy label', async () => {
downloadApiFileMock.mockImplementation(() => new Promise((r) => setTimeout(r, 50)));
render(
Save
);
const btn = screen.getByRole('button', { name: 'Save' });
await userEvent.setup().click(btn);
expect(screen.getByRole('button', { name: 'Downloading…' })).toBeDisabled();
await waitFor(() => expect(downloadApiFileMock).toHaveBeenCalledWith('/api/x', 'a.bin'));
});
it('alerts on download failure', async () => {
downloadApiFileMock.mockRejectedValue(new Error('network down'));
const alertSpy = vi.spyOn(window, 'alert').mockImplementation(() => {});
render(
Save
);
await userEvent.setup().click(screen.getByRole('button'));
await waitFor(() => expect(alertSpy).toHaveBeenCalledWith('network down'));
alertSpy.mockRestore();
});
});
describe('AuthDownloadButton', () => {
afterEach(() => cleanup());
beforeEach(() => {
downloadAuthedFileMock.mockReset();
});
it('calls downloadAuthedFile and shows ellipsis while busy', async () => {
downloadAuthedFileMock.mockImplementation(() => new Promise((r) => setTimeout(r, 30)));
render(
DL
);
await userEvent.setup().click(screen.getByRole('button', { name: 'DL' }));
expect(screen.getByRole('button', { name: '…' })).toBeDisabled();
await waitFor(() =>
expect(downloadAuthedFileMock).toHaveBeenCalledWith('/api/build/1', 'b.exe')
);
});
});
describe('ErrorBoundary', () => {
afterEach(() => cleanup());
it('renders children when no error', () => {
render(
);
expect(screen.getByText('child ok')).toBeInTheDocument();
});
it('shows fallback UI and clears error on retry', async () => {
let throwNow = true;
function MaybeThrow() {
if (throwNow) throw new Error('render boom');
return child ok;
}
render(
);
expect(screen.getByRole('heading', { name: 'Something failed to render' })).toBeInTheDocument();
throwNow = false;
await userEvent.setup().click(screen.getByRole('button', { name: 'Retry' }));
expect(screen.getByText('child ok')).toBeInTheDocument();
});
it('uses custom fallback when provided', () => {
render(
Custom fail
}>
);
expect(screen.getByText('Custom fail')).toBeInTheDocument();
});
});
describe('SessionGate', () => {
afterEach(() => {
cleanup();
vi.unstubAllGlobals();
});
beforeEach(() => {
getStoredAuthMock.mockReturnValue(null);
});
it('shows login form when unauthenticated', async () => {
vi.stubGlobal(
'fetch',
vi.fn().mockResolvedValue({ ok: false })
);
render(
protected
);
await waitFor(() => {
expect(screen.getByRole('heading', { name: 'AetherForge' })).toBeInTheDocument();
});
expect(screen.queryByText('protected')).not.toBeInTheDocument();
});
it('renders children when stored auth validates', async () => {
getStoredAuthMock.mockReturnValue('dGVzdA==');
vi.stubGlobal('fetch', vi.fn().mockResolvedValue({ ok: true }));
render(
protected
);
await waitFor(() => expect(screen.getByText('protected')).toBeInTheDocument());
});
});
describe('GaugeRing', () => {
afterEach(() => cleanup());
it('renders label and percentage for percent-scale max', () => {
render();
expect(screen.getByText('42%')).toBeInTheDocument();
expect(screen.getByText('CPU')).toBeInTheDocument();
expect(screen.getByText('load')).toBeInTheDocument();
});
it('shows raw value in center while ring arc clamps to 0–100%', () => {
const { rerender, container } = render();
expect(screen.getByText('-10%')).toBeInTheDocument();
const fill = container.querySelector('.gauge-ring-fill') as SVGCircleElement;
expect(fill.getAttribute('stroke-dashoffset')).toBe(String(2 * Math.PI * 42));
rerender();
expect(screen.getByText('200%')).toBeInTheDocument();
expect((container.querySelector('.gauge-ring-fill') as SVGCircleElement).getAttribute('stroke-dashoffset')).toBe('0');
});
});
describe('HashrateChart', () => {
afterEach(() => cleanup());
it('shows empty state when data is empty', () => {
render();
expect(screen.getByText('Fleet Hash')).toBeInTheDocument();
expect(screen.getByText(/Awaiting signal from fleet/i)).toBeInTheDocument();
});
it('renders chart with data points', () => {
render(
);
expect(screen.getByText('Live')).toBeInTheDocument();
expect(screen.getByText('● LIVE')).toBeInTheDocument();
expect(screen.getByTestId('recharts-responsive')).toBeInTheDocument();
});
});
describe('AgentRemoteActions', () => {
afterEach(() => cleanup());
beforeEach(() => {
vi.spyOn(api, 'listBuilds').mockResolvedValue([]);
vi.spyOn(api, 'sendAgentCommand').mockResolvedValue({ success: true });
});
it('compact mode disables actions when offline', () => {
render(
);
expect(screen.getByRole('button', { name: 'Pause' })).toBeDisabled();
expect(screen.getByRole('button', { name: 'Resume' })).toBeDisabled();
});
it('compact dispatches pause when online', async () => {
const cmd = vi.spyOn(api, 'sendAgentCommand').mockResolvedValue({ success: true });
render(
);
await userEvent.setup().click(screen.getByRole('button', { name: 'Pause' }));
await waitFor(() => expect(cmd).toHaveBeenCalledWith('a1', 'pause', {}));
});
it('full panel shows Target heading and recon section', async () => {
render();
await waitFor(() => {
expect(screen.getByRole('heading', { name: 'Target: Node A' })).toBeInTheDocument();
});
expect(screen.getByRole('heading', { name: 'Recon & Intel' })).toBeInTheDocument();
expect(screen.getByText(/Awaiting telemetry/i)).toBeInTheDocument();
});
it('disables recon buttons when agent offline', async () => {
render();
await waitFor(() => {
expect(screen.getByRole('heading', { name: /Target:/i })).toBeInTheDocument();
});
expect(screen.getByRole('button', { name: 'Screenshot' })).toBeDisabled();
});
});
describe('AgentListItem', () => {
afterEach(() => cleanup());
const baseProps = {
agent: mockAgent({ name: 'List Node', tags: ['rack'], notes: 'a'.repeat(90) }),
selected: false,
expanded: false,
onToggleExpand: vi.fn(),
onSelect: vi.fn(),
};
it('renders name, status, and click hint when collapsed', () => {
render();
expect(screen.getByText('List Node')).toBeInTheDocument();
expect(screen.getByText('online')).toBeInTheDocument();
expect(screen.getByText('click for details')).toBeInTheDocument();
expect(screen.getByText('rack')).toBeInTheDocument();
});
it('truncates long notes preview when collapsed', () => {
render();
const preview = screen.getByText(/…$/);
expect(preview.textContent!.length).toBeLessThanOrEqual(81);
});
it('expands meta and remote actions', async () => {
vi.spyOn(api, 'listBuilds').mockResolvedValue([]);
render();
expect(screen.getByText(/Shares:/)).toBeInTheDocument();
expect(screen.getByRole('button', { name: 'Pause' })).toBeInTheDocument();
});
it('checkbox stops row navigation', async () => {
const onCheck = vi.fn();
render();
await userEvent.setup().click(screen.getByRole('checkbox'));
expect(onCheck).toHaveBeenCalledWith(true);
expect(baseProps.onSelect).not.toHaveBeenCalled();
});
});
describe('FleetToolbar', () => {
afterEach(() => cleanup());
const filters = { ...DEFAULT_FLEET_FILTERS };
const agents = [
mockAgent({ tags: ['prod'], ip: '10.0.0.5' }),
mockAgent({ id: 'a2', name: 'B', tags: ['dev'], ip: '10.0.1.2' }),
];
it('renders search and filter controls', () => {
render(
);
expect(screen.getByPlaceholderText('Search name, IP, notes, tags…')).toBeInTheDocument();
expect(screen.getByText('All tags')).toBeInTheDocument();
});
it('shows bulk bar when agents selected', async () => {
const onBulk = vi.fn();
render(
);
expect(screen.getByText('2 selected')).toBeInTheDocument();
await userEvent.setup().click(screen.getByRole('button', { name: 'Pause' }));
expect(onBulk).toHaveBeenCalledWith('pause');
});
it('shows select-all filtered when props provided', () => {
const onSelectAll = vi.fn();
render(
);
fireEvent.click(screen.getByRole('button', { name: 'Select all filtered (3)' }));
expect(onSelectAll).toHaveBeenCalled();
});
});
describe('LanDownloadQR', () => {
afterEach(() => cleanup());
it('returns null without url', () => {
const { container } = render();
expect(container.firstChild).toBeNull();
});
it('renders canvas when url provided', () => {
const { container } = render();
expect(container.querySelector('canvas')).toBeTruthy();
});
});
describe('FleetPanels', () => {
afterEach(() => cleanup());
it('AlertBanner returns null when empty', () => {
const { container } = render();
expect(container.firstChild).toBeNull();
});
it('AlertBanner shows up to five alerts', () => {
const alerts = [
{ id: '1', level: 'warning', type: 'offline', message: 'Node down', timestamp: '2026-05-30T12:00:00Z' },
];
render();
expect(screen.getByText('OFFLINE')).toBeInTheDocument();
expect(screen.getByText('Node down')).toBeInTheDocument();
});
it('PoolStatusPanel empty hint', () => {
render();
expect(screen.getByRole('heading', { name: /Pool Stratum Status/i })).toBeInTheDocument();
expect(screen.getByText(/No forged pool connections yet/i)).toBeInTheDocument();
});
it('AIActivityPanel maps agent names', () => {
render(
);
expect(screen.getByText('Friendly')).toBeInTheDocument();
});
it('FleetHealthCard shows score and label', () => {
render(
);
expect(screen.getByText('NOMINAL')).toBeInTheDocument();
expect(screen.getByText('88')).toBeInTheDocument();
expect(screen.getByText('All good')).toBeInTheDocument();
});
it('ContributionBars returns null when empty', () => {
const { container } = render();
expect(container.firstChild).toBeNull();
});
it('ContributionBars renders rows', () => {
render(
);
expect(screen.getByRole('heading', { name: /Contribution Map/i })).toBeInTheDocument();
expect(screen.getByText('A')).toBeInTheDocument();
});
it('OSArchBreakdown returns null when empty', () => {
const { container } = render();
expect(container.firstChild).toBeNull();
});
it('LANGroupView needs at least two groups', () => {
const { container } = render(
);
expect(container.firstChild).toBeNull();
});
it('EarningsEstimator returns null when hashrate zero', () => {
const { container } = render();
expect(container.firstChild).toBeNull();
});
it('UnderperformerList restart calls bulk API', async () => {
const agents = [mockAgent({ id: 'u1', name: 'Slow' })];
const bulk = vi.spyOn(api, 'sendBulkCommand').mockResolvedValue({ success: true, sent: 1, failed: 0, action: 'restart' });
render();
await userEvent.setup().click(screen.getByRole('button', { name: /Restart All/i }));
await waitFor(() => expect(bulk).toHaveBeenCalledWith(['u1'], 'restart'));
expect(await screen.findByText(/Restart sent to 1/i)).toBeInTheDocument();
});
});
describe('ForgeFieldHints', () => {
afterEach(() => cleanup());
it('ForgeLockedHint null without meta', () => {
const { container } = render();
expect(container.firstChild).toBeNull();
});
it('ForgeFieldBadge shows baked label', () => {
render();
expect(screen.getByText('⛏ baked')).toBeInTheDocument();
});
it('ForgeSectionHeader renders title and badge', () => {
render(
);
expect(screen.getByRole('heading', { name: 'Pool' })).toBeInTheDocument();
expect(screen.getByText(/server/i)).toBeInTheDocument();
});
});
describe('VisualComponents', () => {
afterEach(() => cleanup());
it('PipelineFlow highlights active step', () => {
render();
expect(document.querySelector('.pipeline-active')).toBeTruthy();
});
it('FleetPipelineStatus shows step labels', () => {
render(
);
expect(screen.getByText('Forged')).toBeInTheDocument();
expect(screen.getByText('Shares')).toBeInTheDocument();
});
it('ActivityPulse empty message', () => {
render();
expect(screen.getByText(/Awaiting fleet activity/i)).toBeInTheDocument();
});
it('ForgeCalibrateCompare links to routes', () => {
render(
);
expect(screen.getByText(/Forge — baked into each binary/i)).toBeInTheDocument();
});
it('RoadmapGrid lists features', () => {
render();
expect(document.querySelectorAll('.roadmap-card').length).toBeGreaterThan(0);
});
});
describe('MatrixStreamOverlay', () => {
afterEach(() => cleanup());
beforeEach(() => {
useWebSocketMock.mockReturnValue({
isConnected: true,
agents: [],
recentShares: [],
fleetAlerts: [],
poolStatus: [],
aiActivity: [],
agentLogs: {},
commandResults: [],
latestMessage: null,
});
});
it('returns null when inactive', () => {
const { container } = render();
expect(container.firstChild).toBeNull();
});
it('shows overlay heading when active', () => {
render();
expect(screen.getByText('RAW_SOCKET_STREAM [ACTIVE]')).toBeInTheDocument();
});
});
describe('SystemStatusBar', () => {
afterEach(() => cleanup());
beforeEach(() => {
vi.spyOn(api, 'healthCheck').mockResolvedValue(undefined);
vi.spyOn(api, 'listAgents').mockResolvedValue([mockAgent(), mockAgent({ id: 'a2', status: 'offline' })]);
vi.spyOn(api, 'listBuilds').mockResolvedValue([{ id: 'b1' } as never]);
});
it('shows server and fleet pills after poll', async () => {
render(
);
await waitFor(() => {
expect(screen.getByText(/SERVER UP/i)).toBeInTheDocument();
});
expect(screen.getByText(/FLEET 1\/2 ONLINE/i)).toBeInTheDocument();
expect(screen.getByText(/1 BUILD/i)).toBeInTheDocument();
});
});
describe('FleetTopologyMap', () => {
afterEach(() => cleanup());
it('renders canvas wrapper for agents', () => {
render();
expect(screen.getByTestId('three-canvas')).toBeInTheDocument();
});
});
describe('AmbientBackground', () => {
afterEach(() => cleanup());
it('renders ambient layers and sacred geometry svg', () => {
const { container } = render();
expect(container.querySelector('.ambient-bg')).toBeTruthy();
expect(container.querySelector('.ambient-sacred-geo')).toBeTruthy();
});
});
describe('CursorFire', () => {
afterEach(() => cleanup());
it('mounts fullscreen canvas', () => {
const { container } = render();
expect(container.querySelector('canvas')).toBeTruthy();
});
});
describe('MatrixRain', () => {
afterEach(() => cleanup());
beforeEach(() => {
useWebSocketMock.mockReturnValue({
isConnected: true,
agents: [],
recentShares: [],
fleetAlerts: [],
poolStatus: [],
aiActivity: [],
agentLogs: {},
commandResults: [],
latestMessage: null,
});
});
it('renders matrix rain canvas wrapper', () => {
const { container } = render();
expect(container.querySelector('canvas')).toBeTruthy();
});
});
describe('Layout', () => {
afterEach(() => cleanup());
beforeEach(() => {
useWebSocketMock.mockReturnValue({
isConnected: true,
agents: [mockAgent()],
recentShares: [],
fleetAlerts: [],
poolStatus: [],
aiActivity: [],
agentLogs: {},
commandResults: [],
latestMessage: null,
});
vi.spyOn(api, 'getServerInfo').mockResolvedValue(mockServerInfo);
});
it('renders nav links and children', async () => {
render(
page body
);
await waitFor(() => {
expect(screen.getByText('page body')).toBeInTheDocument();
});
expect(screen.getByRole('link', { name: /Command Deck/i })).toBeInTheDocument();
expect(screen.getByRole('link', { name: /Fleet Roster/i })).toBeInTheDocument();
});
});