test: align configuration coverage with current project workflow
This commit is contained in:
1 parent
e147119b51
commit
436f7ba1ea
3 files changed
+115
-137
No files matched your search
@@ -20,15 +20,17 @@
|
||||
|
||||
## Outcome
|
||||
|
||||
- Not completed.
|
||||
- All five final source histories consolidated locally. Product verification passed; normal remote publication and immutable runtime preparation are next. Native activation/quit/restart is still pending because the actual CUA tool reports MacLocked and manual-unlock input has not arrived. Keep this owned checkout until restart verification and final handoff are complete.
|
||||
|
||||
## Verification
|
||||
|
||||
- Not run.
|
||||
- 398 related unit tests across 15 files passed. TypeScript and scoped ESLint passed. Initial default full build passed with Renderer, Main, preload and utility outputs. Independent combined-product and source-equivalence reviews passed.
|
||||
- 14 distinct targeted Electron cases passed across the targeted runs: navigation/home/account/shared-sidebar, work-entry restoration, Canvas sidebar, cloud channel, permanent deletion/project menus, and current project configuration/resource/plugin workflow. Two obsolete fixture workflows initially failed; corrected only test fixtures/locators/route-query expectations and reran those cases successfully (2 passed in 8.7 seconds). Final source build/proof will be regenerated after committing these test-only corrections.
|
||||
- Real user-app native verification is blocked by MacLocked; do not equate isolated Electron tests with activation of the user profile.
|
||||
|
||||
## Follow-ups
|
||||
|
||||
- None recorded.
|
||||
- Publish normally, prepare full runtime, then after manual unlock observe fresh saved/idle native state, cancel any leftover delete confirmation, quit and restart the existing app, verify the actual loaded Main/Renderer and account/project continuity, finalize runtime receipt, and retire only this owned clean worktree.
|
||||
|
||||
## Promotion Candidates
|
||||
|
||||
@@ -70,3 +72,10 @@
|
||||
- Resolved actual overlap semantically: Code brand removed and shared configuration sidebar/footer retained per newest explicit user request. All other product merging was clean, including work-preview stored snapshot getter with deletion flight/physical purge lifecycle, Canvas styling with archive removal and latest channel Page. No rejected whole visual variant included.
|
||||
- Adapted pre-existing shared-sidebar E2E to the current approved project-menu Settings entry and default-model control, retaining geometric equality, direct reload, collapse and plugin assertions. It explicitly checks deleted session-settings entry is absent and Delete Conversation visible; no actual user data deleted. Removed the resulting stale README reference to brand-positioned creation and deleted menu entry. These are integration-only coverage/documentation corrections, not product behavior expansion.
|
||||
- Root actual CUA call confirmed MacLocked; human manual unlock question remains pending. Code integration/validation/staging proceeds; application interaction/quit/launch waits for unlocked fresh native state. No lock bypass, old input-discard authorization, actual card/conversation deletion or cloud mutation.
|
||||
|
||||
## Combined Verification And Test Fixture Reconciliation
|
||||
|
||||
- Product source e147119 passed 398 related units, typecheck, scoped lint and actual default full build. No code behavior changed during fixture repairs. The first targeted Electron batch had 10 passes and two old-fixture failures; a later four-case run passed both deletion/project-menu cases and exposed only locator/query expectations in the repaired configuration cases. Final two-case run passed in8.7s. Evidence is under `.trial-runtime/consolidate-five-20261014-2d069b40/` outside the checkout.
|
||||
- Main-navigation remembered-project seed previously used initialized:true/agents:[]; now uses the supported createCodingProjectConfigV2 factory so the default-model assertion represents an existing configured project. Native select uses its accessible combobox role; exact wrapping-label text includes option content. Plugin drawer close legitimately retains filter query; test preserves the base route and verifies drawer gone.
|
||||
- Existing project-configuration-skills E2E had already-obsolete create-Agent/card/avatar workflows at base350f7d7. Replaced them with current project-menu Settings, valid default-agent fixture, null-model save preserving prompt/Skills metadata, same-sized three resource cards, actual isolated local knowledge upload/readback/reload, and plugin deep-link/reload/close. Local fixture blocks external fetch and never invokes a provider or actual user profile.
|
||||
- A fresh root native getApp after tool documentation restore again returned MacLocked. No native quit, input discard, activation, profile access or user-data mutation occurred.
|
||||
@@ -2,6 +2,7 @@ import { mkdir, writeFile } from 'node:fs/promises';
|
||||
import { join } from 'node:path';
|
||||
import { closeElectronApp, expect, getStableWindow, test } from './fixtures/electron';
|
||||
import { billingSummary } from '../fixtures/permanent-points';
|
||||
import { createCodingProjectConfigV2 } from '../../electron/coding-projects/project-config';
|
||||
|
||||
async function seedInactiveCodingProjects(resources: { rootDir: string; userDataDir: string }) {
|
||||
const now = '2026-09-06T08:00:00.000Z';
|
||||
@@ -31,12 +32,7 @@ async function seedInactiveCodingProjects(resources: { rootDir: string; userData
|
||||
await mkdir(join(project.path, '.makelore'), { recursive: true });
|
||||
await mkdir(join(project.path, 'knowledge'), { recursive: true });
|
||||
await writeFile(join(project.path, '.makelore', 'project.json'), JSON.stringify({
|
||||
schemaVersion: 2,
|
||||
projectType: 'custom',
|
||||
projectId: project.projectId,
|
||||
initialized: true,
|
||||
agents: [],
|
||||
knowledgeDirectory: 'knowledge',
|
||||
...createCodingProjectConfigV2(project.createdAt, 'custom', project.projectId),
|
||||
createdAt: project.createdAt,
|
||||
updatedAt: project.updatedAt,
|
||||
}));
|
||||
@@ -535,7 +531,7 @@ test.describe('Makelore module navigation without setup flow', () => {
|
||||
await page.mouse.move(1000, 500);
|
||||
await expect.poll(readCodeChrome).toEqual(chatChrome);
|
||||
await expect(sidebar).toHaveCSS('background-color', 'rgb(243, 247, 251)');
|
||||
const defaultModel = page.getByLabel('默认模型', { exact: true });
|
||||
const defaultModel = page.getByRole('combobox', { name: '默认模型', exact: true });
|
||||
await expect(defaultModel).toBeVisible();
|
||||
const originalModel = await defaultModel.inputValue();
|
||||
await expect(page.getByLabel('项目提示词', { exact: true })).toHaveCount(0);
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { mkdir, mkdtemp, rm, writeFile } from 'node:fs/promises';
|
||||
import { mkdtemp, readFile, rm, writeFile } from 'node:fs/promises';
|
||||
import { tmpdir } from 'node:os';
|
||||
import path from 'node:path';
|
||||
import { closeElectronApp, expect, getStableWindow, test } from './fixtures/electron';
|
||||
import { createCodingProjectConfigV2 } from '../../electron/coding-projects/project-config';
|
||||
|
||||
test.describe('Project configuration plugin capabilities', () => {
|
||||
test('merges Skill management into the plugin tabs and removes standalone local Skills', async ({ launchElectronApp }) => {
|
||||
test('keeps model settings and resource drawers while managing Skills through plugins', async ({ launchElectronApp }) => {
|
||||
const parentPath = await mkdtemp(path.join(tmpdir(), 'makelore-project-configuration-e2e-'));
|
||||
const app = await launchElectronApp({ skipSetup: true });
|
||||
|
||||
@@ -13,6 +13,15 @@ test.describe('Project configuration plugin capabilities', () => {
|
||||
await app.evaluate(({ ipcMain }, selectedPath) => {
|
||||
ipcMain.removeHandler('dialog:open');
|
||||
ipcMain.handle('dialog:open', async () => ({ canceled: false, filePaths: [selectedPath] }));
|
||||
// Plugin catalog reads must not reach a real cloud service in this fixture.
|
||||
const originalFetch = globalThis.fetch;
|
||||
globalThis.fetch = async (input, init) => {
|
||||
const url = new URL(typeof input === 'string' ? input : input instanceof URL ? input.href : input.url);
|
||||
if (!['127.0.0.1', 'localhost', '[::1]'].includes(url.hostname)) {
|
||||
throw new Error('External requests are disabled in the project configuration fixture');
|
||||
}
|
||||
return originalFetch(input, init);
|
||||
};
|
||||
}, parentPath);
|
||||
|
||||
const page = await getStableWindow(app);
|
||||
@@ -20,50 +29,92 @@ test.describe('Project configuration plugin capabilities', () => {
|
||||
await page.getByTestId('ai-module-option-programming').click();
|
||||
await expect(page.getByTestId('main-layout')).toBeVisible();
|
||||
await page.getByTestId('sidebar-create-project').click();
|
||||
await expect(page.getByRole('radio', { name: '创建新的项目 ID' })).toHaveCount(0);
|
||||
await expect(page.getByRole('radio', { name: '绑定已有项目 ID' })).toHaveCount(0);
|
||||
await expect(page.getByRole('radio', { name: '交互式 AI 应用' })).toHaveCount(0);
|
||||
await expect(page.getByRole('radio', { name: '自定义项目' })).toHaveCount(0);
|
||||
await expect(page.getByRole('radio', { name: '小游戏' })).toHaveCount(0);
|
||||
await expect(page.getByRole('radio', { name: '小程序' })).toHaveCount(0);
|
||||
await expect(page.getByRole('radio', { name: '直接使用所选文件夹(默认)' })).toBeChecked();
|
||||
await page.getByRole('button', { name: '选择路径' }).click();
|
||||
await expect(page.getByLabel('项目路径')).toHaveValue(parentPath);
|
||||
await page.getByRole('button', { name: '确认创建' }).click();
|
||||
|
||||
await expect(page.getByTestId('coding-chat-empty-agent')).toBeVisible();
|
||||
const projectMenu = page.getByTestId('sidebar').getByRole('button', { name: /^项目操作:/ });
|
||||
await expect(projectMenu).toHaveCount(1);
|
||||
await expect(page.getByTestId('project-initialization-gate')).toHaveCount(0);
|
||||
await page.getByRole('button', { name: '创建项目智能体' }).click();
|
||||
await expect(page.getByTestId('project-configuration-page')).toBeVisible();
|
||||
await expect(page.getByTestId('project-identity-card')).toHaveCount(0);
|
||||
await expect(page.getByTestId('legacy-project-identity-card')).toHaveCount(0);
|
||||
await expect(page.getByTestId('independent-copy-button')).toHaveCount(0);
|
||||
await expect(page.getByText(/项目 ID|项目身份|独立副本/u)).toHaveCount(0);
|
||||
await expect(page.getByRole('button', { name: '保存项目配置' })).toBeVisible();
|
||||
await expect(page.getByRole('button', { name: '确认并完成初始化' })).toHaveCount(0);
|
||||
await expect(page.getByTestId('sidebar-nav-publish')).toHaveCount(0);
|
||||
await expect(page.getByText(/新项目还没有智能体/)).toHaveCount(0);
|
||||
await expect(page.getByTestId('project-configuration-actions')).toBeVisible();
|
||||
const actionBarBottomGap = await page.getByTestId('project-configuration-actions').evaluate((element) => window.innerHeight - element.getBoundingClientRect().bottom);
|
||||
expect(actionBarBottomGap).toBeLessThan(40);
|
||||
await expect(page.getByRole('button', { name: '创建智能体' })).toBeVisible();
|
||||
|
||||
const resourceCardGeometry = await page.getByTestId('project-resource-row').locator(':scope > button').evaluateAll((cards) => cards.map((card) => {
|
||||
// Seed only this temporary project's supported default configuration. The
|
||||
// former create-Agent/card/avatar workflow was already absent at main350f7d7.
|
||||
const configPath = path.join(parentPath, '.makelore', 'project.json');
|
||||
const createdConfig = JSON.parse(await readFile(configPath, 'utf8')) as { projectId?: string };
|
||||
const now = new Date().toISOString();
|
||||
const defaultAgent = {
|
||||
id: 'e2e-agent', avatarId: 'avatar-01', roleName: '项目智能体', name: 'E2E智能体',
|
||||
builtIn: false, enabled: true, model: null, modelResolution: 'required' as const,
|
||||
skillIds: ['agent-browser'],
|
||||
responsibility: { mission: '验证项目资源入口。', owns: [], boundaries: [], collaborators: [], principles: [] },
|
||||
prompt: '保留已有配置,不在页面中编辑。', archivedAt: null, pinned: true,
|
||||
createdAt: now, updatedAt: now,
|
||||
};
|
||||
await writeFile(configPath, JSON.stringify({
|
||||
...createCodingProjectConfigV2(now, 'interactive_ai_app', createdConfig.projectId),
|
||||
initialized: true, defaultAgentId: defaultAgent.id, agents: [defaultAgent],
|
||||
}, null, 2));
|
||||
await page.reload();
|
||||
await expect(projectMenu).toBeVisible();
|
||||
await projectMenu.click();
|
||||
await expect(page.getByRole('menuitem')).toHaveText(['项目设置']);
|
||||
await page.getByRole('menuitem', { name: '项目设置', exact: true }).click();
|
||||
await expect(page).toHaveURL(/\/project-config$/);
|
||||
const configuration = page.getByTestId('project-configuration-page');
|
||||
await expect(configuration).toBeVisible();
|
||||
const model = configuration.getByRole('combobox', { name: '默认模型', exact: true });
|
||||
await expect(model).toBeEnabled();
|
||||
await expect(model).toHaveValue('');
|
||||
await expect(configuration.getByRole('heading', { name: '默认编程配置', exact: true })).toBeVisible();
|
||||
for (const id of ['project-identity-card', 'legacy-project-identity-card', 'independent-copy-button', 'resource-card-skills', 'project-agent-e2e-agent', 'superpowers-card']) {
|
||||
await expect(configuration.getByTestId(id)).toHaveCount(0);
|
||||
}
|
||||
await expect(configuration.getByRole('textbox', { name: '项目提示词', exact: true })).toHaveCount(0);
|
||||
await expect(configuration.getByRole('heading', { name: '项目 Skills', exact: true })).toHaveCount(0);
|
||||
await expect(configuration.getByRole('button', { name: '创建智能体', exact: true })).toHaveCount(0);
|
||||
await expect(configuration.getByRole('switch', { name: '启用 Superpowers' })).toHaveCount(0);
|
||||
const save = configuration.getByRole('button', { name: '保存项目配置', exact: true });
|
||||
await expect(save).toBeEnabled();
|
||||
const actionBar = configuration.getByTestId('project-configuration-actions');
|
||||
await expect(actionBar).toBeVisible();
|
||||
const actionBarBottomGap = await actionBar.evaluate((element) => window.innerHeight - element.getBoundingClientRect().bottom);
|
||||
expect(actionBarBottomGap).toBeGreaterThanOrEqual(0);
|
||||
expect(actionBarBottomGap).toBeLessThan(40);
|
||||
|
||||
const resourceCardGeometry = await configuration.getByTestId('project-resource-row').locator(':scope > button').evaluateAll((cards) => cards.map((card) => {
|
||||
const rect = card.getBoundingClientRect();
|
||||
return { left: rect.left, top: rect.top, width: rect.width };
|
||||
return { left: rect.left, top: rect.top, width: rect.width, height: rect.height };
|
||||
}));
|
||||
expect(resourceCardGeometry).toHaveLength(3);
|
||||
expect(Math.max(...resourceCardGeometry.map(({ top }) => top)) - Math.min(...resourceCardGeometry.map(({ top }) => top))).toBeLessThanOrEqual(1);
|
||||
for (const dimension of ['top', 'width', 'height'] as const) {
|
||||
const values = resourceCardGeometry.map((card) => card[dimension]);
|
||||
expect(Math.max(...values) - Math.min(...values)).toBeLessThanOrEqual(1);
|
||||
}
|
||||
expect(resourceCardGeometry.every(({ width }) => width > 0)).toBe(true);
|
||||
expect(resourceCardGeometry.map(({ left }) => left)).toEqual([...resourceCardGeometry.map(({ left }) => left)].sort((a, b) => a - b));
|
||||
|
||||
await save.click();
|
||||
await expect(page.getByText('项目配置已保存', { exact: true })).toBeVisible();
|
||||
await expect(save).toBeEnabled();
|
||||
const savedConfig = JSON.parse(await readFile(configPath, 'utf8')) as { defaultAgentId: string; agents: typeof defaultAgent[] };
|
||||
expect(savedConfig.defaultAgentId).toBe(defaultAgent.id);
|
||||
expect(savedConfig.agents[0]).toMatchObject({ model: null, prompt: defaultAgent.prompt, skillIds: defaultAgent.skillIds });
|
||||
await configuration.getByTestId('project-configuration-back-button').click();
|
||||
await expect(page).toHaveURL(/\/chat$/);
|
||||
await projectMenu.click();
|
||||
await page.getByRole('menuitem', { name: '项目设置', exact: true }).click();
|
||||
await expect(configuration).toBeVisible();
|
||||
await expect(model).toHaveValue('');
|
||||
|
||||
const knowledgeFile = path.join(parentPath, 'fixture-note.txt');
|
||||
await writeFile(knowledgeFile, '本地项目知识文件,仅供界面验证。');
|
||||
const drawerWidths: number[] = [];
|
||||
for (const [resourceId, title] of [
|
||||
['resource-card-models', '可用模型'],
|
||||
['resource-card-knowledge', '知识文件'],
|
||||
['resource-card-plugins', '插件'],
|
||||
] as const) {
|
||||
await page.getByTestId(resourceId).click();
|
||||
await configuration.getByTestId(resourceId).click();
|
||||
const drawer = page.getByRole('dialog', { name: title });
|
||||
await expect(drawer).toBeVisible();
|
||||
const drawerBox = await drawer.boundingBox();
|
||||
@@ -73,17 +124,25 @@ test.describe('Project configuration plugin capabilities', () => {
|
||||
await expect(drawer.getByRole('combobox')).toHaveCount(0);
|
||||
await expect(drawer.locator('[data-testid="project-model-list"], [data-testid="project-model-empty-state"]')).toHaveCount(1);
|
||||
}
|
||||
if (resourceId === 'resource-card-knowledge') {
|
||||
await expect(drawer.getByRole('button', { name: '上传知识文件', exact: true })).toBeVisible();
|
||||
await drawer.locator('input[type="file"]').setInputFiles(knowledgeFile);
|
||||
await expect(drawer.getByText('fixture-note.txt', { exact: true })).toBeVisible();
|
||||
expect(await readFile(path.join(parentPath, 'knowledge', 'fixture-note.txt'), 'utf8')).toBe('本地项目知识文件,仅供界面验证。');
|
||||
}
|
||||
if (resourceId === 'resource-card-plugins') {
|
||||
await expect(page).toHaveURL(/\/project-config\/plugins\?/);
|
||||
await expect(page.getByTestId('project-plugins-sheet')).toBeVisible();
|
||||
await expect(drawer.getByTestId('plugins-page')).toBeVisible();
|
||||
await expect(drawer.getByText('统一管理云端下发的插件与 Skill,以及本机安装的能力。')).toBeVisible();
|
||||
await expect(drawer.getByRole('tab', { name: /可选/ })).toBeVisible();
|
||||
await expect(drawer.getByRole('tab', { name: /已安装/ })).toBeVisible();
|
||||
await expect(drawer.getByRole('button', { name: /刷新/ })).toHaveCount(0);
|
||||
await expect(drawer.getByRole('searchbox')).toHaveCount(0);
|
||||
await expect(drawer.getByRole('combobox')).toHaveCount(0);
|
||||
await page.reload();
|
||||
await expect(page).toHaveURL(/\/project-config\/plugins\?/);
|
||||
await expect(drawer).toBeVisible();
|
||||
await expect(drawer.getByTestId('plugins-page')).toBeVisible();
|
||||
}
|
||||
const closeButton = drawer.getByRole('button', { name: '关闭' });
|
||||
const closeButton = drawer.getByRole('button', { name: '关闭', exact: true });
|
||||
const closeGeometry = await closeButton.evaluate((button) => {
|
||||
const icon = button.querySelector('svg');
|
||||
if (!icon) return null;
|
||||
@@ -94,110 +153,24 @@ test.describe('Project configuration plugin capabilities', () => {
|
||||
icon: { x: iconRect.x, y: iconRect.y, width: iconRect.width, height: iconRect.height },
|
||||
};
|
||||
});
|
||||
if (!closeGeometry) {
|
||||
throw new Error(`未能读取 ${title} 抽屉关闭按钮的布局区域`);
|
||||
}
|
||||
if (!closeGeometry) throw new Error(`未能读取 ${title} 抽屉关闭按钮的布局区域`);
|
||||
expect(closeGeometry.button.width).toBe(40);
|
||||
expect(closeGeometry.button.height).toBe(40);
|
||||
expect(Math.abs((closeGeometry.icon.x + closeGeometry.icon.width / 2) - (closeGeometry.button.x + closeGeometry.button.width / 2))).toBeLessThanOrEqual(0.5);
|
||||
expect(Math.abs((closeGeometry.icon.y + closeGeometry.icon.height / 2) - (closeGeometry.button.y + closeGeometry.button.height / 2))).toBeLessThanOrEqual(0.5);
|
||||
await closeButton.locator('svg').click();
|
||||
await expect(page.getByRole('dialog', { name: title })).toHaveCount(0);
|
||||
await expect(drawer).toHaveCount(0);
|
||||
await expect(page).toHaveURL(/\/project-config(?:\?|$)/);
|
||||
}
|
||||
expect(Math.max(...drawerWidths) - Math.min(...drawerWidths)).toBeLessThanOrEqual(1);
|
||||
expect(Math.max(...drawerWidths)).toBeLessThanOrEqual(430);
|
||||
|
||||
const now = new Date().toISOString();
|
||||
await mkdir(path.join(parentPath, '.makelore'), { recursive: true });
|
||||
await writeFile(path.join(parentPath, '.makelore', 'project.json'), JSON.stringify({
|
||||
...createCodingProjectConfigV2(now, 'interactive_ai_app'),
|
||||
initialized: true,
|
||||
agents: [{
|
||||
id: 'e2e-agent',
|
||||
avatarId: 'avatar-01',
|
||||
roleName: '项目智能体',
|
||||
name: 'E2E智能体',
|
||||
builtIn: false,
|
||||
enabled: true,
|
||||
model: { accountId: 'moonshot', modelId: 'kimi-k2.6', thinkingLevel: 'off' },
|
||||
modelResolution: 'resolved',
|
||||
skillIds: ['agent-browser', 'grilling'],
|
||||
responsibility: { mission: '验证智能体编辑弹窗。', owns: [], boundaries: [], collaborators: [], principles: [] },
|
||||
prompt: '',
|
||||
archivedAt: null,
|
||||
pinned: false,
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
}],
|
||||
}, null, 2));
|
||||
await page.reload();
|
||||
await expect(page.getByTestId('project-configuration-page')).toBeVisible();
|
||||
await expect(page.getByRole('textbox', { name: '项目提示词', exact: true })).toHaveCount(0);
|
||||
await expect(page.getByRole('heading', { name: '项目 Skills', exact: true })).toHaveCount(0);
|
||||
await expect(page.getByTestId('project-identity-card')).toHaveCount(0);
|
||||
await expect(page.getByTestId('legacy-project-identity-card')).toHaveCount(0);
|
||||
await expect(page.getByText(/项目 ID|项目身份|独立副本/u)).toHaveCount(0);
|
||||
|
||||
await expect(page.getByTestId('resource-card-skills')).toHaveCount(0);
|
||||
await expect(page.getByTestId('project-agent-e2e-agent')).toContainText('0 项插件能力');
|
||||
await expect(page.getByTestId('superpowers-card')).toHaveCount(0);
|
||||
await expect(page.getByRole('switch', { name: '启用 Superpowers' })).toHaveCount(0);
|
||||
await expect(page.getByTestId('skill-card-agent-browser')).toHaveCount(0);
|
||||
await expect(page.getByTestId('skill-card-game-engine')).toHaveCount(0);
|
||||
await expect(page.getByTestId('resource-card-publish')).toHaveCount(0);
|
||||
await expect(page.getByRole('button', { name: '一键提交审核' })).toBeVisible();
|
||||
|
||||
await app.evaluate(({ ipcMain }) => {
|
||||
ipcMain.removeHandler('hostapi:fetch');
|
||||
ipcMain.handle('hostapi:fetch', async (_event, request: { path?: string }) => {
|
||||
if (/^\/api\/works\/projects\/mine\/[^/]+\/status$/.test(request.path ?? '')) {
|
||||
return {
|
||||
ok: true,
|
||||
data: {
|
||||
status: 200,
|
||||
ok: true,
|
||||
json: {
|
||||
success: false,
|
||||
status: 404,
|
||||
code: 'PROJECT_NOT_FOUND',
|
||||
error: 'Project not found',
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
return { ok: false, error: { message: `Unexpected E2E Host API request: ${request.path ?? ''}` } };
|
||||
});
|
||||
});
|
||||
await page.getByRole('button', { name: '一键提交审核' }).click();
|
||||
const publishDialog = page.getByRole('dialog', { name: '完善作品信息后提交' });
|
||||
await expect(publishDialog).toBeVisible();
|
||||
await expect(publishDialog.getByLabel(/项目封面/)).toBeVisible();
|
||||
await publishDialog.getByLabel(/发布者姓名/).fill('E2E 作者');
|
||||
await publishDialog.getByLabel(/发布者年龄/).fill('12');
|
||||
await publishDialog.getByLabel(/项目简介/).fill('验证首次提审必须选择项目封面。');
|
||||
await publishDialog.getByRole('button', { name: '提交审核' }).click();
|
||||
await expect(publishDialog.getByRole('alert')).toContainText('首次提交必须上传');
|
||||
|
||||
const coverPath = path.join(process.cwd(), 'src/assets/agent-avatars/avatar-01.png');
|
||||
await publishDialog.getByLabel(/项目封面/).setInputFiles(coverPath);
|
||||
await expect(publishDialog.getByAltText('项目封面预览')).toBeVisible();
|
||||
await expect(publishDialog.getByText('avatar-01.png')).toBeVisible();
|
||||
await expect(publishDialog.getByText('重新选择')).toBeVisible();
|
||||
await publishDialog.getByRole('button', { name: '取消' }).click();
|
||||
|
||||
const agentCard = page.getByTestId('project-agent-e2e-agent');
|
||||
await expect(agentCard).toContainText('E2E智能体');
|
||||
await agentCard.click();
|
||||
const maintenanceDialog = page.getByRole('dialog', { name: 'E2E智能体 · 编辑智能体' });
|
||||
await expect(maintenanceDialog).toBeVisible();
|
||||
await expect(maintenanceDialog.getByLabel(/智能体名称/)).toHaveValue('E2E智能体');
|
||||
await maintenanceDialog.getByRole('button', { name: '更换头像' }).click();
|
||||
const avatarDialog = page.getByRole('dialog', { name: '选择头像' });
|
||||
await expect(avatarDialog).toBeVisible();
|
||||
await avatarDialog.getByLabel('上传智能体头像').setInputFiles(path.join(process.cwd(), 'src/assets/agent-avatars/avatar-01.png'));
|
||||
await expect(avatarDialog).toHaveCount(0);
|
||||
await expect(maintenanceDialog.getByAltText('当前上传头像')).toBeVisible();
|
||||
await expect(page.getByText('完成配置')).toHaveCount(0);
|
||||
await expect(configuration).toBeVisible();
|
||||
await expect(model).toHaveValue('');
|
||||
await configuration.getByTestId('resource-card-knowledge').click();
|
||||
const restoredKnowledge = page.getByRole('dialog', { name: '知识文件' });
|
||||
await expect(restoredKnowledge.getByText('fixture-note.txt', { exact: true })).toBeVisible();
|
||||
await restoredKnowledge.getByRole('button', { name: '关闭', exact: true }).click();
|
||||
} finally {
|
||||
await closeElectronApp(app);
|
||||
await rm(parentPath, { recursive: true, force: true });
|
||||
|
||||
Reference in new issue
Block a user