feat(canvas): preview generated task images in app

This commit is contained in:
2026-09-15 14:58:21 +08:00
parent 80e52496d2
commit 41664b2ae3
6 changed files with 357 additions and 3 deletions

View File

@@ -145,7 +145,7 @@ test.describe('AI Design V2 workspace', () => {
assistantMessage: '明白了:你想做一张适合小红书的便携咖啡机图片。',
}],
tasks: [] as Array<Record<string, unknown>>,
assets: [],
assets: [] as Array<Record<string, unknown>>,
};
const respond = (json: unknown) => ({
ok: true,
@@ -162,9 +162,29 @@ test.describe('AI Design V2 workspace', () => {
const e2eGlobal = globalThis as typeof globalThis & {
__designE2eAuthReady?: boolean;
__designE2eProfileReady?: boolean;
__designE2eCompleteTask?: () => void;
__designE2eDownloadCount?: number;
};
e2eGlobal.__designE2eAuthReady = false;
e2eGlobal.__designE2eProfileReady = false;
e2eGlobal.__designE2eDownloadCount = 0;
e2eGlobal.__designE2eCompleteTask = () => {
workspace.tasks[0] = {
...workspace.tasks[0],
status: 'succeeded',
taskRevision: 2,
progress: { stage: 'completed', completedRequiredSteps: 1, totalRequiredSteps: 1 },
resultAssetIds: ['result-1'],
nextActions: ['view_result'],
};
workspace.assets = [{
assetId: 'result-1', workspaceId: 'workspace-1', role: 'generated',
mediaType: 'image', mimeType: 'image/svg+xml', width: 1600, height: 2400,
durationMilliseconds: null, generationTaskId: 'task-1',
createdAt: '2026-08-30T10:02:00.000Z',
contentPath: '/api/works/image-workspace/workspaces/workspace-1/assets/result-1/content',
}];
};
ipcMain.removeHandler('hostapi:fetch');
ipcMain.handle('hostapi:fetch', async (_event, request: {
@@ -173,6 +193,10 @@ test.describe('AI Design V2 workspace', () => {
body?: string | null;
}) => {
const path = request.path ?? '';
if (path.endsWith('/assets/result-1/download')) {
e2eGlobal.__designE2eDownloadCount! += 1;
return envelope({ status: 'saved' });
}
if (path === '/api/auth/session/sync') {
return respond({ success: true, session: e2eSession });
}
@@ -465,6 +489,54 @@ test.describe('AI Design V2 workspace', () => {
await expect(page.getByText('等待制作')).toBeVisible();
await expect(page.getByTestId('youth-creation-card')).toHaveCount(0);
await expect(page.getByText('1200', { exact: true })).toHaveCount(0);
// Complete the existing task without a paid provider or native download.
await page.route('**/assets/result-1/content?*', (route) => route.fulfill({
contentType: 'image/svg+xml',
body: '<svg xmlns="http://www.w3.org/2000/svg" width="1600" height="2400"><rect width="1600" height="2400" fill="#f4efe5"/><rect x="80" y="80" width="1440" height="2240" rx="80" fill="#d6e5dc"/><circle cx="800" cy="1050" r="450" fill="#47665b"/><text x="800" y="1850" text-anchor="middle" font-size="120" fill="#203b30">DESIGN PREVIEW</text></svg>',
}));
await app.evaluate(() => {
(globalThis as typeof globalThis & { __designE2eCompleteTask?: () => void }).__designE2eCompleteTask?.();
});
await page.reload();
const historyTask = page.getByTestId('design-plan-history-task-1');
await expect(historyTask).toContainText('已完成');
await historyTask.locator('summary').click();
const previewButton = historyTask.getByRole('button', { name: '放大查看图片' });
await previewButton.click();
const previewDialog = page.getByRole('dialog', { name: '图片预览' });
const previewImage = previewDialog.getByRole('img', { name: 'AI 作品大图' });
await expect(previewDialog).toBeVisible();
await expect(previewDialog.getByRole('button', { name: '原始尺寸' })).toBeEnabled();
expect(await previewImage.evaluate((image: HTMLImageElement) => image.naturalWidth)).toBe(1600);
await expect(previewImage).toHaveCSS('object-fit', 'contain');
const previewBounds = await previewDialog.boundingBox();
expect(previewBounds!.height).toBeGreaterThan(400);
expect(previewBounds!.width).toBeGreaterThan(800);
await previewDialog.getByRole('button', { name: '原始尺寸' }).click();
expect((await previewImage.boundingBox())!.width).toBe(1600);
expect((await previewImage.boundingBox())!.height).toBe(2400);
const scrollArea = previewDialog.getByTestId('design-image-preview-viewport');
expect(await scrollArea.evaluate((element) => element.scrollHeight > element.clientHeight)).toBe(true);
await previewDialog.getByRole('button', { name: '适应窗口' }).click();
await page.keyboard.press('Escape');
await expect(previewDialog).toHaveCount(0);
await expect(previewButton).toBeFocused();
await page.setViewportSize({ width: 375, height: 800 });
const compactTask = page.getByTestId('image-workspace-conversation').getByTestId('design-plan-history-task-1');
await compactTask.locator('summary').click();
await compactTask.getByRole('button', { name: '放大查看图片' }).click();
await expect(previewDialog.getByRole('button', { name: '原始尺寸' })).toBeEnabled();
const compactBounds = await previewDialog.boundingBox();
expect(compactBounds!.x).toBeGreaterThanOrEqual(0);
expect(compactBounds!.x + compactBounds!.width).toBeLessThanOrEqual(375);
await previewDialog.getByRole('button', { name: '关闭图片预览' }).click();
await expect(previewDialog).toHaveCount(0);
expect(await app.evaluate(() => (
globalThis as typeof globalThis & { __designE2eDownloadCount?: number }
).__designE2eDownloadCount)).toBe(0);
} finally {
await closeElectronApp(app);
}