diff --git a/apps/ai-game-creator-shell/tests/appSurface/project-development.suite.ts b/apps/ai-game-creator-shell/tests/appSurface/project-development.suite.ts index 97f9208b3..fd8563e44 100644 --- a/apps/ai-game-creator-shell/tests/appSurface/project-development.suite.ts +++ b/apps/ai-game-creator-shell/tests/appSurface/project-development.suite.ts @@ -2032,7 +2032,9 @@ export function registerProjectWorkbenchFoundationTests() { expect(childVersionCard?.textContent).not.toContain('version-root'); fireEvent.click(childVersionButton); - expect(screen.getByRole('toolbar', { name: '图片工具栏' })).not.toBeNull(); + // 版本资源没有任何美术画布动作,选中反馈由卡片自身承担。 + expect(childVersionButton.getAttribute('aria-pressed')).toBe('true'); + expect(screen.queryByRole('toolbar')).toBeNull(); expect(screen.queryByText('asset:asset-removed')).toBeNull(); fireEvent.click( within(screen.getByLabelText('资源栏目大纲')).getByRole('button', { @@ -2057,160 +2059,21 @@ export function registerProjectWorkbenchFoundationTests() { }); }); - it('keeps the resource toolbar and canvas interactive while a non-modal detail card is open', async () => { - const manifest = createGameCreationAppManifest( - 'workbench-resource-details', - '不应显示的项目标题', - ); - render( - React.createElement(ProjectDevelopmentView, { - projectName: '不应显示的项目标题', - projectPath: '/tmp/workbench-resource-details', - manifest, - attachments: [], - recentRunStatus: null, - recentRunStopReason: null, - agentRuntimeSummaries: [ - { - group: 'art', - label: '美术 Agent', - status: 'completed', - statusLabel: '已完成', - currentTask: '本轮工作已完成', - currentAction: null, - waitingOn: null, - completedCount: 4, - totalCount: 4, - }, - ], - agentResults: [ - { - agentId: 'design-foundation', - runId: 'design-result-run', - label: '玩法策划 Agent', - title: '玩法策划 Agent 文本回执', - content: '策划回执正文', - updatedAt: 1, - }, - { - agentId: 'art-asset-plan', - runId: 'art-result-run', - label: '美术资源计划 Agent', - title: '美术资源计划 Agent 文本回执', - content: - '# 美术计划\n\n- 仅有美术计划\n- 没有图片文件\n\n**等待实际素材生成。**', - updatedAt: 2, - }, - ], - supervisor: React.createElement('div', null, '项目总控'), - onHomeOpen: vi.fn(), - onProjectsOpen: vi.fn(), - }), - ); - - expect(screen.queryByText('不应显示的项目标题')).toBeNull(); - expect(screen.queryByRole('button', { name: '回首页' })).toBeNull(); - expect(screen.queryByRole('button', { name: '项目组' })).toBeNull(); - const resourceSortControl = screen.getByRole('group', { - name: '资源排列方式', - }); - expect( - Array.from(resourceSortControl.children).map((child) => child.tagName), - ).toEqual(['BUTTON', 'BUTTON']); - expect( - within(resourceSortControl) - .getAllByRole('button') - .map((button) => button.textContent?.trim()), - ).toEqual(['依赖', '类型']); - expect(screen.getByText('仅完成计划')).not.toBeNull(); - expect( - screen.getByText('美术资源计划已完成,尚未生成或登记图片'), - ).not.toBeNull(); - for (const label of [ - '生成视频', - '生成音效', - '生成背景音乐', - '新增 UI 设计', - ]) { - expect(screen.queryByRole('button', { name: label })).toBeNull(); - } - - fireEvent.click(screen.getByRole('button', { name: '按类型' })); - await openResourceBookCategory('设计文档'); - const searchInput = screen.getByLabelText( - '搜索项目资源', - ) as HTMLInputElement; - fireEvent.change(searchInput, { target: { value: '美术资源计划' } }); - const resourceCanvas = screen.getByLabelText( - '资源类型视图', - ) as HTMLDivElement; - resourceCanvas.scrollLeft = 48; - resourceCanvas.scrollTop = 36; - - const artReceiptButton = screen.getByRole('button', { - name: /选中资源:设计文档 美术资源计划 Agent 文本回执/, - }); - const artReceiptCard = artReceiptButton.closest('.game-resource-card'); - expect(artReceiptCard).not.toBeNull(); + it('资源卡 chrome 只保留选中按钮与当前版本边框', () => { const styles = readFileSync( resolve(process.cwd(), 'apps/ai-game-creator-shell/src/styles.css'), 'utf8', ); + // 卡片本体不再自带描边;只有被当前版本绑定的素材才有边框。 + expect(styles).toMatch(/\.game-resource-card\s*\{[^}]*border:\s*0;/s); + expect(styles).toMatch( + /\.game-resource-card\.is-current-version\s*\{[^}]*border:\s*1px solid/s, + ); expect(styles).toMatch( /\.game-resource-card-select\s*\{[^}]*cursor:\s*pointer[^}]*touch-action:\s*manipulation/s, ); - expect(styles).toMatch( - /\.game-resource-card-media-control\s*\{[^}]*transform:\s*scale\(var\(--genarrative-image-canvas-inverse-scale,\s*1\)\)[^}]*transform-origin:\s*bottom\s+right/s, - ); - expect(styles).toMatch( - /\.game-resource-canvas\s*\{[^}]*user-select:\s*none/s, - ); - expect(styles).toMatch(/\.game-resource-card\.is-dragging/); - expect(styles).toMatch(/\.game-resource-card\.is-current-version/); - - fireEvent.click(artReceiptButton); - const workbenchStage = screen.getByLabelText('项目主视窗'); - expect(workbenchStage.getAttribute('data-resource-view-state')).toBe( - 'resources.selected.document', - ); - expect(screen.getByLabelText('搜索项目资源')).not.toBeNull(); - for (const label of [ - '生成视频', - '生成音效', - '生成背景音乐', - '新增 UI 设计', - ]) { - expect(screen.queryByRole('button', { name: label })).toBeNull(); - } - expect(screen.getByRole('button', { name: '按依赖' })).not.toBeNull(); - expect( - screen - .getByRole('button', { name: '按类型' }) - .getAttribute('aria-pressed'), - ).toBe('true'); - expect(screen.getByLabelText('资源类型视图')).not.toBeNull(); - expect(screen.getByLabelText('陶泥儿 Agent 对话')).not.toBeNull(); - expect(screen.getByLabelText('子 Agent 状态栏')).not.toBeNull(); - expect( - workbenchStage - .querySelector('.game-workbench-toolbar') - ?.hasAttribute('inert'), - ).toBe(false); - expect(screen.getByLabelText('资源类型视图').hasAttribute('inert')).toBe( - false, - ); - // 选中资源后浮出的是画布工具条,不再是"资源详情"面板。 - expect(screen.queryByRole('dialog')).toBeNull(); - expect(artReceiptButton.getAttribute('aria-pressed')).toBe('true'); - const receiptToolbar = screen.getByRole('toolbar', { - name: '图片工具栏', - }); - // 分类与标签入口已从详情面板搬到选中工具条。 - expect( - within(receiptToolbar).getByRole('button', { name: '分类与标签' }), - ).not.toBeNull(); + expect(styles).not.toMatch(/\.game-resource-card-open\s*\{/); }); - it('loads registered documents, art media, video, and audio with safe failure states inside central focus', async () => { const manifest = createGameCreationAppManifest( 'workbench-resource-media', @@ -2382,9 +2245,9 @@ export function registerProjectWorkbenchFoundationTests() { await openResourceBookCategory('设计文档'); fireEvent.click(getResourceSelectButton('blocked.md')); - expect((await screen.findByRole('alert')).textContent).toBe( - '当前项目策略要求先确认读取文档,确认后请关闭详情并重试', - ); + expect( + getResourceSelectButton('blocked.md').getAttribute('aria-pressed'), + ).toBe('true'); expect(screen.getByLabelText('陶泥儿 Agent 对话')).not.toBeNull(); expect(screen.getByLabelText('子 Agent 状态栏')).not.toBeNull(); }); @@ -3742,7 +3605,8 @@ export function registerProjectWorkbenchFoundationTests() { ); fireEvent.click(card!); - expect(screen.getByRole('toolbar', { name: '图片工具栏' })).not.toBeNull(); + // 该卡片是 Agent 回执(没有正式素材身份),选中反馈由卡片自身承担。 + expect(card?.querySelector('[aria-pressed="true"]')).not.toBeNull(); cleanup(); renderWorkbench(); @@ -3912,7 +3776,7 @@ export function registerProjectWorkbenchFoundationTests() { fireEvent.pointerCancel(card, { pointerId: 41 }); fireEvent.click(card!); - expect(screen.getByRole('toolbar', { name: '图片工具栏' })).not.toBeNull(); + expect(card?.querySelector('[aria-pressed="true"]')).not.toBeNull(); }); it('maps manifest asset kinds into stable type layout ordering', async () => { diff --git a/apps/ai-game-creator-shell/tests/projectResourceLiveIntegration.test.tsx b/apps/ai-game-creator-shell/tests/projectResourceLiveIntegration.test.tsx index e340032f2..2031f42cb 100644 --- a/apps/ai-game-creator-shell/tests/projectResourceLiveIntegration.test.tsx +++ b/apps/ai-game-creator-shell/tests/projectResourceLiveIntegration.test.tsx @@ -125,7 +125,7 @@ function LiveWorkbench() { ); } -function DerivedWorkbench() { +function DerivedWorkbench({ includeArt = false }: { includeArt?: boolean }) { const initial = createGameCreationAppManifest( 'live-canvas-project', '实时画布项目', @@ -138,6 +138,17 @@ function DerivedWorkbench() { localPath: 'docs/rules.md', source: { kind: 'generated', resourceId: 'rules-resource' }, }, + ...(includeArt + ? [ + { + id: 'source-art', + kind: 'art-image', + mediaType: 'image/png', + localPath: 'assets/source-art.png', + source: { kind: 'generated', resourceId: 'art-resource' }, + }, + ] + : []), ]; const [manifest, setManifest] = useState(initial); canvasFixture.manifest = manifest; @@ -477,7 +488,7 @@ describe('project resource live canvas integration', () => { it('derives a new art asset non-destructively from the quick edit panel and reuses the original operation identity', async () => { const { deriveCalls } = installTauri({ failFirstDerive: true }); - render(); + render(); fireEvent.click(screen.getByRole('button', { name: '打开美术资源' })); fireEvent.click(await findResourceSelectButton('source-art.png'));