diff --git a/tests/e2e/main-navigation.spec.ts b/tests/e2e/main-navigation.spec.ts index 9fa24c7e..2ee0f717 100644 --- a/tests/e2e/main-navigation.spec.ts +++ b/tests/e2e/main-navigation.spec.ts @@ -376,7 +376,7 @@ test.describe('Makelore module navigation without setup flow', () => { } }); - test('opens remembered Code projects and keeps the module return entry in chat instead of project settings', async ({ + test('opens remembered Code projects and keeps shared Code sidebar chrome in settings', async ({ electronTestResources, launchElectronApp, }) => { @@ -435,10 +435,11 @@ test.describe('Makelore module navigation without setup flow', () => { const communityBox = await community.boundingBox(); const createBox = await sidebar.getByTestId('sidebar-create-project').boundingBox(); const headingBox = await sidebar.locator('.classroom-projects-heading').boundingBox(); - expect(communityBox!.y).toBeGreaterThanOrEqual(brandBox!.y + brandBox!.height); - expect(communityBox!.y - brandBox!.y - brandBox!.height).toBe(10); - expect(createBox!.y - communityBox!.y - communityBox!.height).toBe(10); - expect(createBox!.y - brandBox!.y - brandBox!.height).toBe(communityBox!.height + 20); + const accountBox = await sidebar.getByTestId('sidebar-member-menu-trigger').boundingBox(); + expect(createBox!.y - brandBox!.y - brandBox!.height).toBe(10); + expect(communityBox!.x).toBe(createBox!.x); + expect(communityBox!.y).toBeGreaterThan(headingBox!.y + headingBox!.height); + expect(accountBox!.y - communityBox!.y - communityBox!.height).toBeCloseTo(0, 0); expect(communityBox!.height).toBe(createBox!.height); await expect(community).toHaveCSS('background-color', 'rgba(0, 0, 0, 0)'); const buttonStyles = await page.evaluate(() => { @@ -484,14 +485,76 @@ test.describe('Makelore module navigation without setup flow', () => { await sidebarResizer.dblclick(); await expect(sidebarResizer).toHaveAttribute('aria-valuenow', '171'); - await sidebar.getByRole('button', { name: '项目操作:故事绘本', exact: true }).click(); - await page.getByRole('menuitem', { name: '项目设置', exact: true }).click(); - await expect(page).toHaveURL(/\/project-config$/); + const readCodeChrome = () => page.evaluate(() => { + const selectors = { + sidebar: '[data-testid="sidebar"]', + titlebar: '[data-testid="titlebar-sidebar-surface"]', + navigation: '[data-testid="classroom-titlebar-navigation"]', + home: '[data-testid="sidebar-module-switcher-trigger"]', + toggle: '[data-testid="titlebar-sidebar-toggle"]', + brand: '[data-testid="sidebar"] .classroom-brand', + create: '[data-testid="sidebar-create-project"]', + heading: '[data-testid="sidebar"] .classroom-projects-heading', + community: '[data-testid="sidebar"] .community-link[data-variant="sidebar"]', + communityIcon: '[data-testid="sidebar"] .community-link-icon', + account: '[data-testid="sidebar-member-menu-trigger"]', + }; + return Object.fromEntries(Object.entries(selectors).map(([name, selector]) => { + const element = document.querySelector(selector); + if (!element) throw new Error('Code chrome element missing: ' + name); + const bounds = element.getBoundingClientRect(); + const style = getComputedStyle(element); + const svg = element.querySelector('svg'); + return [name, { + x: Number(bounds.x.toFixed(1)), y: Number(bounds.y.toFixed(1)), + width: Number(bounds.width.toFixed(1)), height: Number(bounds.height.toFixed(1)), + // The titlebar surface is empty chrome; its inherited text color + // belongs to the route's content theme and paints no text or icons. + color: name === 'titlebar' ? null : style.color, + background: style.backgroundColor, border: style.borderTopColor, + radius: style.borderRadius, padding: style.padding, + iconWidth: svg ? Number(svg.getBoundingClientRect().width.toFixed(1)) : null, + iconStroke: svg?.getAttribute('stroke-width') ?? null, + }]; + })); + }); + // Create local metadata only; no prompt is sent and no model runs. + await sidebar.getByRole('button', { name: '新建对话', exact: true }).click(); + const conversationActions = sidebar.getByRole('button', { name: '对话操作:新对话', exact: true }).first(); + await expect(conversationActions).toBeAttached(); + await page.mouse.move(1000, 500); + const chatChrome = await readCodeChrome(); + await conversationActions.hover(); + await conversationActions.click(); + await page.getByRole('menuitem', { name: '会话编程设置', exact: true }).click(); + await expect(page).toHaveURL(/\/project-config\?agent=/); await expect(page.getByTestId('project-configuration-page')).toBeVisible(); - await expect(sidebar.getByTestId('sidebar-module-switcher')).toHaveCount(0); + await expect(moduleReturn).toBeVisible(); const projectBack = page.getByTestId('project-configuration-back-button'); await expect(projectBack).toBeVisible(); - await page.screenshot({ path: test.info().outputPath('project-config-without-module-return.png') }); + await page.mouse.move(1000, 500); + await expect.poll(readCodeChrome).toEqual(chatChrome); + await expect(sidebar).toHaveCSS('background-color', 'rgb(243, 247, 251)'); + const prompt = page.getByLabel('项目提示词', { exact: true }); + await expect(prompt).toBeVisible(); + const originalPrompt = await prompt.inputValue(); + await page.screenshot({ path: test.info().outputPath('project-config-shared-code-sidebar.png') }); + + // Reload directly on the settings URL, without mounting /chat first. + await page.reload({ waitUntil: 'domcontentloaded' }); + await expect(page).toHaveURL(/\/project-config\?agent=/); + await expect(page.getByTestId('project-configuration-page')).toBeVisible(); + await expect.poll(readCodeChrome).toEqual(chatChrome); + const sidebarToggle = page.getByTestId('titlebar-sidebar-toggle'); + await sidebarToggle.click(); + await page.getByTestId('project-configuration-page').click({ position: { x: 500, y: 20 } }); + await expect(sidebar).toHaveAttribute('aria-hidden', 'true'); + await expect(moduleReturn).toBeVisible(); + await sidebarToggle.click(); + await page.mouse.move(1000, 500); + await expect(sidebar).toHaveAttribute('aria-hidden', 'false'); + await expect.poll(readCodeChrome).toEqual(chatChrome); + await expect(prompt).toHaveValue(originalPrompt); await projectBack.click(); await expect(page).toHaveURL(/\/chat$/); await expect(moduleReturn).toBeVisible(); @@ -502,8 +565,9 @@ test.describe('Makelore module navigation without setup flow', () => { await expect(page).toHaveURL(/\/project-config\/plugins\?/); const plugins = page.getByTestId('project-plugins-sheet'); await expect(plugins).toBeVisible(); - await expect(sidebar.getByTestId('sidebar-module-switcher')).toHaveCount(0); - await page.screenshot({ path: test.info().outputPath('project-config-plugins-without-module-return.png') }); + await expect(moduleReturn).toBeVisible(); + await expect.poll(readCodeChrome).toEqual(chatChrome); + await page.screenshot({ path: test.info().outputPath('project-config-plugins-shared-code-sidebar.png') }); await plugins.getByRole('button', { name: '关闭', exact: true }).click(); await expect(page).toHaveURL(/\/project-config(?:\?|$)/); await expect(plugins).toHaveCount(0); @@ -512,7 +576,6 @@ test.describe('Makelore module navigation without setup flow', () => { await sidebar.getByTestId('sidebar-course-project-project-storybook').click(); await expect(page).toHaveURL(/\/chat$/); - const sidebarToggle = page.getByTestId('titlebar-sidebar-toggle'); await sidebarToggle.click(); await page.getByTestId('coding-chat-panel').click({ position: { x: 500, y: 200 } }); await expect(sidebar).toHaveAttribute('aria-hidden', 'true');