Align Code navigation and branding with workspace header rows
This commit is contained in:
@@ -267,7 +267,7 @@ describe('PI-130 feature-complete Coding UI', () => {
|
||||
);
|
||||
|
||||
expect(screen.getByTestId('coding-conversation-header-titlebar')).toHaveClass('fixed', 'top-0', 'h-10');
|
||||
expect(screen.getByTestId('coding-conversation-header-titlebar')).toHaveStyle({ left: '132px' });
|
||||
expect(screen.getByTestId('coding-conversation-header-titlebar')).toHaveStyle({ left: '168px' });
|
||||
expect(screen.queryByTestId('coding-conversation-sidebar')).not.toBeInTheDocument();
|
||||
|
||||
window.electron.platform = originalPlatform;
|
||||
|
||||
@@ -1,8 +1,19 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { act, fireEvent, render, screen, waitFor } from '@testing-library/react';
|
||||
import type { ReactElement } from 'react';
|
||||
import { act, fireEvent, render as renderComponent, screen, waitFor } from '@testing-library/react';
|
||||
import { MemoryRouter, useLocation } from 'react-router-dom';
|
||||
import { TitleBar } from '@/components/layout/TitleBar';
|
||||
import { CodingConversationHeader } from '@/pages/Chat/CodingConversationHeader';
|
||||
import { useSettingsStore } from '@/stores/settings';
|
||||
|
||||
function render(ui: ReactElement) {
|
||||
return renderComponent(ui, { wrapper: ({ children }) => <MemoryRouter initialEntries={['/chat']}>{children}</MemoryRouter> });
|
||||
}
|
||||
|
||||
function LocationPath() {
|
||||
return <span data-testid="location-path">{useLocation().pathname}</span>;
|
||||
}
|
||||
|
||||
const invokeIpcMock = vi.hoisted(() => vi.fn());
|
||||
|
||||
vi.mock('@/lib/api-client', () => ({
|
||||
@@ -91,7 +102,10 @@ describe('TitleBar platform behavior', () => {
|
||||
expect(screen.queryByTestId('titlebar-logo')).not.toBeInTheDocument();
|
||||
expect(screen.queryByRole('img', { name: 'Makelore logo' })).not.toBeInTheDocument();
|
||||
expect(screen.queryByTestId('titlebar-project-context')).not.toBeInTheDocument();
|
||||
expect(screen.queryByRole('button', { name: '折叠侧栏' })).not.toBeInTheDocument();
|
||||
expect(screen.getByRole('button', { name: '折叠侧栏' })).toBeEnabled();
|
||||
expect(screen.getByRole('button', { name: '返回首页' })).toBeEnabled();
|
||||
expect(screen.getByTestId('classroom-titlebar-navigation')).toHaveClass('pl-[88px]');
|
||||
expect(screen.getByTestId('titlebar-sidebar-toggle')).toHaveClass('right-2');
|
||||
});
|
||||
|
||||
it('renders the painting title bar as a transparent overlay with the logo at the window edge', () => {
|
||||
@@ -179,14 +193,14 @@ describe('TitleBar platform behavior', () => {
|
||||
useSettingsStore.setState({ sidebarCollapsed: true });
|
||||
|
||||
const { rerender } = render(<TitleBar integrated workspaceLayout sidebarPeekOpen={false} />);
|
||||
expect(screen.getByTestId('titlebar-sidebar-surface')).toHaveClass('w-[132px]');
|
||||
expect(screen.getByTestId('titlebar-sidebar-surface')).toHaveStyle({ width: '168px' });
|
||||
expect(screen.queryByTestId('titlebar-conversation-surface')).not.toBeInTheDocument();
|
||||
expect(screen.queryByTestId('titlebar-logo')).not.toBeInTheDocument();
|
||||
expect(screen.getByRole('button', { name: '展开侧栏' })).toHaveAttribute('aria-expanded', 'false');
|
||||
|
||||
rerender(<TitleBar integrated workspaceLayout sidebarPeekOpen />);
|
||||
|
||||
expect(screen.getByTestId('titlebar-sidebar-surface')).toHaveClass('w-[132px]');
|
||||
expect(screen.getByTestId('titlebar-sidebar-surface')).toHaveStyle({ width: '168px' });
|
||||
expect(screen.queryByTestId('titlebar-conversation-surface')).not.toBeInTheDocument();
|
||||
expect(screen.queryByTestId('titlebar-logo')).not.toBeInTheDocument();
|
||||
const pinButton = screen.getByRole('button', { name: '固定侧栏' });
|
||||
@@ -195,7 +209,67 @@ describe('TitleBar platform behavior', () => {
|
||||
fireEvent.click(pinButton);
|
||||
expect(useSettingsStore.getState().sidebarCollapsed).toBe(false);
|
||||
expect(screen.getByTestId('titlebar-sidebar-surface')).toHaveStyle({ width: '171px', minWidth: '171px', flexBasis: '171px' });
|
||||
expect(screen.queryByRole('button', { name: '折叠侧栏' })).not.toBeInTheDocument();
|
||||
expect(screen.getByRole('button', { name: '折叠侧栏' })).toBeEnabled();
|
||||
});
|
||||
|
||||
it.each([
|
||||
['darwin', 168, 168, 'pl-[88px]'],
|
||||
['win32', 128, 88, 'pl-2'],
|
||||
] as const)('keeps both %s navigation controls outside the conversation header at narrow and collapsed widths', (platform, narrowWidth, collapsedWidth, insetClass) => {
|
||||
window.electron.platform = platform;
|
||||
useSettingsStore.setState({ classroomSidebarWidth: 128 });
|
||||
render(<>
|
||||
<TitleBar integrated workspaceLayout />
|
||||
<CodingConversationHeader conversation={null} snapshot={null} onRename={vi.fn()} onAbort={vi.fn()} onRecover={vi.fn()} />
|
||||
<LocationPath />
|
||||
</>);
|
||||
|
||||
const assertWidth = (width: number) => {
|
||||
expect(screen.getByTestId('titlebar-sidebar-surface')).toHaveStyle({ width: `${width}px` });
|
||||
expect(screen.getByTestId('titlebar-sidebar-toggle-layer')).toHaveStyle({ width: `${width}px` });
|
||||
expect(screen.getByTestId('coding-conversation-header-titlebar')).toHaveStyle({ left: `${width}px` });
|
||||
};
|
||||
assertWidth(narrowWidth);
|
||||
const rail = screen.getByTestId('classroom-titlebar-navigation');
|
||||
expect(rail).toHaveClass(insetClass);
|
||||
expect(rail).toContainElement(screen.getByRole('button', { name: '返回首页' }));
|
||||
expect(rail).toContainElement(screen.getByRole('button', { name: '折叠侧栏' }));
|
||||
expect(screen.getByRole('button', { name: '返回首页' })).toHaveTextContent('');
|
||||
expect(screen.getAllByTestId('titlebar-sidebar-toggle')).toHaveLength(1);
|
||||
|
||||
act(() => useSettingsStore.setState({ classroomSidebarWidth: 256 }));
|
||||
assertWidth(256);
|
||||
fireEvent.click(screen.getByRole('button', { name: '折叠侧栏' }));
|
||||
assertWidth(collapsedWidth);
|
||||
fireEvent.click(screen.getByRole('button', { name: '返回首页' }));
|
||||
expect(screen.getByTestId('location-path')).toHaveTextContent('/module-select');
|
||||
});
|
||||
|
||||
it('preserves keyboard preview when focus moves between the classroom controls', () => {
|
||||
window.electron.platform = 'darwin';
|
||||
useSettingsStore.setState({ sidebarCollapsed: true });
|
||||
const onSidebarPeekChange = vi.fn();
|
||||
render(<>
|
||||
<TitleBar integrated workspaceLayout sidebarPeekOpen onSidebarPeekChange={onSidebarPeekChange} />
|
||||
<button type="button">Outside navigation</button>
|
||||
</>);
|
||||
const toggle = screen.getByRole('button', { name: '固定侧栏' });
|
||||
const back = screen.getByRole('button', { name: '返回首页' });
|
||||
act(() => toggle.focus());
|
||||
expect(onSidebarPeekChange).toHaveBeenLastCalledWith(true, 'focus');
|
||||
onSidebarPeekChange.mockClear();
|
||||
act(() => back.focus());
|
||||
expect(onSidebarPeekChange).not.toHaveBeenCalledWith(false, 'focus');
|
||||
expect(onSidebarPeekChange).toHaveBeenLastCalledWith(true, 'focus');
|
||||
act(() => screen.getByRole('button', { name: 'Outside navigation' }).focus());
|
||||
expect(onSidebarPeekChange).toHaveBeenLastCalledWith(false, 'focus');
|
||||
|
||||
const layer = screen.getByTestId('titlebar-sidebar-toggle-layer');
|
||||
fireEvent.pointerEnter(layer);
|
||||
fireEvent.pointerLeave(layer);
|
||||
expect(onSidebarPeekChange).toHaveBeenCalledWith(true, 'titlebar');
|
||||
expect(onSidebarPeekChange).toHaveBeenLastCalledWith(false, 'titlebar');
|
||||
expect(layer).toHaveStyle({ width: '168px' });
|
||||
});
|
||||
|
||||
it('extends the ordinary titlebar sidebar surface during a hover preview', () => {
|
||||
|
||||
Reference in New Issue
Block a user