feat: rebuild warm operations workbench
This commit is contained in:
@@ -20,7 +20,11 @@ const snapshot: FleetSnapshot = {
|
||||
{
|
||||
reachable: true,
|
||||
authenticated: true,
|
||||
summary: { freshness: 'fresh', resources: { cpuPercent: 24, memoryPercent: 51 } },
|
||||
summary: {
|
||||
version: '1.1.6',
|
||||
freshness: 'fresh',
|
||||
resources: { cpuPercent: 24, memoryPercent: 51, maxTemperatureCelsius: 42 },
|
||||
},
|
||||
},
|
||||
],
|
||||
]),
|
||||
@@ -43,16 +47,97 @@ describe('FleetPage card navigation', () => {
|
||||
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(screen.queryByRole('region', { name: '节点资源健康' })).toBeNull();
|
||||
expect(within(card).getByText('SimAdmin 1.1.6')).toBeTruthy();
|
||||
expect(
|
||||
within(card).getByRole('progressbar', { name: 'CPU 使用率' }).getAttribute('aria-valuenow'),
|
||||
).toBe('24');
|
||||
expect(
|
||||
within(card).getByRole('progressbar', { name: '内存使用率' }).getAttribute('aria-valuenow'),
|
||||
).toBe('51');
|
||||
expect(within(card).getByText('进入仪表盘')).toBeTruthy();
|
||||
expect(within(card).getByRole('group', { name: '实例运维操作' })).toBeTruthy();
|
||||
expect(within(card).getByRole('button', { name: '重启服务 Alpha modem' })).toBeTruthy();
|
||||
expect(within(card).getByRole('button', { name: '系统重启 Alpha modem' })).toBeTruthy();
|
||||
const nodeEntry = within(card).getByRole('link', { name: '打开 Alpha modem 节点入口' });
|
||||
expect(nodeEntry.getAttribute('href')).toBe('http://192.168.1.2');
|
||||
expect(nodeEntry.getAttribute('target')).toBe('_blank');
|
||||
expect(nodeEntry.getAttribute('rel')).toContain('noopener');
|
||||
expect(within(card).queryByRole('group', { name: '实例运维操作' })).toBeNull();
|
||||
expect(within(card).queryByRole('button', { name: '重启服务 Alpha modem' })).toBeNull();
|
||||
const actionTrigger = within(card).getByRole('button', { name: '实例操作 Alpha modem' });
|
||||
expect(actionTrigger.getAttribute('aria-expanded')).toBe('false');
|
||||
fireEvent.click(actionTrigger);
|
||||
expect(actionTrigger.getAttribute('aria-expanded')).toBe('true');
|
||||
expect(within(card).getByRole('menuitem', { name: '重启服务 Alpha modem' })).toBeTruthy();
|
||||
expect(within(card).getByRole('menuitem', { name: '系统重启 Alpha modem' })).toBeTruthy();
|
||||
|
||||
const metadata = card.querySelector('.fleet-card-metadata');
|
||||
const hardware = within(card).getByRole('group', { name: '节点硬件信息' });
|
||||
const telemetry = within(card).getByRole('region', { name: '资源遥测' });
|
||||
const footer = within(card).getByRole('region', { name: '短信状态' });
|
||||
expect(metadata).toBeTruthy();
|
||||
expect(
|
||||
Boolean(metadata!.compareDocumentPosition(hardware) & Node.DOCUMENT_POSITION_FOLLOWING),
|
||||
).toBe(true);
|
||||
expect(
|
||||
Boolean(hardware.compareDocumentPosition(telemetry) & Node.DOCUMENT_POSITION_FOLLOWING),
|
||||
).toBe(true);
|
||||
expect(
|
||||
Boolean(telemetry.compareDocumentPosition(footer) & Node.DOCUMENT_POSITION_FOLLOWING),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('shows an explicit fallback when the upstream SimAdmin version is unavailable', () => {
|
||||
const withoutVersion: FleetSnapshot = {
|
||||
...snapshot,
|
||||
statuses: new Map([
|
||||
[
|
||||
'alpha',
|
||||
{
|
||||
...snapshot.statuses.get('alpha')!,
|
||||
summary: {
|
||||
freshness: 'fresh',
|
||||
resources: { cpuPercent: 24, memoryPercent: 51 },
|
||||
},
|
||||
},
|
||||
],
|
||||
]),
|
||||
};
|
||||
|
||||
render(<FleetPage initialData={withoutVersion} />);
|
||||
|
||||
const card = screen.getByRole('article', { name: 'Alpha modem 实例概览' });
|
||||
expect(within(card).getByText('版本未知')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('supports the menu button keyboard model and dismisses the menu from outside', () => {
|
||||
render(<FleetPage initialData={snapshot} />);
|
||||
|
||||
const card = screen.getByRole('article', { name: 'Alpha modem 实例概览' });
|
||||
const trigger = within(card).getByRole('button', { name: '实例操作 Alpha modem' });
|
||||
|
||||
trigger.focus();
|
||||
fireEvent.keyDown(trigger, { key: 'ArrowDown' });
|
||||
|
||||
const serviceRestart = within(card).getByRole('menuitem', {
|
||||
name: '重启服务 Alpha modem',
|
||||
});
|
||||
const systemReboot = within(card).getByRole('menuitem', { name: '系统重启 Alpha modem' });
|
||||
expect(document.activeElement).toBe(serviceRestart);
|
||||
|
||||
fireEvent.keyDown(serviceRestart, { key: 'ArrowDown' });
|
||||
expect(document.activeElement).toBe(systemReboot);
|
||||
fireEvent.keyDown(systemReboot, { key: 'ArrowDown' });
|
||||
expect(document.activeElement).toBe(serviceRestart);
|
||||
fireEvent.keyDown(serviceRestart, { key: 'ArrowUp' });
|
||||
expect(document.activeElement).toBe(systemReboot);
|
||||
|
||||
fireEvent.keyDown(systemReboot, { key: 'Escape' });
|
||||
expect(within(card).queryByRole('menu')).toBeNull();
|
||||
expect(document.activeElement).toBe(trigger);
|
||||
|
||||
fireEvent.click(trigger);
|
||||
expect(within(card).getByRole('menu')).toBeTruthy();
|
||||
fireEvent.pointerDown(document.body);
|
||||
expect(within(card).queryByRole('menu')).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -78,9 +163,59 @@ describe('FleetPage search and filter toolbar', () => {
|
||||
expect(screen.getByRole('article', { name: 'Alpha modem 实例概览' })).toBeTruthy();
|
||||
expect(within(search).getByText(/显示/).textContent).toMatch(/显示\s*1\s*\/\s*1/);
|
||||
});
|
||||
|
||||
it('filters the matrix from the tag group row without moving search out of the sidebar', () => {
|
||||
const groupedSnapshot: FleetSnapshot = {
|
||||
instances: [
|
||||
{ ...snapshot.instances[0]!, tags: ['核心'] },
|
||||
{
|
||||
id: 'beta',
|
||||
name: 'Beta modem',
|
||||
url: 'http://192.168.1.3',
|
||||
tags: ['外场'],
|
||||
revision: 1,
|
||||
},
|
||||
],
|
||||
statuses: new Map([
|
||||
...snapshot.statuses,
|
||||
['beta', { reachable: false, authenticated: false }],
|
||||
]),
|
||||
};
|
||||
render(<FleetPage initialData={groupedSnapshot} />);
|
||||
|
||||
const groups = screen.getByRole('group', { name: '节点分组' });
|
||||
const betaCard = screen.getByRole('article', { name: 'Beta modem 实例概览' });
|
||||
expect(screen.queryByRole('region', { name: '节点资源健康' })).toBeNull();
|
||||
expect(within(betaCard).getAllByText('--')).toHaveLength(3);
|
||||
expect(within(groups).getByRole('button', { name: '全部节点' })).toBeTruthy();
|
||||
fireEvent.click(within(groups).getByRole('button', { name: '核心' }));
|
||||
|
||||
expect(screen.getByRole('article', { name: 'Alpha modem 实例概览' })).toBeTruthy();
|
||||
expect(screen.queryByRole('article', { name: 'Beta modem 实例概览' })).toBeNull();
|
||||
expect(
|
||||
screen
|
||||
.getByRole('search', { name: '实例搜索与筛选' })
|
||||
.closest('aside')
|
||||
?.classList.contains('fleet-sidebar'),
|
||||
).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('FleetPage batch and restart actions', () => {
|
||||
it('keeps selection controls hidden until batch-selection mode is entered', () => {
|
||||
render(<FleetPage initialData={snapshot} />);
|
||||
expect(screen.queryByRole('checkbox', { name: /选择 Alpha modem/ })).toBeNull();
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: '批量选择' }));
|
||||
const checkbox = screen.getByRole('checkbox', { name: /选择 Alpha modem/ });
|
||||
expect(checkbox).toBeTruthy();
|
||||
expect(checkbox.closest('.fleet-card-header-meta')).toBeTruthy();
|
||||
expect(screen.getByRole('button', { name: '全选本页' })).toBeTruthy();
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: '退出批量选择' }));
|
||||
expect(screen.queryByRole('checkbox', { name: /选择 Alpha modem/ })).toBeNull();
|
||||
});
|
||||
|
||||
it('exposes card restart controls and batch restart entry for selected instances', async () => {
|
||||
const prepare = vi.fn(async () => ({
|
||||
id: 'prep-1',
|
||||
@@ -123,17 +258,19 @@ describe('FleetPage batch and restart actions', () => {
|
||||
}));
|
||||
vi.stubGlobal('confirm', () => true);
|
||||
render(
|
||||
<FleetPage
|
||||
initialData={snapshot}
|
||||
operationClient={{ list, prepare, execute } as never}
|
||||
/>,
|
||||
<FleetPage initialData={snapshot} operationClient={{ list, prepare, execute } as never} />,
|
||||
);
|
||||
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();
|
||||
const cardMenuTrigger = within(card).getByRole('button', { name: '实例操作 Alpha modem' });
|
||||
expect(cardMenuTrigger.getAttribute('aria-expanded')).toBe('false');
|
||||
fireEvent.click(cardMenuTrigger);
|
||||
expect(within(card).getByRole('menuitem', { name: '重启服务 Alpha modem' })).toBeTruthy();
|
||||
expect(within(card).getByRole('menuitem', { name: '系统重启 Alpha modem' })).toBeTruthy();
|
||||
fireEvent.click(screen.getByRole('button', { name: '批量选择' }));
|
||||
fireEvent.click(within(card).getByRole('checkbox', { name: '选择 Alpha modem' }));
|
||||
expect(screen.getByText(/已选择 1 项/).textContent).toMatch(/已选择 1 项/);
|
||||
fireEvent.click(screen.getByRole('button', { name: '批量操作' }));
|
||||
expect(
|
||||
screen.getAllByText(/已选择 1 项/).some((node) => /已选择 1 项/.test(node.textContent ?? '')),
|
||||
).toBe(true);
|
||||
const batch = await screen.findByRole('region', { name: '批量操作入口' });
|
||||
expect(batch.textContent).toMatch(/已选择 1 项/);
|
||||
fireEvent.click(screen.getByRole('button', { name: '批量重启服务' }));
|
||||
|
||||
Reference in New Issue
Block a user