321 lines
27 KiB
TypeScript
321 lines
27 KiB
TypeScript
import { closeElectronApp, expect, getStableWindow, test } from './fixtures/electron';
|
||
|
||
test('personal cloud Agent creation, draft save and leave protection in Electron', async ({ launchElectronApp }, testInfo) => {
|
||
const app = await launchElectronApp({ skipSetup: true });
|
||
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 }) => {
|
||
BrowserWindow.getAllWindows()[0].setSize(1366, 768);
|
||
let draft: Record<string, unknown> | null = null;
|
||
let recent: unknown = null;
|
||
const versions: { version: number; draft_revision: number; created_at: string }[] = [];
|
||
let knowledgeCatalogLoads = 0;
|
||
let knowledgeCreated = false;
|
||
let knowledgeUploaded = false;
|
||
let knowledgeStage = -1;
|
||
const knowledgeFile = { file_id: 'document', name: '本体(Ontology)学习路线图.pdf', size: 34000, error: null };
|
||
let limits: { request_limit_points: string | null; daily_limit_points: string | null } = { request_limit_points: null, daily_limit_points: null };
|
||
const jobs: Record<string, unknown>[] = [];
|
||
const configuration = { model: '', tools: [], knowledges: [], mcps: [], skills: [], preload_skills: [], subagents: [], tool_approval_mode: 'default', max_execution_steps: 40, max_output_tokens: 4096, max_run_seconds: 600 };
|
||
const result = (json: unknown) => ({ ok: true, data: { status: 200, ok: true, json } });
|
||
ipcMain.removeHandler('hostapi:fetch');
|
||
ipcMain.handle('hostapi:fetch', async (_event, request: { path?: string; method?: string; body?: string }) => {
|
||
const path = request.path ?? '';
|
||
const method = request.method ?? 'GET';
|
||
if (path === '/api/auth/session/sync') return result({
|
||
success: true, session: { accessToken: 'ui-fixture', tokenType: 'Bearer', expiresAt: Date.now() + 3600000, lastActiveAt: Date.now(), canRefresh: false },
|
||
});
|
||
if (path === '/api/auth/me') return result({
|
||
success: true, user: { username: 'creator', userId: 'creator', tenantId: null, deptId: null, authorities: [] },
|
||
moduleAccess: { programming: true, design: true, robot: true, cloud_agents: true },
|
||
});
|
||
if (path === '/api/works/user/agent-profile') return result({
|
||
success: true, profile: { display_name: '创作者', age: null, gender: null, avatar_url: null, share_age_with_agents: false, share_gender_with_agents: false, analysis_enabled: true, completed: true, version: 1, updated_at: '2026-09-10T00:00:00Z' },
|
||
});
|
||
if (path.startsWith('/api/cloud-agents/')) {
|
||
const body = typeof request.body === 'string' ? JSON.parse(request.body) : request.body ?? {};
|
||
if (path.endsWith('/knowledge/pick')) {
|
||
knowledgeUploaded = true;
|
||
return result({ ...knowledgeFile, status: 'uploaded', chunk_count: 0, available: false, processing_task: null });
|
||
}
|
||
if (path.endsWith('/recovery')) return result({ recent, pending: [] });
|
||
if (path.endsWith('/recovery/recent')) { recent = body; return result({ saved: true }); }
|
||
if (path.endsWith('/actions')) {
|
||
const input = body.input ?? {};
|
||
if (body.operation === 'catalog') return result({ models: [{ id: 'test-model', name: '创作模型' }], resources: {}, pricing: null });
|
||
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' }); }
|
||
if (body.operation === 'knowledgeFiles') {
|
||
const stage = knowledgeStage;
|
||
if (knowledgeStage >= 0) knowledgeStage++;
|
||
return result({ next_offset: null, files: knowledgeUploaded ? [
|
||
{ ...knowledgeFile, status: stage < 1 ? 'uploaded' : stage === 1 ? 'parsing' : stage === 2 ? 'indexing' : 'indexed',
|
||
available: stage >= 3, chunk_count: stage >= 3 ? 18 : 0,
|
||
processing_task: stage < 0 ? null : { task_id: 'process-document', status: stage === 0 ? 'pending' : stage < 3 ? 'running' : 'success', error: null } },
|
||
{ file_id: 'empty', name: '扫描文档.pdf', size: 2000, status: 'indexed', available: false, chunk_count: 0, error: null },
|
||
] : [] });
|
||
}
|
||
if (body.operation === 'resources') return result({ mcps: [], skills: [], subagents: [] });
|
||
if (body.operation === 'budget' || body.operation === 'saveBudget') {
|
||
if (body.operation === 'saveBudget') limits = input;
|
||
return result({ agent_slug: draft?.slug, ...limits, daily_committed_points: '0.00', timezone: 'Asia/Shanghai', unit: '词元点数', resets_at: '2026-09-11T00:00:00+08:00' });
|
||
}
|
||
if (body.operation === 'scheduleContext') return result({ version: 1, enabled: true, configuration, result_destination: '任务历史对话与活动', payer: 'creator' });
|
||
if (body.operation === 'channelSelfCallers') return result({ items: [] });
|
||
if (body.operation === 'channelBindings') return result({ items: [], available_accounts: [] });
|
||
if (body.operation === 'threads') return result({ threads: [], next_offset: null });
|
||
if (body.operation === 'publish') { const version = versions.length + 1; if (draft) draft.published_version = version; versions.push({ version, draft_revision: input.expected_revision, created_at: new Date().toISOString() }); return result({ version, draft_revision: input.expected_revision }); }
|
||
if (body.operation === 'access') return result({ published_version: draft?.published_version, enabled: true, share_url: 'niancode://agents/' + draft?.slug, versions, grants: [], applications: [] });
|
||
if (body.operation === 'costs') return result({ items: [], next_offset: null, unit: '词元点数', summary: { count: 0, settled_points: '0.00', pending_points: '0.00' } });
|
||
if (body.operation === 'schedules') return result({ jobs });
|
||
if (body.operation === 'createSchedule') { const job = { ...input, id: 'job-1', agent_slug: draft?.slug, next_run_at: '2026-09-11T01:00:00Z', runs: [] }; jobs.push(job); return result(job); }
|
||
if (body.operation === 'submit' || body.operation === 'preview') return result({ request_id: input.request_id, thread_id: 'thread-1', run_id: 'run-1', version: '1', status: 'dispatched' });
|
||
if (body.operation === 'history') return result({ thread_id: 'thread-1', next_offset: null,
|
||
queued_requests: [], schedule_proposals: [{ id: 'proposal', name: '每天整理选题', prompt: '每天给我三个适合个人创作的选题', cron_expression: '30 8 * * *', timezone: 'Asia/Shanghai' }],
|
||
messages: [{ id: 1, role: 'assistant', content: '## 创作建议\n先从一个真实的观察开始。\n\n' + '记录今天的一次观察,把具体场景、你的感受和想分享的发现写下来。\n\n'.repeat(22) }],
|
||
run: { agent_run_id: 'run-1', request_id: 'request-1', thread_id: 'thread-1', status: 'completed', version: '1' } });
|
||
if (body.operation === 'viewed') return result({ viewed: true });
|
||
if (body.operation === 'attachments') return result({ attachments: [] });
|
||
if (body.operation === 'files') return result({ files: [] });
|
||
throw new Error('Unexpected cloud fixture operation ' + body.operation);
|
||
}
|
||
if (method === 'POST') draft = {
|
||
slug: 'ml-' + 'a'.repeat(32), name: body.name, purpose: body.purpose, system_prompt: body.purpose,
|
||
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, system_prompt: body.system_prompt, 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.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();
|
||
await page.getByLabel('名称', { exact: true }).fill('我的写作搭档');
|
||
await page.getByLabel('用途', { exact: true }).fill('整理灵感,把想法写成清晰的文章');
|
||
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 page.getByLabel('特别要求').fill('使用简洁自然的中文。先理解我的目的,再协助梳理结构。');
|
||
await expect(page.getByLabel('模型', { exact: true })).toHaveValue('test-model');
|
||
await expect(page.getByRole('button', { name: '先给我提示', exact: true })).toHaveAttribute('aria-pressed', 'true');
|
||
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.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(page.getByRole('navigation', { name: '配置分类' })).toHaveCount(0);
|
||
await requirementsTab.focus();
|
||
await requirementsTab.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(page.getByRole('button', { name: '能力', exact: true })).toHaveAttribute('aria-current', 'page');
|
||
await advancedTab.click();
|
||
await expect(advancedTab).toHaveAttribute('aria-selected', 'true');
|
||
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 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 advancedTab.click();
|
||
await expect.poll(() => configurationScroll.evaluate(el => el.scrollTop)).toBe(0);
|
||
await page.getByRole('button', { name: '知识', exact: true }).click();
|
||
await page.getByText('管理我的知识文档', { exact: true }).click();
|
||
const knowledgeDescription = page.getByText(/上传到知识库的文档可供/);
|
||
await expect(knowledgeDescription).toContainText('embedding 向量化由平台承担,不计入用户用量、词元点数或智能体费用上限');
|
||
await expect(knowledgeDescription).toContainText('知识处理如触发对话模型调用,仍按原模型实际用量计费');
|
||
await page.getByRole('button', { name: '新建知识库', exact: true }).click();
|
||
await expect(page.getByLabel('向量模型', { exact: true })).toBeDisabled();
|
||
await page.getByText('管理员配置说明', { exact: true }).click();
|
||
await expect(page.getByText(/Embedding 只在 Yuxi 配置/)).toBeVisible();
|
||
await expect(page.getByText(/Yuxi 后台/)).toContainText('智能体管理 → 模型供应商');
|
||
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 expect(page.getByRole('navigation', { name: '配置分类' })).toHaveCount(0);
|
||
await expect(page.getByLabel('特别要求')).toHaveValue('使用简洁自然的中文。先理解我的目的,再协助梳理结构。');
|
||
await advancedTab.click();
|
||
await expect(page.getByRole('button', { name: '知识', exact: true })).toHaveAttribute('aria-current', 'page');
|
||
await expect(page.getByLabel('知识库名称', { exact: true })).toHaveValue('我的创作资料');
|
||
await page.screenshot({ path: testInfo.outputPath('knowledge-empty.png') });
|
||
await page.getByRole('button', { name: '刷新知识库与模型', exact: true }).click();
|
||
await page.getByLabel('向量模型', { exact: true }).selectOption('fixture:test-embedding');
|
||
await expect(page.getByLabel('知识库名称', { exact: true })).toHaveValue('我的创作资料');
|
||
await expect(page.getByRole('button', { name: '创建并选用', exact: true })).toBeEnabled();
|
||
await expect(page.getByText('管理员配置说明', { exact: true })).toHaveCount(0);
|
||
await page.getByRole('button', { name: '创建并选用', exact: true }).click();
|
||
await expect(page.getByText('上传第一份文档,让智能体用你的资料回答。')).toBeVisible();
|
||
await page.getByRole('button', { name: '上传文档', exact: true }).click();
|
||
const document = page.getByRole('article', { name: '本体(Ontology)学习路线图.pdf' });
|
||
await expect(document.getByText('等待处理', { exact: true })).toBeVisible();
|
||
await expect(page.getByText('没有可用内容', { exact: true })).toBeVisible();
|
||
await document.scrollIntoViewIfNeeded();
|
||
await page.screenshot({ path: testInfo.outputPath('knowledge-queued.png') });
|
||
await expect(document.getByText('正在解析文档', { exact: true })).toBeVisible();
|
||
await expect(document.getByText('正在建立索引', { exact: true })).toBeVisible();
|
||
await expect(document.getByText('可用于回答', { exact: true })).toBeVisible();
|
||
await expect(document.getByText(/18 段可检索内容/)).toBeVisible();
|
||
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 advancedTab.press('ArrowLeft');
|
||
await expect(requirementsTab).toBeFocused();
|
||
await expect(requirementsTab).toHaveAttribute('aria-selected', 'true');
|
||
await expect(page.getByLabel('每日上限(词元点数)')).toBeHidden();
|
||
await requirementsTab.press('ArrowRight');
|
||
await expect(page.getByRole('button', { name: '限制', exact: true })).toHaveAttribute('aria-current', 'page');
|
||
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 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.getByLabel('名称', { exact: true }).fill('我的新版写作搭档');
|
||
await expect(page.getByRole('button', { name: '应用最新修改', exact: true })).toBeDisabled();
|
||
await page.getByRole('button', { name: '保存草稿', exact: true }).click();
|
||
await expect(page.getByText('修改已保存,尚未应用', { exact: true })).toBeVisible();
|
||
const applyButton = page.getByRole('button', { name: '应用最新修改', exact: true });
|
||
await expect(applyButton).toBeInViewport();
|
||
await page.screenshot({ path: testInfo.outputPath('cloud-agent-apply-visible.png') });
|
||
await app.evaluate(({ BrowserWindow }) => BrowserWindow.getAllWindows()[0].setSize(1024, 768));
|
||
await expect(applyButton).toBeInViewport();
|
||
await page.screenshot({ path: testInfo.outputPath('cloud-agent-apply-compact.png') });
|
||
await applyButton.click();
|
||
await expect(page.getByRole('button', { name: '已应用', exact: true })).toBeDisabled();
|
||
await expect(page.getByText('修改已保存,尚未应用', { exact: true })).toHaveCount(0);
|
||
await app.evaluate(({ BrowserWindow }) => BrowserWindow.getAllWindows()[0].setSize(1366, 768));
|
||
await page.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();
|
||
await expect(page.getByRole('heading', { name: '分享给指定用户', exact: true })).toHaveCount(0);
|
||
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 page.getByRole('button', { name: '查看并配置自动任务' }).click();
|
||
await expect(page.getByLabel('任务名称')).toHaveValue('每天整理选题');
|
||
await expect(page.getByLabel('执行时间')).toHaveValue('08:30');
|
||
await expect(page.getByLabel('保存后启用')).not.toBeChecked();
|
||
await page.getByLabel('保存后启用').check();
|
||
await expect(page.getByText('启用前确认')).toBeVisible();
|
||
await page.getByRole('button', { name: '保存并启用' }).click();
|
||
await expect(page.getByRole('heading', { name: '每天整理选题' })).toBeVisible();
|
||
await expect(page.getByText(/每天 08:30/)).toBeVisible();
|
||
await page.getByRole('button', { name: '添加任务', exact: true }).click();
|
||
await expect(page.getByLabel('保存后启用')).not.toBeChecked();
|
||
await page.getByRole('button', { name: '取消', exact: true }).click();
|
||
await page.screenshot({ path: testInfo.outputPath('cloud-agent-schedules.png') });
|
||
} finally {
|
||
await app.evaluate(({ BrowserWindow }) => { for (const win of BrowserWindow.getAllWindows()) win.destroy(); }).catch(() => undefined);
|
||
await closeElectronApp(app);
|
||
}
|
||
});
|