// @vitest-environment jsdom import { cleanup, fireEvent, render, screen, within } from '@testing-library/react'; import { afterEach, describe, expect, it, vi } from 'vitest'; import { FleetPage, type FleetSnapshot } from './fleet-page.js'; const snapshot: FleetSnapshot = { instances: [ { id: 'alpha', name: 'Alpha modem', url: 'http://192.168.1.2', tags: [], revision: 3, }, ], statuses: new Map([ [ 'alpha', { reachable: true, authenticated: true, summary: { freshness: 'fresh', resources: { cpuPercent: 24, memoryPercent: 51 } }, }, ], ]), }; afterEach(cleanup); describe('FleetPage card navigation', () => { it('makes the whole instance card open its dashboard while admin controls stay separately interactive', () => { render(); const card = screen.getByRole('article', { name: 'Alpha modem 实例概览' }); const entry = within(card).getByRole('link', { name: '打开 Alpha modem 实例仪表盘' }); expect(entry.getAttribute('href')).toBe('/instances/alpha/overview'); expect(entry.classList.contains('fleet-card-entry')).toBe(true); expect(within(card).getByRole('link', { name: '编辑 Alpha modem' })).toBeTruthy(); expect(within(card).getByRole('button', { name: '删除 Alpha modem' })).toBeTruthy(); expect(within(card).queryByRole('link', { name: /查看.*短信/ })).toBeNull(); expect(screen.getByRole('region', { name: '实例状态摘要' }).textContent).toMatch( /实例总数\s*1.*在线\s*1.*需处理\s*0/s, ); expect(within(card).getByRole('meter', { name: 'CPU 使用率' }).getAttribute('value')).toBe( '24', ); expect(within(card).getByRole('meter', { name: '内存使用率' }).getAttribute('value')).toBe( '51', ); expect(within(card).getByText('进入仪表盘')).toBeTruthy(); expect(within(card).getByRole('group', { name: '实例管理操作' })).toBeTruthy(); }); }); describe('FleetPage search and filter toolbar', () => { it('filters by status chips and clears active search conditions', () => { render(); const search = screen.getByRole('search', { name: '实例搜索与筛选' }); expect(within(search).getByPlaceholderText('搜索名称、ID、标签、源地址…')).toBeTruthy(); expect(within(search).getByText(/显示/).textContent).toMatch(/显示\s*1\s*\/\s*1/); fireEvent.click(within(search).getByRole('button', { name: /离线/ })); expect(screen.queryByRole('article', { name: 'Alpha modem 实例概览' })).toBeNull(); expect(within(search).getByText(/显示/).textContent).toMatch(/显示\s*0\s*\/\s*1/); expect(within(search).getByRole('button', { name: /移除筛选 状态:离线/ })).toBeTruthy(); fireEvent.change(within(search).getByPlaceholderText('搜索名称、ID、标签、源地址…'), { target: { value: 'Alpha' }, }); expect(within(search).getByRole('button', { name: /移除筛选 搜索:Alpha/ })).toBeTruthy(); fireEvent.click(within(search).getByRole('button', { name: '清除全部筛选' })); expect(screen.getByRole('article', { name: 'Alpha modem 实例概览' })).toBeTruthy(); expect(within(search).getByText(/显示/).textContent).toMatch(/显示\s*1\s*\/\s*1/); }); }); describe('FleetPage batch and restart actions', () => { it('exposes card restart controls and batch restart entry for selected instances', async () => { const prepare = vi.fn(async () => ({ id: 'prep-1', status: 'prepared', operationId: 'postServiceRestart', risk: 'R3', expiresAt: '2030-01-01T00:00:00.000Z', confirmationPrompt: 'Confirm restart', targetCount: 1, })); const execute = vi.fn(async () => ({ id: 'job-1', operationId: 'postServiceRestart', status: 'succeeded', rootJobId: 'job-1', items: [{ id: 'item-1', targetId: 'alpha', state: 'succeeded' }], attempts: [], createdAt: '2029-01-01T00:00:00.000Z', })); const list = vi.fn(async () => ({ items: [ { operationId: 'postServiceRestart', title: 'Restart Service', risk: 'R3', capability: 'job', batchable: false, parameterSchemaId: 'simadmin.58e2204.postServiceRestart.parameters.v1', }, { operationId: 'postSystemReboot', title: 'Reboot System', risk: 'R3', capability: 'job', batchable: false, parameterSchemaId: 'simadmin.58e2204.postSystemReboot.parameters.v1', }, ], page: { page: 1, pageSize: 100, total: 2 }, })); vi.stubGlobal('confirm', () => true); render( , ); const card = screen.getByRole('article', { name: 'Alpha modem 实例概览' }); expect(within(card).getByRole('button', { name: '重启服务 Alpha modem' })).toBeTruthy(); expect(within(card).getByRole('button', { name: '系统重启 Alpha modem' })).toBeTruthy(); fireEvent.click(within(card).getByRole('checkbox', { name: '选择 Alpha modem' })); expect(screen.getByText(/已选择 1 项/).textContent).toMatch(/已选择 1 项/); fireEvent.click(screen.getByRole('button', { name: '批量操作' })); const batch = await screen.findByRole('region', { name: '批量操作入口' }); expect(batch.textContent).toMatch(/已选择 1 项/); fireEvent.click(screen.getByRole('button', { name: '批量重启服务' })); await vi.waitFor(() => expect(prepare).toHaveBeenCalled()); expect(execute).toHaveBeenCalledWith('prep-1'); }); });