Files
DeskClaw/tests/e2e/channels-health-diagnostics.spec.ts
2026-04-17 19:13:31 +08:00

168 lines
5.5 KiB
TypeScript

import { completeSetup, expect, test } from './fixtures/electron';
test.describe('Channels health diagnostics', () => {
test('shows degraded banner, restarts gateway, and copies diagnostics', async ({ electronApp, page }) => {
await electronApp.evaluate(({ ipcMain }) => {
const state = {
restartCount: 0,
diagnosticsCount: 0,
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(globalThis as any).__clawxE2eChannelHealth = state;
ipcMain.removeHandler('hostapi:fetch');
ipcMain.handle('hostapi:fetch', async (_event, request: { path?: string; method?: string }) => {
const method = request?.method ?? 'GET';
const path = request?.path ?? '';
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const current = (globalThis as any).__clawxE2eChannelHealth as typeof state;
if (path === '/api/channels/accounts' && method === 'GET') {
return {
ok: true,
data: {
status: 200,
ok: true,
json: {
success: true,
gatewayHealth: {
state: 'degraded',
reasons: ['channels_status_timeout'],
consecutiveHeartbeatMisses: 1,
},
channels: [
{
channelType: 'feishu',
defaultAccountId: 'default',
status: 'degraded',
statusReason: 'channels_status_timeout',
accounts: [
{
accountId: 'default',
name: 'Primary Account',
configured: true,
status: 'degraded',
statusReason: 'channels_status_timeout',
isDefault: true,
},
],
},
],
},
},
};
}
if (path === '/api/gateway/status' && method === 'GET') {
return {
ok: true,
data: {
status: 200,
ok: true,
json: { state: 'running', port: 18789 },
},
};
}
if (path === '/api/agents' && method === 'GET') {
return {
ok: true,
data: {
status: 200,
ok: true,
json: { success: true, agents: [] },
},
};
}
if (path === '/api/gateway/restart' && method === 'POST') {
current.restartCount += 1;
return {
ok: true,
data: {
status: 200,
ok: true,
json: { success: true },
},
};
}
if (path === '/api/diagnostics/gateway-snapshot' && method === 'GET') {
current.diagnosticsCount += 1;
return {
ok: true,
data: {
status: 200,
ok: true,
json: {
capturedAt: 123,
platform: 'darwin',
gateway: {
state: 'degraded',
reasons: ['channels_status_timeout'],
consecutiveHeartbeatMisses: 1,
},
channels: [],
clawxLogTail: 'clawx-log',
gatewayLogTail: 'gateway-log',
gatewayErrLogTail: '',
},
},
};
}
return {
ok: false,
error: { message: `Unexpected hostapi:fetch request: ${method} ${path}` },
};
});
});
await completeSetup(page);
await page.evaluate(() => {
Object.defineProperty(navigator, 'clipboard', {
value: {
writeText: (value: string) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(window as any).__copiedDiagnostics = value;
return Promise.resolve();
},
},
configurable: true,
});
});
await page.getByTestId('sidebar-nav-channels').click();
await expect(page.getByTestId('channels-page')).toBeVisible();
await expect(page.getByTestId('channels-health-banner')).toBeVisible();
await expect(page.getByText(/Gateway degraded|网关状态异常|ゲートウェイ劣化/)).toBeVisible();
await expect(page.locator('div.rounded-2xl').getByText(/Degraded|异常降级|劣化中/).first()).toBeVisible();
await page.getByTestId('channels-restart-gateway').click();
await page.getByTestId('channels-copy-diagnostics').click();
await page.getByTestId('channels-toggle-diagnostics').click();
await expect(page.getByTestId('channels-diagnostics')).toBeVisible();
const result = await electronApp.evaluate(() => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const state = (globalThis as any).__clawxE2eChannelHealth as { restartCount: number; diagnosticsCount: number };
return {
restartCount: state.restartCount,
diagnosticsCount: state.diagnosticsCount,
};
});
expect(result.restartCount).toBe(1);
expect(result.diagnosticsCount).toBeGreaterThanOrEqual(1);
const copied = await page.evaluate(() => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return (window as any).__copiedDiagnostics as string;
});
expect(copied).toContain('"platform": "darwin"');
});
});