Merge branch 'feat/agc-v3-c3-canvas-match' into feat/agc-canvas-resource-workbench-v3
This commit is contained in:
@@ -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 () => {
|
||||
|
||||
@@ -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(<DerivedWorkbench />);
|
||||
render(<DerivedWorkbench includeArt />);
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: '打开美术资源' }));
|
||||
fireEvent.click(await findResourceSelectButton('source-art.png'));
|
||||
|
||||
Reference in New Issue
Block a user