merge: retire Canvas inspiration entry

# Conflicts:
#	README.md
#	src/components/layout/MainLayout.tsx
#	src/components/layout/Sidebar.tsx
#	tests/e2e/image-workspace-v2.spec.ts
#	tests/unit/app-module-provider-gate.test.tsx
#	tests/unit/title-bar.test.tsx
This commit is contained in:
inman
2026-09-07 10:24:24 +08:00
12 changed files with 128 additions and 114 deletions

View File

@@ -1,7 +1,7 @@
import { closeElectronApp, expect, getStableWindow, test } from './fixtures/electron';
test.describe('AI Design V2 workspace', () => {
test('keeps Prompt Museum cards usable when relative media fails', async ({ launchElectronApp }) => {
test('removes the inspiration entry and redirects its retired route to Canvas', async ({ launchElectronApp }) => {
test.setTimeout(90_000);
const app = await launchElectronApp({ skipSetup: true });
@@ -10,29 +10,6 @@ test.describe('AI Design V2 workspace', () => {
await expect(page.getByTestId('ai-module-selection-page')).toBeVisible();
await app.evaluate(({ ipcMain }) => {
const image = {
url: '/api/image-prompt-museum/e2e-entry/media/thumbnail',
width: 1200,
height: 900,
alt: 'E2E museum thumbnail',
};
const card = {
id: 'e2e-entry',
slug: 'e2e-entry',
title: '相对媒体 E2E',
summary: '验证图片失败不会阻断卡片。',
thumbnail: image,
categories: [],
model: { id: 'e2e-model', name: 'E2E Model' },
language: 'zh-CN',
attribution: {
author: { name: 'E2E 作者' },
source: { name: 'E2E 来源' },
license: { name: '测试许可', attributionText: 'E2E attribution' },
},
publishedAt: '2026-08-18T00:00:00.000Z',
updatedAt: '2026-08-18T00:00:00.000Z',
};
const respond = (json: unknown) => ({
ok: true,
data: { status: 200, ok: true, json },
@@ -50,47 +27,20 @@ test.describe('AI Design V2 workspace', () => {
},
});
}
if (path === '/api/works/image-prompt-museum') {
return respond({
success: true,
data: {
items: [card],
facets: { useCases: [], styles: [], subjects: [] },
nextCursor: null,
total: 1,
},
});
}
if (path === '/api/works/image-prompt-museum/e2e-entry') {
return respond({
success: true,
data: {
...card,
prompt: 'Create a resilient image card.',
variables: [],
images: [image],
requiresReferenceImages: false,
},
});
}
if (path === '/api/works/image-prompt-museum/e2e-entry/media/thumbnail') {
return respond({ mimeType: 'text/html', dataBase64: 'PGgxPnVuc2FmZTwvaDE+' });
}
return { ok: false, error: { message: `Unexpected E2E Host API request: ${path}` } };
});
});
await page.getByTestId('ai-module-option-painting').click();
const worksRail = page.getByTestId('image-workspace-works-rail');
await expect(worksRail.getByRole('button', { name: '获取灵感' })).toBeVisible();
await worksRail.getByRole('button', { name: '获取灵感' }).click();
await expect(worksRail).toBeVisible();
await expect(worksRail.getByRole('button', { name: /.*/u })).toHaveCount(0);
const cardButton = page.getByRole('button', { name: '查看 相对媒体 E2E' });
await expect(cardButton).toBeVisible();
await expect(page.getByLabel('E2E museum thumbnail加载失败')).toBeVisible();
await expect(cardButton).toBeEnabled();
await cardButton.click();
await expect(page.getByRole('button', { name: '关闭详情' })).toBeVisible();
await page.evaluate(() => {
window.location.hash = '#/image-prompts';
});
await expect.poll(() => page.evaluate(() => window.location.hash)).toBe('#/image-canvas');
await expect(page.getByTestId('image-workspace-works-rail')).toBeVisible();
} finally {
await closeElectronApp(app);
}

View File

@@ -123,6 +123,14 @@ describe('App programming provider initialization gate', () => {
expect(screen.queryByText('项目尚未初始化')).not.toBeInTheDocument();
});
it('redirects the retired inspiration route to the Canvas workspace', async () => {
await renderAt('/image-prompts/example');
expect(await screen.findByText('Canvas workspace')).toBeInTheDocument();
expect(screen.queryByText('Module chooser')).not.toBeInTheDocument();
expect(initProviders).not.toHaveBeenCalled();
});
it('redirects an orphaned token without a user identity away from a direct workspace route', async () => {
useAuthStore.setState({
initialized: true,

View File

@@ -64,16 +64,6 @@ describe('MainLayout module isolation', () => {
expect(screen.queryByTestId('sidebar-stub')).not.toBeInTheDocument();
});
it('keeps the user sidebar preference while moving the inspiration title into the title bar', () => {
renderLayout('/image-prompts');
expect(screen.getByTestId('titlebar-stub')).toHaveAttribute('data-page-title', '获取灵感');
expect(screen.getByTestId('titlebar-stub')).toHaveAttribute('data-overlay', 'false');
expect(screen.getByTestId('titlebar-stub')).toHaveAttribute('data-sidebar-collapsed', 'unset');
expect(screen.getByTestId('sidebar-stub')).toHaveAttribute('data-sidebar-collapsed', 'unset');
expect(useSettingsStore.getState().sidebarCollapsed).toBe(false);
});
it('does not overlay the local project initialization gate on AI hardware', () => {
renderLayout('/ai-hardware');

View File

@@ -132,13 +132,13 @@ describe('TitleBar platform behavior', () => {
expect(screen.getByTestId('titlebar-logo')).toBeInTheDocument();
});
it('keeps the painting page title after the macOS traffic-light safe area', () => {
it('keeps an optional page title after the macOS traffic-light safe area', () => {
window.electron.platform = 'darwin';
useSettingsStore.setState({ sidebarCollapsed: true });
render(<TitleBar integrated pageTitle="获取灵感" />);
render(<TitleBar integrated pageTitle="页面标题" />);
expect(screen.getByTestId('titlebar-page-title')).toHaveTextContent('获取灵感');
expect(screen.getByTestId('titlebar-page-title')).toHaveTextContent('页面标题');
expect(screen.getByTestId('titlebar-sidebar-surface')).toHaveClass('w-[132px]');
expect(screen.queryByTestId('titlebar-project-context')).not.toBeInTheDocument();
expect(screen.getByTestId('titlebar-logo').querySelectorAll('img')).toHaveLength(1);