// @vitest-environment jsdom import { cleanup, render, screen, within } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { afterEach, describe, expect, it, vi } from 'vitest'; import { AppShell, type InstanceContext } from '../app-shell.js'; import { SensitiveRevealProvider } from '../privacy/sensitive-reveal.js'; import { OverviewSystemPage, type OverviewDataSource, type OverviewSnapshot, } from './overview-system.js'; import type { InstanceCapabilityMap } from './instance-detail.js'; afterEach(cleanup); const owner: InstanceContext = { id: 'alpha', name: 'Alpha', origin: 'https://alpha.example', status: 'online', authentication: 'authenticated', freshness: 'fresh', resources: { cpuPercent: 18.4, memoryPercent: 63.2, maxTemperatureCelsius: 46.7, phoneNumbers: ['13800138000'], }, }; const overviewCapabilities: InstanceCapabilityMap = { overview: { state: 'supported' }, }; const snapshot: OverviewSnapshot = { observedAt: '2026-07-17T10:00:00Z', device: { Model: 'SIMBox 8', Uptime: '2 days' }, sim: { Slots: 8, Active: 6 }, network: { Operator: 'Example Mobile', Registration: 'registered' }, stats: { 'Messages today': 42, Calls: 7 }, cpu: { Usage: '18%', Temperature: '46 °C' }, connectivity: { State: 'connected', Latency: '21 ms' }, }; function deferredSource() { let resolve!: (value: OverviewSnapshot) => void; let reject!: (reason: unknown) => void; const load = vi.fn( (_instanceId, _signal) => new Promise((done, fail) => { void _instanceId; void _signal; resolve = done; reject = fail; }), ); return { source: { load }, load, resolve: (value: OverviewSnapshot) => resolve(value), reject: (reason: unknown) => reject(reason), }; } describe('Phase 6.1 Overview / System read slice', () => { it('loads only through an injected source and renders six structured sections', async () => { const pending = deferredSource(); render( , ); expect(screen.getByRole('status', { name: '概览加载状态' }).textContent).toContain( '正在加载概览', ); expect(pending.load).toHaveBeenCalledWith('alpha', expect.any(AbortSignal)); pending.resolve(snapshot); for (const heading of ['设备', 'SIM', '网络', '统计', 'CPU', '连接状态']) { expect(await screen.findByRole('heading', { name: heading })).toBeTruthy(); } expect(within(screen.getByRole('region', { name: '设备' })).getByText('SIMBox 8')).toBeTruthy(); expect(screen.getByText(/观测时间:2026-07-17T10:00:00Z/)).toBeTruthy(); expect(screen.getByRole('button', { name: '重启服务' })).toBeTruthy(); expect(screen.getByRole('button', { name: '系统重启' })).toBeTruthy(); expect(screen.getByText(/服务重启与系统重启均为高风险操作/i)).toBeTruthy(); }); it('translates only known field names and values while preserving unknown safe data', async () => { render( ({ ...snapshot, device: { Model: 'SIMBox 8', Enabled: true, Mystery: 'vendor-value' }, network: { Registration: 'registered' }, connectivity: { State: 'connected' }, }), }} />, ); const device = await screen.findByRole('region', { name: '设备' }); expect(within(device).getByText('型号')).toBeTruthy(); expect(within(device).getByText('Enabled')).toBeTruthy(); expect(within(device).getByText('是')).toBeTruthy(); expect(within(device).getByText('Mystery')).toBeTruthy(); expect(within(device).getByText('vendor-value')).toBeTruthy(); expect(within(screen.getByRole('region', { name: '网络' })).getByText('已注册')).toBeTruthy(); expect( within(screen.getByRole('region', { name: '连接状态' })).getByText('已连接'), ).toBeTruthy(); }); it('renders the route-owned Fleet resource summary without inventing another endpoint', () => { render( , , ); const operations = screen.getByRole('region', { name: '运行状态与资源' }); expect(within(operations).getByText('在线')).toBeTruthy(); expect(within(operations).getByRole('meter', { name: 'CPU使用率' }).getAttribute('value')).toBe( '18.4', ); expect( within(operations).getByRole('meter', { name: '内存使用率' }).getAttribute('value'), ).toBe('63.2'); expect(within(operations).getByText('46.7 °C')).toBeTruthy(); expect(within(operations).getByText('138 •••• 8000')).toBeTruthy(); expect(within(operations).queryByText('13800138000')).toBeNull(); expect(screen.queryByText(/没有可用的安全概览只读数据源/i)).toBeNull(); expect(screen.getByRole('button', { name: '重启服务' })).toBeTruthy(); expect(screen.getByRole('button', { name: '系统重启' })).toBeTruthy(); }); it('reveals the overview phone number through the console-wide switch', async () => { const user = userEvent.setup(); render( , ); const operations = screen.getByRole('region', { name: '运行状态与资源' }); expect(within(operations).getByText('138 •••• 8000')).toBeTruthy(); await user.click(screen.getByRole('button', { name: '显示敏感标识' })); expect(within(operations).getByText('13800138000')).toBeTruthy(); expect(within(operations).queryByText('138 •••• 8000')).toBeNull(); }); it('shows authentication-required without loading or leaking prior owner data', async () => { const load = vi.fn().mockResolvedValue(snapshot); const { rerender } = render(); expect(await screen.findByText('SIMBox 8')).toBeTruthy(); rerender( , ); expect(screen.getByRole('alert').textContent).toMatch(/需要先完成认证/i); expect(screen.queryByText('SIMBox 8')).toBeNull(); expect(load).toHaveBeenCalledTimes(1); }); it('marks injected data stale from owner context while retaining structured values', async () => { render( snapshot }} />, ); expect((await screen.findByRole('status', { name: '概览数据新鲜度' })).textContent).toMatch( /可能已过期/i, ); expect(screen.getByText('SIMBox 8')).toBeTruthy(); }); it('surfaces read errors and supports a real injected retry', async () => { const user = userEvent.setup(); const load = vi .fn() .mockRejectedValueOnce(new Error('collector unavailable')) .mockResolvedValueOnce(snapshot); render(); expect((await screen.findByRole('alert')).textContent).toContain('无法加载概览数据。'); await user.click(screen.getByRole('button', { name: '重试加载概览' })); expect(await screen.findByText('SIMBox 8')).toBeTruthy(); expect(load).toHaveBeenCalledTimes(2); }); it('aborts old reads, fences late owners, and reloads on refreshSignal', async () => { const alpha = deferredSource(); const bravo = deferredSource(); const load = vi.fn((instanceId, signal) => instanceId === 'alpha' ? alpha.source.load(instanceId, signal) : bravo.source.load(instanceId, signal), ); const source = { load }; const { rerender } = render( , ); const alphaSignal = load.mock.calls[0]?.[1]; rerender( , ); expect(alphaSignal?.aborted).toBe(true); alpha.resolve({ ...snapshot, device: { Model: 'Alpha stale' } }); bravo.resolve({ ...snapshot, device: { Model: 'Bravo current' } }); expect(await screen.findByText('Bravo current')).toBeTruthy(); expect(screen.queryByText('Alpha stale')).toBeNull(); rerender( , ); expect(load).toHaveBeenCalledTimes(3); }); it('keeps unsupported capability explicit and does not invoke the overview source', () => { const load = vi.fn(); render( , ); expect(screen.getAllByText('No overview read support').length).toBeGreaterThan(0); expect(load).not.toHaveBeenCalled(); }); });