Files
iofficeai--aionui/tests/e2e/specs/agent-settings-detection.e2e.ts
2026-07-13 13:20:22 +08:00

114 lines
4.8 KiB
TypeScript

/**
* Agent Settings Detection — diagnostics-only E2E tests.
*
* Phase 2 turns Agent Settings into a management/diagnostics surface rather
* than a business-facing picker. These tests lock the page to that contract:
* - sections come from `/api/agents/management`
* - official/custom buckets stay visible
* - a troubleshoot/repair affordance exists per agent
* - legacy market/chat/preset affordances do not reappear
*/
import { test, expect } from '../fixtures';
import { goToSettings, expectUrlContains, settingsSiderItemById, httpGet } from '../helpers';
type ManagedAgent = {
id: string;
name: string;
agent_type?: string;
backend?: string;
agent_source: 'internal' | 'builtin' | 'extension' | 'custom';
status?: 'online' | 'offline' | 'missing';
};
const DEPRECATED_RUNTIME_AGENT_TYPES = new Set(['nanobot', 'openclaw-gateway', 'remote', 'gemini']);
const TEXT = {
customAgents: ['Custom Agents', '自定义 Agents'],
setupGuide: ['Setup guide', '查看安装指南'],
// The custom-agent editor is now opened from an "Add" button in the
// custom-agents section header (was a "Detect Custom Agent" text link).
addCustomAgent: ['Add', '添加'],
testConnection: ['Test Connection', '测试连接'],
commandLabel: ['Command', '命令'],
commandPlaceholder: ['e.g. my-agent or /usr/local/bin/my-agent', '例如 my-agent 或 /usr/local/bin/my-agent'],
installFromMarket: ['Install from Market', '从市场安装'],
discoverMoreAgents: ['Discover More Agents', '发现更多 Agent'],
startChat: ['Start Chat', '开始对话'],
} as const;
async function expectAnyText(page: Parameters<typeof test>[0]['page'], candidates: readonly string[]) {
await expect
.poll(async () => {
const body = await page.locator('body').textContent();
return candidates.some((candidate) => body?.includes(candidate));
})
.toBeTruthy();
}
async function expectNoText(page: Parameters<typeof test>[0]['page'], candidates: readonly string[]) {
const body = (await page.locator('body').textContent()) ?? '';
for (const candidate of candidates) {
expect(body).not.toContain(candidate);
}
}
test.describe('Agent Settings Detection', () => {
test('renders the management catalog buckets and mirrors diagnostics rows', async ({ page }) => {
const managedAgents = await httpGet<ManagedAgent[]>(page, '/api/agents/management');
await goToSettings(page, 'agent');
await expectUrlContains(page, 'agent');
await expect(page.locator(settingsSiderItemById('agent')).first()).toBeVisible({ timeout: 8_000 });
await expect(page.locator('[data-testid="agent-management-page"]')).toBeVisible({ timeout: 8_000 });
await expect(page.locator('[data-testid="agent-management-custom-section"]')).toBeVisible({ timeout: 8_000 });
await expectAnyText(page, TEXT.customAgents);
await expectAnyText(page, TEXT.setupGuide);
const visibleManagedAgents = managedAgents.filter(
(agent) =>
agent.agent_source === 'custom' || !DEPRECATED_RUNTIME_AGENT_TYPES.has(agent.agent_type ?? agent.backend ?? '')
);
for (const agent of visibleManagedAgents.slice(0, 4)) {
await expect(page.locator(`[data-testid="agent-row-${agent.id}"]`)).toBeVisible({ timeout: 8_000 });
await expect(page.locator(`[data-testid="agent-row-status-${agent.id}"]`)).toBeVisible({ timeout: 8_000 });
await expect(page.locator(`[data-testid="agent-row-test-${agent.id}"]`)).toBeVisible({ timeout: 8_000 });
}
});
test('keeps the page diagnostics-only and removes legacy market/chat affordances', async ({ page }) => {
await goToSettings(page, 'agent');
await expectAnyText(page, TEXT.customAgents);
await expectNoText(page, TEXT.installFromMarket);
await expectNoText(page, TEXT.discoverMoreAgents);
await expectNoText(page, TEXT.startChat);
});
test('opens the custom agent editor from the diagnostics page', async ({ page }) => {
await goToSettings(page, 'agent');
await page.getByRole('button', { name: new RegExp(`^(${TEXT.addCustomAgent.join('|')})$`) }).click();
await expectAnyText(page, TEXT.commandLabel);
await expect(page.getByPlaceholder(new RegExp(TEXT.commandPlaceholder.join('|'))).first()).toBeVisible({
timeout: 8_000,
});
await page.getByRole('button', { name: /Cancel|取消/ }).click();
await expect(page.getByPlaceholder(new RegExp(TEXT.commandPlaceholder.join('|')))).toHaveCount(0);
});
test('re-entering the page keeps the diagnostics surface instead of legacy picker content', async ({ page }) => {
await goToSettings(page, 'agent');
await goToSettings(page, 'about');
await goToSettings(page, 'agent');
await expectAnyText(page, TEXT.customAgents);
await expectAnyText(page, TEXT.setupGuide);
await expectNoText(page, TEXT.installFromMarket);
await expectNoText(page, TEXT.discoverMoreAgents);
});
});