Restore Agent workspace and add platform pixel avatars

This commit is contained in:
鲨鱼辣椒 committed 2026-10-12 17:05:24 +08:00
1 parent 7a7d1f7fd8
commit c14d996c05
22 files changed
+1387 -462

No files matched your search

+215 -140
View File
@@ -1,19 +1,24 @@
import { closeElectronApp, expect, getStableWindow, test } from './fixtures/electron';
test('personal cloud Agent creation, draft save and leave protection in Electron', async ({ launchElectronApp }, testInfo) => {
test('personal cloud Agent identity, configuration and separate published chat in Electron', async ({ launchElectronApp }, testInfo) => {
const app = await launchElectronApp({ skipSetup: true });
const avatar = {
icon: '/uploads/avatars/writing-partner.png',
icon_url: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAwMCAO+ip1sAAAAASUVORK5CYII=',
};
try {
const page = await getStableWindow(app);
await expect(page.getByTestId('ai-module-selection-page')).toBeVisible();
const applicationUrl = page.url();
await page.goto('about:blank');
// This UI test owns the Host API boundary; real cloud HTTP/PG is tested separately.
await app.evaluate(({ ipcMain, BrowserWindow }) => {
await app.evaluate(({ ipcMain, BrowserWindow }, uploadedAvatar) => {
BrowserWindow.getAllWindows()[0].setSize(1366, 768);
let draft: Record<string, unknown> | null = null;
let avatarUploads = 0;
const iconUrl = (icon: unknown) => icon ? 'https://avatars.example.test' + icon : null;
let recent: unknown = null;
let createInput: Record<string, unknown> | null = null;
const operations: string[] = [];
Reflect.set(globalThis, '__cloudAgentUiFixture', { snapshot: () => ({ draft, createInput, operations }) });
const versions: { version: number; draft_revision: number; created_at: string }[] = [];
let knowledgeCatalogLoads = 0;
let knowledgeCreated = false;
@@ -40,10 +45,7 @@ test('personal cloud Agent creation, draft save and leave protection in Electron
});
if (path.startsWith('/api/cloud-agents/')) {
const body = typeof request.body === 'string' ? JSON.parse(request.body) : request.body ?? {};
if (path.endsWith('/avatars/pick')) {
const icon = `/api/storage/public/images/avatar-${++avatarUploads}.png`;
return result({ icon, icon_url: iconUrl(icon) });
}
if (path.endsWith('/avatars/pick')) return result(uploadedAvatar);
if (path.endsWith('/knowledge/pick')) {
knowledgeUploaded = true;
return result({ ...knowledgeFile, status: 'uploaded', chunk_count: 0, available: false, processing_task: null });
@@ -51,8 +53,13 @@ test('personal cloud Agent creation, draft save and leave protection in Electron
if (path.endsWith('/recovery')) return result({ recent, pending: [] });
if (path.endsWith('/recovery/recent')) { recent = body; return result({ saved: true }); }
if (path.endsWith('/actions')) {
operations.push(body.operation);
const input = body.input ?? {};
if (body.operation === 'catalog') return result({ models: [{ id: 'test-model', name: '创作模型' }], resources: {}, pricing: null });
if (body.operation === 'catalog') return result({
models: [{ id: 'test-model', name: '创作模型', description: '模型说明不应显示在配置页' }, { id: 'reasoning-model', name: '思考模型' }],
resources: { tools: [{ key: 'fixture-tool', name: '资料整理工具' }], skills: [{ key: 'fixture-skill', name: '文章整理 Skill' }] },
pricing: { unit: '词元点数', usage_unit: '词元', unit_size: 1000, points_per_unit: '9.99', version: 1 },
});
if (body.operation === 'knowledge') return result({ databases: knowledgeCreated ? [{ kb_id: 'kb', name: '我的创作资料' }] : [], models: ++knowledgeCatalogLoads === 1 ? [] : [{ id: 'fixture:test-embedding', name: '资料向量模型', dimension: 1024 }] });
if (body.operation === 'createKnowledge') { knowledgeCreated = true; return result({ kb_id: 'kb', name: '我的创作资料' }); }
if (body.operation === 'processKnowledge') { knowledgeStage = 0; return result({ task_id: 'process-document' }); }
@@ -90,71 +97,124 @@ test('personal cloud Agent creation, draft save and leave protection in Electron
if (body.operation === 'files') return result({ files: [] });
throw new Error('Unexpected cloud fixture operation ' + body.operation);
}
if (method === 'POST') draft = {
if (method === 'POST') { createInput = body; draft = {
slug: 'ml-' + 'a'.repeat(32), name: body.name, purpose: body.purpose, system_prompt: body.purpose,
icon: body.icon ?? null, icon_url: iconUrl(body.icon),
icon: body.icon ?? null, icon_url: body.icon === uploadedAvatar.icon ? uploadedAvatar.icon_url : null,
draft_revision: 1, updated_at: '2026-09-10T00:00:00Z',
configuration, published_version: null, enabled: true,
};
if (method === 'PATCH') draft = { ...draft, name: body.name, purpose: body.purpose, icon: body.icon ?? null, icon_url: iconUrl(body.icon), system_prompt: body.system_prompt, configuration: body.configuration, draft_revision: Number(draft?.draft_revision ?? 1) + 1 };
}; }
if (method === 'PATCH') draft = { ...draft, name: body.name, purpose: body.purpose, system_prompt: body.system_prompt,
icon: body.icon ?? null, icon_url: body.icon === uploadedAvatar.icon ? uploadedAvatar.icon_url : null,
configuration: body.configuration, draft_revision: Number(draft?.draft_revision ?? 1) + 1 };
if (method === 'GET' && (path.endsWith('/agents') || path.endsWith('/bootstrap'))) return result({ agents: draft ? [draft] : [], next_cursor: null });
return result(draft);
}
return result({ success: true });
});
});
await page.route('https://avatars.example.test/**', route => route.fulfill({ contentType: 'image/png',
body: Buffer.from('iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAALUlEQVR4nGOssXrLQEvARFPTRy0YtWDUglELRi0YtWDUglELRi0YtWDUAioCAGYEAeMrBAV7AAAAAElFTkSuQmCC', 'base64') }));
}, avatar);
await page.goto(applicationUrl);
await page.getByTestId('ai-module-option-cloud_agents').click();
await expect(page.getByTestId('sidebar-cloud-agents-navigation')).toBeVisible();
await expect(page.getByTestId('sidebar-robot-navigation')).toHaveCount(0);
await page.getByRole('button', { name: '创建第一个智能体' }).click();
await page.screenshot({ path: testInfo.outputPath('cloud-agent-choose-purpose.png') });
await page.getByRole('button', { name: /故事搭档/ }).click();
await page.getByRole('button', { name: '先给我提示', exact: true }).click();
const fixtureState = () => app.evaluate(() => Reflect.get(globalThis, '__cloudAgentUiFixture').snapshot());
const messageOperations = async () => (await fixtureState()).operations.filter((operation: string) => operation === 'preview' || operation === 'submit');
await page.getByRole('button', { name: '创建我的第一个智能体', exact: true }).click();
await expect(page.getByRole('heading', { name: '创建智能体', exact: true })).toBeVisible();
await expect(page.getByLabel('名称', { exact: true })).toHaveValue('');
await expect(page.getByRole('textbox')).toHaveCount(1);
await expect(page.getByLabel('用途', { exact: true })).toHaveCount(0);
await expect(page.getByLabel('提示词', { exact: true })).toHaveCount(0);
await expect(page.getByLabel('模型', { exact: true })).toHaveCount(0);
await expect(page.getByRole('button', { name: /科学问答助手|故事搭档|英语陪练|整理小帮手|我自己想一个|先给我提示/ })).toHaveCount(0);
await expect(page.getByRole('button', { name: '上一步', exact: true })).toHaveCount(0);
await expect(page.getByRole('button', { name: '下一步', exact: true })).toBeDisabled();
await page.screenshot({ path: testInfo.outputPath('cloud-agent-create-empty-form.png') });
await page.getByLabel('名称', { exact: true }).fill('我的写作搭档');
await page.getByLabel('用途', { exact: true }).fill('整理灵感,把想法写成清晰的文章');
await page.getByRole('button', { name: '上传头像', exact: true }).click();
await expect(page.getByRole('img', { name: '我的写作搭档头像', exact: true })).toHaveAttribute('src', /avatar-1\.png$/);
await page.screenshot({ path: testInfo.outputPath('cloud-agent-create-requirements.png') });
await page.getByRole('button', { name: '下一步:试一试', exact: true }).click();
await expect(page.getByTestId('cloud-agent-editor')).toBeVisible();
await expect(page.getByRole('group', { name: '智能体头像' }).getByRole('img')).toHaveAttribute('src', /avatar-1\.png$/);
await page.getByRole('button', { name: '更换头像', exact: true }).click();
await expect(page.getByRole('group', { name: '智能体头像' }).getByRole('img')).toHaveAttribute('src', /avatar-2\.png$/);
await expect.poll(() => page.getByRole('group', { name: '智能体头像' }).getByRole('img').evaluate(el => (el as HTMLImageElement).naturalWidth)).toBe(32);
await page.getByLabel('特别要求').fill('使用简洁自然的中文。先理解我的目的,再协助梳理结构。');
await expect(page.getByRole('img', { name: '我的写作搭档头像', exact: true })).toHaveAttribute('src', avatar.icon_url);
await page.screenshot({ path: testInfo.outputPath('cloud-agent-create-identity.png') });
await page.getByRole('button', { name: '下一步', exact: true }).click();
const editor = page.getByTestId('cloud-agent-editor');
const workspaceNavigation = page.getByRole('navigation', { name: '智能体工作区' });
const configurationButton = workspaceNavigation.getByRole('button', { name: '配置', exact: true });
const chatButton = workspaceNavigation.getByRole('button', { name: '聊天', exact: true });
const instructionsTab = page.getByRole('tab', { name: '模型与提示词', exact: true });
const advancedTab = page.getByRole('tab', { name: '高级设置', exact: true });
const prompt = page.getByLabel('提示词', { exact: true });
const initialPrompt = '使用简洁自然的中文。先理解我的目的,再协助梳理结构。';
const revisedPrompt = initialPrompt + '补充具体例子。';
await expect(editor).toBeVisible();
await expect(page.getByTestId('titlebar-page-title')).toHaveText('智能体工作区');
await expect(page.getByLabel('名称', { exact: true })).toHaveValue('我的写作搭档');
await expect(page.getByRole('button', { name: '修改头像', exact: true }).getByRole('img')).toHaveAttribute('src', avatar.icon_url);
await expect(configurationButton).toHaveAttribute('aria-current', 'page');
await expect(prompt).toHaveValue('');
await expect(page.getByLabel('模型', { exact: true })).toHaveValue('test-model');
await expect(page.getByRole('button', { name: '先给我提示', exact: true })).toHaveAttribute('aria-pressed', 'true');
expect(await page.getByLabel('模型', { exact: true }).evaluate(el => Boolean(el.compareDocumentPosition(window.document.querySelector('textarea[aria-label="提示词"]')!) & Node.DOCUMENT_POSITION_FOLLOWING))).toBe(true);
await expect(page.getByLabel('用途', { exact: true })).toHaveCount(0);
await expect(page.getByLabel('特别要求')).toHaveCount(0);
await expect(page.getByText('模型说明不应显示在配置页', { exact: true })).toHaveCount(0);
await expect(page.getByText(/9\.99/)).toHaveCount(0);
await expect(page.getByRole('button', { name: /先给我提示|简单易懂|条理清楚|详细深入/ })).toHaveCount(0);
await expect(page.getByRole('region', { name: '草稿预览', exact: true })).toHaveCount(0);
await expect(page.getByRole('separator', { name: '调整配置与试用宽度' })).toHaveCount(0);
await expect(page.getByLabel('消息', { exact: true })).toHaveCount(0);
const created = await fixtureState();
expect(created.createInput).toMatchObject({ name: '我的写作搭档', icon: avatar.icon });
expect(created.createInput).not.toHaveProperty('icon_url');
expect(created.createInput.purpose).toBeTruthy();
expect(created.draft).toMatchObject({ name: '我的写作搭档', icon: avatar.icon, icon_url: avatar.icon_url, published_version: null });
expect(await messageOperations()).toEqual([]);
await page.getByRole('button', { name: '修改头像', exact: true }).click();
const avatarDialog = page.getByRole('dialog', { name: '修改头像', exact: true });
await expect(avatarDialog.getByRole('img', { name: '我的写作搭档头像', exact: true })).toHaveAttribute('src', avatar.icon_url);
await avatarDialog.getByRole('button', { name: '完成', exact: true }).click();
await prompt.fill(initialPrompt);
await page.getByLabel('模型', { exact: true }).selectOption('reasoning-model');
await page.getByTestId('sidebar-module-switcher-trigger').click();
await expect(page.getByRole('dialog', { name: '未保存的修改' })).toBeVisible();
await page.getByRole('button', { name: '继续编辑', exact: true }).click();
await page.getByRole('button', { name: '保存并开始试用', exact: true }).click();
await expect(page.getByRole('button', { name: '已保存', exact: true })).toBeVisible();
await expect(page.getByRole('group', { name: '智能体头像' }).getByRole('img')).toHaveAttribute('src', /avatar-2\.png$/);
await expect(page.getByTestId('titlebar-page-title')).toHaveText('智能体工作区');
const requirementsTab = page.getByRole('tab', { name: '我的要求', exact: true });
const advancedTab = page.getByRole('tab', { name: '高级设置', exact: true });
await expect(requirementsTab).toHaveAttribute('aria-selected', 'true');
await expect(prompt).toHaveValue(initialPrompt);
await expect(page.getByLabel('模型', { exact: true })).toHaveValue('reasoning-model');
await expect(instructionsTab).toHaveAttribute('aria-selected', 'true');
await expect(page.getByRole('navigation', { name: '配置分类' })).toHaveCount(0);
await requirementsTab.focus();
await requirementsTab.press('ArrowRight');
await instructionsTab.focus();
await instructionsTab.press('ArrowRight');
await expect(advancedTab).toBeFocused();
await expect(advancedTab).toHaveAttribute('aria-selected', 'true');
await expect(page.getByRole('tabpanel', { name: '高级设置' })).toBeVisible();
await expect(page.getByLabel('特别要求')).toBeHidden();
await expect(prompt).toBeHidden();
await expect(page.getByRole('button', { name: '能力', exact: true })).toHaveAttribute('aria-current', 'page');
await page.getByRole('button', { name: '选择工具', exact: true }).click();
await page.getByRole('checkbox', { name: '资料整理工具', exact: true }).check();
await page.getByRole('button', { name: '完成选择', exact: true }).click();
await page.getByText('管理我的云端能力', { exact: true }).click();
await page.getByRole('button', { name: '添加 MCP', exact: true }).click();
await page.getByLabel('连接名称', { exact: true }).fill('尚未保存的资料连接');
await page.getByLabel('连接地址', { exact: true }).fill('https://example.com/mcp');
await instructionsTab.click();
await expect(prompt).toHaveValue(initialPrompt);
await advancedTab.click();
await expect(advancedTab).toHaveAttribute('aria-selected', 'true');
await expect(page.getByLabel('连接名称', { exact: true })).toHaveValue('尚未保存的资料连接');
await expect(page.getByLabel('连接地址', { exact: true })).toHaveValue('https://example.com/mcp');
await expect(page.getByRole('checkbox', { name: '资料整理工具', exact: true })).toBeChecked();
await chatButton.click();
await expect(page.getByText('保存配置后,开始使用这个智能体。', { exact: true })).toBeVisible();
await expect(page.getByLabel('消息', { exact: true })).toHaveCount(0);
await configurationButton.click();
await expect(page.getByLabel('连接名称', { exact: true })).toHaveValue('尚未保存的资料连接');
await page.getByRole('button', { name: '返回能力列表', exact: true }).click();
await page.screenshot({ path: testInfo.outputPath('cloud-agent-advanced-tab.png') });
const configurationScroll = page.getByRole('tabpanel').locator('.agent-config-scroll');
await configurationScroll.evaluate(el => { el.scrollTop = el.scrollHeight; });
await expect.poll(() => configurationScroll.evaluate(el => el.scrollTop)).toBeGreaterThan(0);
await requirementsTab.click();
await instructionsTab.click();
await expect.poll(() => configurationScroll.evaluate(el => el.scrollTop)).toBe(0);
await expect(page.getByLabel('用途', { exact: true })).toBeInViewport();
await page.screenshot({ path: testInfo.outputPath('cloud-agent-requirements-tab.png') });
await expect(page.getByLabel('模型', { exact: true })).toBeInViewport();
await expect(prompt).toBeInViewport();
await page.screenshot({ path: testInfo.outputPath('cloud-agent-model-prompt-tab.png') });
await advancedTab.click();
await expect.poll(() => configurationScroll.evaluate(el => el.scrollTop)).toBe(0);
await page.getByRole('button', { name: '知识', exact: true }).click();
@@ -170,9 +230,9 @@ test('personal cloud Agent creation, draft save and leave protection in Electron
await expect(page.getByText(/Yuxi 后台/)).toContainText('服务地址和 API Key');
await expect(page.getByText(/Works Square 运营后台|one-api/)).toHaveCount(0);
await page.getByLabel('知识库名称', { exact: true }).fill('我的创作资料');
await requirementsTab.click();
await instructionsTab.click();
await expect(page.getByRole('navigation', { name: '配置分类' })).toHaveCount(0);
await expect(page.getByLabel('特别要求')).toHaveValue('使用简洁自然的中文。先理解我的目的,再协助梳理结构。');
await expect(prompt).toHaveValue(initialPrompt);
await advancedTab.click();
await expect(page.getByRole('button', { name: '知识', exact: true })).toHaveAttribute('aria-current', 'page');
await expect(page.getByLabel('知识库名称', { exact: true })).toHaveValue('我的创作资料');
@@ -197,99 +257,99 @@ test('personal cloud Agent creation, draft save and leave protection in Electron
await document.scrollIntoViewIfNeeded();
expect(await document.evaluate(el => el.scrollWidth - el.clientWidth)).toBeLessThanOrEqual(1);
await page.screenshot({ path: testInfo.outputPath('knowledge-ready.png') });
await page.getByRole('tab', { name: '我的要求', exact: true }).click();
const preview = page.getByRole('region', { name: '草稿预览', exact: true });
await preview.getByRole('button', { name: '保存并重新试用', exact: true }).click();
await expect(preview.getByText('当前试用 · 修订 3')).toBeVisible();
await preview.getByRole('button', { name: '你可以怎样帮助我?请举一个例子。', exact: true }).click();
await expect(preview.getByLabel('消息')).toHaveValue('你可以怎样帮助我?请举一个例子。');
await expect(preview.getByRole('heading', { name: '创作建议' })).toHaveCount(0);
await preview.getByLabel('消息').fill('先给我一些创作建议');
await preview.getByLabel('消息').press('Enter');
await expect(preview.getByRole('heading', { name: '创作建议' })).toBeAttached();
const composer = preview.getByTestId('cloud-chat-composer');
const beforeScroll = await composer.boundingBox();
await preview.getByTestId('cloud-chat-messages').evaluate(el => { el.scrollTop = 0; });
await expect.poll(async () => (await composer.boundingBox())?.y).toBe(beforeScroll?.y);
await expect.poll(() => page.getByTestId('main-content').evaluate(el => el.scrollHeight - el.clientHeight)).toBeLessThanOrEqual(1);
expect(beforeScroll!.y + beforeScroll!.height).toBeLessThanOrEqual(await page.evaluate(() => innerHeight));
await preview.getByLabel('消息').fill('保存后继续的问题');
await preview.getByLabel('消息').press('F6');
await expect(page.getByRole('region', { name: '草稿配置', exact: true }).getByRole('button', { name: '展开配置' })).toBeFocused();
await page.getByLabel('特别要求').fill('使用简洁自然的中文。先理解我的目的,再协助梳理结构。补充具体例子。');
await page.getByLabel('特别要求').press('Control+s');
await expect(page.getByText('云端已保存', { exact: true })).toBeVisible();
await expect(preview.getByLabel('消息')).toHaveValue('保存后继续的问题');
await expect(preview.getByRole('heading', { name: '创作建议' })).toBeAttached();
await expect(preview.getByText('当前试用 · 修订 3')).toBeVisible();
const divider = page.getByRole('separator', { name: '调整配置与试用宽度' });
await divider.focus();
const previousRatio = Number(await divider.getAttribute('aria-valuenow'));
await divider.press('ArrowRight');
await expect(divider).toHaveAttribute('aria-valuenow', String(previousRatio + 2));
const handle = await divider.boundingBox();
await page.mouse.move(handle!.x + 4, handle!.y + 80);
await page.mouse.down();
await page.mouse.move(handle!.x - 35, handle!.y + 80);
await page.mouse.up();
expect(Number(await divider.getAttribute('aria-valuenow'))).toBeLessThan(previousRatio + 2);
await page.getByRole('button', { name: '展开试用', exact: true }).click();
await expect(page.getByRole('region', { name: '草稿配置', exact: true })).toBeHidden();
await page.keyboard.press('Escape');
await expect(page.getByRole('region', { name: '草稿配置', exact: true })).toBeVisible();
await page.screenshot({ path: testInfo.outputPath('cloud-agent-editor.png') });
await app.evaluate(({ BrowserWindow }) => { const win = BrowserWindow.getAllWindows()[0]; win.setMinimumSize(800, 600); win.setSize(980, 680); });
await expect(divider).toBeHidden();
await page.getByRole('button', { name: '试用', exact: true }).click();
await expect(preview.getByLabel('消息')).toHaveValue('保存后继续的问题');
await expect.poll(async () => {
const bounds = await composer.boundingBox();
return bounds!.y + bounds!.height - await page.evaluate(() => innerHeight);
}).toBeLessThanOrEqual(0);
await page.screenshot({ path: testInfo.outputPath('cloud-agent-compact.png') });
await app.evaluate(({ BrowserWindow }) => BrowserWindow.getAllWindows()[0].setSize(1366, 768));
for (const factor of [1.25, 1.5]) {
await app.evaluate(({ BrowserWindow }, zoom) => BrowserWindow.getAllWindows()[0].webContents.setZoomFactor(zoom), factor);
if (await page.getByRole('button', { name: '试用', exact: true }).isVisible()) await page.getByRole('button', { name: '试用', exact: true }).click();
await expect.poll(async () => { const bounds = await composer.boundingBox(); return bounds!.y + bounds!.height - await page.evaluate(() => innerHeight); }).toBeLessThanOrEqual(0);
}
await app.evaluate(({ BrowserWindow }) => BrowserWindow.getAllWindows()[0].webContents.setZoomFactor(1));
await preview.getByRole('button', { name: '用最新草稿试用' }).click();
await expect(preview.getByText('当前试用 · 修订 4')).toBeVisible();
await expect(preview.getByLabel('消息')).toHaveValue('保存后继续的问题');
await preview.getByText('对比上一次试用 · 修订 3', { exact: true }).click();
await expect(preview.getByRole('heading', { name: '创作建议' })).toBeVisible();
await preview.getByText('对比上一次试用 · 修订 3', { exact: true }).click();
await page.getByRole('button', { name: '简单易懂', exact: true }).click();
await preview.getByRole('button', { name: '保存并重新试用', exact: true }).click();
await expect(preview.getByText('当前试用 · 修订 5')).toBeVisible();
await expect(preview.getByLabel('消息')).toHaveValue('保存后继续的问题');
await preview.getByLabel('消息').fill('');
await page.getByTestId('sidebar-module-switcher-trigger').click();
await expect(page.getByTestId('ai-module-selection-page')).toBeVisible();
await page.getByTestId('ai-module-option-cloud_agents').click();
await expect(page.getByTestId('cloud-agent-editor')).toBeVisible();
await expect(page.getByLabel('特别要求')).toHaveValue('使用简洁自然的中文。先理解我的目的,再协助梳理结构。补充具体例子。');
await page.getByRole('tab', { name: '高级设置', exact: true }).click();
await page.getByRole('button', { name: '限制', exact: true }).click();
await page.getByLabel('每次任务上限(词元点数)').fill('2.50');
await page.getByLabel('每日上限(词元点数)').fill('10.00');
await page.getByLabel('最多执行步数', { exact: true }).fill('60');
await advancedTab.focus();
await advancedTab.press('ArrowLeft');
await expect(requirementsTab).toBeFocused();
await expect(requirementsTab).toHaveAttribute('aria-selected', 'true');
await expect(instructionsTab).toBeFocused();
await expect(instructionsTab).toHaveAttribute('aria-selected', 'true');
await expect(page.getByLabel('每日上限(词元点数)')).toBeHidden();
await requirementsTab.press('ArrowRight');
await expect(prompt).toHaveValue(initialPrompt);
await instructionsTab.press('ArrowRight');
await expect(page.getByRole('button', { name: '限制', exact: true })).toHaveAttribute('aria-current', 'page');
await expect(page.getByLabel('每次任务上限(词元点数)')).toHaveValue('2.50');
await expect(page.getByLabel('每日上限(词元点数)')).toHaveValue('10.00');
await expect(page.getByLabel('最多执行步数', { exact: true })).toHaveValue('60');
await chatButton.click();
await configurationButton.click();
await expect(page.getByLabel('每日上限(词元点数)')).toHaveValue('10.00');
await page.getByRole('button', { name: '保存费用上限' }).click();
await expect(page.getByRole('button', { name: '保存费用上限' })).toBeDisabled();
await page.getByRole('button', { name: '使用与接入', exact: true }).click();
await instructionsTab.click();
await page.getByRole('button', { name: '保存草稿', exact: true }).click();
await expect(page.getByRole('button', { name: '已保存', exact: true })).toBeDisabled();
expect((await fixtureState()).draft).toMatchObject({
name: '我的写作搭档', icon: avatar.icon, icon_url: avatar.icon_url, system_prompt: initialPrompt, published_version: null,
configuration: { model: 'reasoning-model', tools: ['fixture-tool'], knowledges: ['kb'], max_execution_steps: 60 },
});
expect(await messageOperations()).toEqual([]);
await prompt.fill(revisedPrompt);
await prompt.press('Control+s');
await expect(page.getByText('云端已保存', { exact: true })).toBeVisible();
expect((await fixtureState()).draft.system_prompt).toBe(revisedPrompt);
expect(await messageOperations()).toEqual([]);
await page.getByTestId('sidebar-module-switcher-trigger').click();
await expect(page.getByTestId('ai-module-selection-page')).toBeVisible();
await page.getByTestId('ai-module-option-cloud_agents').click();
await expect(editor).toBeVisible();
await expect(configurationButton).toHaveAttribute('aria-current', 'page');
await expect(prompt).toHaveValue(revisedPrompt);
await expect(page.getByLabel('模型', { exact: true })).toHaveValue('reasoning-model');
await expect(page.getByRole('button', { name: '修改头像', exact: true }).getByRole('img')).toHaveAttribute('src', avatar.icon_url);
await app.evaluate(({ BrowserWindow }) => { const win = BrowserWindow.getAllWindows()[0]; win.setMinimumSize(800, 600); win.setSize(980, 680); });
await expect(prompt).toBeInViewport();
await expect(configurationButton).toBeInViewport();
await expect(page.getByRole('button', { name: '已保存', exact: true })).toBeInViewport();
await expect(page.getByRole('region', { name: '草稿预览', exact: true })).toHaveCount(0);
await expect(page.getByLabel('消息', { exact: true })).toHaveCount(0);
await expect.poll(() => editor.evaluate(el => el.scrollWidth - el.clientWidth)).toBeLessThanOrEqual(1);
await page.screenshot({ path: testInfo.outputPath('cloud-agent-config-compact.png') });
await app.evaluate(({ BrowserWindow }) => BrowserWindow.getAllWindows()[0].setSize(1366, 768));
for (const factor of [1.25, 1.5]) {
await app.evaluate(({ BrowserWindow }, zoom) => BrowserWindow.getAllWindows()[0].webContents.setZoomFactor(zoom), factor);
await expect(configurationButton).toBeInViewport();
await expect(page.getByLabel('模型', { exact: true })).toBeInViewport();
await expect(page.getByRole('button', { name: '已保存', exact: true })).toBeInViewport();
await expect.poll(() => editor.evaluate(el => el.scrollWidth - el.clientWidth)).toBeLessThanOrEqual(1);
}
await app.evaluate(({ BrowserWindow }) => BrowserWindow.getAllWindows()[0].webContents.setZoomFactor(1));
await page.screenshot({ path: testInfo.outputPath('cloud-agent-config.png') });
expect(await messageOperations()).toEqual([]);
await workspaceNavigation.getByRole('button', { name: '使用与接入', exact: true }).click();
await expect(page.getByLabel('应用名称')).toHaveCount(0);
await page.screenshot({ path: testInfo.outputPath('cloud-agent-start-private-use.png') });
await page.getByRole('button', { name: '确认开始使用' }).click();
await expect(page.getByRole('region', { name: '智能体对话', exact: true })).toBeVisible();
await expect(page.getByRole('region', { name: '智能体对话', exact: true }).getByRole('heading', { name: '创作建议' })).toHaveCount(0);
await page.getByRole('button', { name: '编辑', exact: true }).click();
await page.getByRole('button', { name: '确认开始使用', exact: true }).click();
const formalChat = page.getByRole('region', { name: '智能体对话', exact: true });
await expect(formalChat).toBeVisible();
await expect(chatButton).toHaveAttribute('aria-current', 'page');
await expect(prompt).toBeHidden();
await expect(formalChat.getByRole('heading', { name: '创作建议' })).toHaveCount(0);
expect((await fixtureState()).operations.filter((operation: string) => operation === 'publish')).toHaveLength(1);
expect(await messageOperations()).toEqual([]);
await formalChat.getByRole('button', { name: '你可以怎样帮助我?请举一个例子。', exact: true }).click();
await expect(formalChat.getByLabel('消息', { exact: true })).toHaveValue('你可以怎样帮助我?请举一个例子。');
expect(await messageOperations()).toEqual([]);
await formalChat.getByLabel('消息', { exact: true }).fill('先给我一些创作建议');
await formalChat.getByRole('button', { name: '发送', exact: true }).click();
await expect(formalChat.getByRole('heading', { name: '创作建议' })).toBeAttached();
expect(await messageOperations()).toEqual(['submit']);
const composer = formalChat.getByTestId('cloud-chat-composer');
const beforeScroll = await composer.boundingBox();
await formalChat.getByTestId('cloud-chat-messages').evaluate(el => { el.scrollTop = 0; });
await expect.poll(async () => (await composer.boundingBox())?.y).toBe(beforeScroll?.y);
await expect.poll(() => page.getByTestId('main-content').evaluate(el => el.scrollHeight - el.clientHeight)).toBeLessThanOrEqual(1);
expect(beforeScroll!.y + beforeScroll!.height).toBeLessThanOrEqual(await page.evaluate(() => innerHeight));
await formalChat.getByLabel('消息', { exact: true }).fill('保存后继续的问题');
await configurationButton.click();
await expect(prompt).toHaveValue(revisedPrompt);
await expect(formalChat).toBeHidden();
await expect(page.getByLabel('消息', { exact: true })).toBeHidden();
await expect(page.getByRole('region', { name: '草稿预览', exact: true })).toHaveCount(0);
await page.getByLabel('名称', { exact: true }).fill('我的新版写作搭档');
await expect(page.getByRole('button', { name: '应用最新修改', exact: true })).toBeDisabled();
await page.getByRole('button', { name: '保存草稿', exact: true }).click();
@@ -303,8 +363,24 @@ test('personal cloud Agent creation, draft save and leave protection in Electron
await applyButton.click();
await expect(page.getByRole('button', { name: '已应用', exact: true })).toBeDisabled();
await expect(page.getByText('修改已保存,尚未应用', { exact: true })).toHaveCount(0);
await chatButton.click();
await expect(formalChat.getByLabel('消息', { exact: true })).toHaveValue('保存后继续的问题');
await expect(formalChat.getByRole('heading', { name: '创作建议' })).toBeAttached();
expect(await messageOperations()).toEqual(['submit']);
await app.evaluate(({ BrowserWindow }) => BrowserWindow.getAllWindows()[0].setSize(980, 680));
await expect.poll(async () => {
const bounds = await composer.boundingBox();
return bounds!.y + bounds!.height - await page.evaluate(() => innerHeight);
}).toBeLessThanOrEqual(0);
await page.screenshot({ path: testInfo.outputPath('cloud-agent-chat-compact.png') });
await app.evaluate(({ BrowserWindow }) => BrowserWindow.getAllWindows()[0].setSize(1366, 768));
await page.getByRole('button', { name: '使用与接入', exact: true }).click();
for (const factor of [1.25, 1.5]) {
await app.evaluate(({ BrowserWindow }, zoom) => BrowserWindow.getAllWindows()[0].webContents.setZoomFactor(zoom), factor);
await expect.poll(async () => { const bounds = await composer.boundingBox(); return bounds!.y + bounds!.height - await page.evaluate(() => innerHeight); }).toBeLessThanOrEqual(0);
await expect(formalChat.getByLabel('消息', { exact: true })).toHaveValue('保存后继续的问题');
}
await app.evaluate(({ BrowserWindow }) => BrowserWindow.getAllWindows()[0].webContents.setZoomFactor(1));
await workspaceNavigation.getByRole('button', { name: '使用与接入', exact: true }).click();
await expect(page.getByRole('heading', { name: '应用与 API', exact: true })).toBeVisible();
await expect(page.getByRole('button', { name: '打开渠道', exact: true })).toBeVisible();
await expect(page.getByLabel('应用名称')).toBeVisible();
@@ -312,11 +388,15 @@ test('personal cloud Agent creation, draft save and leave protection in Electron
await expect(page.getByLabel('查找分享用户')).toHaveCount(0);
await expect(page.getByRole('button', { name: '复制分享链接', exact: true })).toHaveCount(0);
await page.screenshot({ path: testInfo.outputPath('cloud-agent-access-without-user-sharing.png') });
await page.getByRole('button', { name: '对话', exact: true }).click();
await page.getByRole('region', { name: '智能体对话', exact: true }).getByLabel('消息', { exact: true }).fill('每天早上八点半给我三个创作方向');
await page.getByRole('region', { name: '智能体对话', exact: true }).getByRole('button', { name: '发送', exact: true }).click();
await expect(page.getByRole('region', { name: '智能体对话', exact: true }).getByRole('heading', { name: '创作建议' })).toBeAttached();
await chatButton.click();
await expect(formalChat.getByLabel('消息', { exact: true })).toHaveValue('保存后继续的问题');
await formalChat.getByLabel('消息', { exact: true }).fill('每天早上八点半给我三个创作方向');
await formalChat.getByRole('button', { name: '发送', exact: true }).click();
await expect(formalChat.getByLabel('消息', { exact: true })).toHaveValue('');
await expect(formalChat.getByRole('heading', { name: '创作建议' })).toBeAttached();
expect(await messageOperations()).toEqual(['submit', 'submit']);
await page.getByRole('button', { name: '查看并配置自动任务' }).click();
await expect(workspaceNavigation.getByRole('button', { name: '自动任务', exact: true })).toHaveAttribute('aria-current', 'page');
await expect(page.getByLabel('任务名称')).toHaveValue('每天整理选题');
await expect(page.getByLabel('执行时间')).toHaveValue('08:30');
await expect(page.getByLabel('保存后启用')).not.toBeChecked();
@@ -329,12 +409,7 @@ test('personal cloud Agent creation, draft save and leave protection in Electron
await expect(page.getByLabel('保存后启用')).not.toBeChecked();
await page.getByRole('button', { name: '取消', exact: true }).click();
await page.screenshot({ path: testInfo.outputPath('cloud-agent-schedules.png') });
await page.getByRole('navigation', { name: '智能体工作区' }).getByRole('button', { name: '编辑', exact: true }).click();
await page.getByRole('tab', { name: '我的要求', exact: true }).click();
await page.getByRole('button', { name: '移除头像', exact: true }).click();
await page.getByRole('button', { name: '保存草稿', exact: true }).click();
await expect(page.getByRole('button', { name: '已保存', exact: true })).toBeVisible();
await expect(page.getByRole('group', { name: '智能体头像' }).getByRole('img', { name: '我的新版写作搭档默认头像' })).toBeVisible();
expect(await messageOperations()).toEqual(['submit', 'submit']);
} finally {
await app.evaluate(({ BrowserWindow }) => { for (const win of BrowserWindow.getAllWindows()) win.destroy(); }).catch(() => undefined);
await closeElectronApp(app);