收口 Makelore 客户端变更
Some checks failed
Electron E2E / Electron E2E (macos-latest) (push) Has been cancelled
Electron E2E / Electron E2E (ubuntu-latest) (push) Has been cancelled
Electron E2E / Electron E2E (windows-latest) (push) Has been cancelled

This commit is contained in:
inman
2026-08-12 22:35:06 +08:00
parent 253bad8b40
commit f4113a872f
232 changed files with 4617 additions and 20121 deletions

View File

@@ -0,0 +1,143 @@
import { act, fireEvent, render, screen } from '@testing-library/react';
import { MemoryRouter, Route, Routes } from 'react-router-dom';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { MainLayout } from '@/components/layout/MainLayout';
import { useOpencodeStore } from '@/stores/opencode';
import { useSettingsStore } from '@/stores/settings';
type PeekProps = {
sidebarPeekOpen?: boolean;
onSidebarPeekChange?: (open: boolean, source: 'toggle' | 'focus' | 'sidebar' | 'titlebar') => void;
};
vi.mock('@/components/layout/TitleBar', () => ({
TitleBar: ({ sidebarPeekOpen, onSidebarPeekChange }: PeekProps) => (
<>
<button
type="button"
data-testid="peek-trigger"
data-peek-open={sidebarPeekOpen ? 'true' : 'false'}
onPointerEnter={() => onSidebarPeekChange?.(true, 'toggle')}
onPointerLeave={() => onSidebarPeekChange?.(false, 'toggle')}
/>
<div
data-testid="peek-titlebar"
onPointerEnter={() => onSidebarPeekChange?.(true, 'titlebar')}
onPointerLeave={() => onSidebarPeekChange?.(false, 'titlebar')}
/>
</>
),
}));
vi.mock('@/components/layout/Sidebar', () => ({
Sidebar: ({ sidebarPeekOpen, onSidebarPeekChange }: PeekProps) => (
<aside
data-testid="peek-sidebar"
data-peek-open={sidebarPeekOpen ? 'true' : 'false'}
onPointerEnter={() => onSidebarPeekChange?.(true, 'sidebar')}
onPointerLeave={() => onSidebarPeekChange?.(false, 'sidebar')}
/>
),
}));
function renderLayout() {
render(
<MemoryRouter initialEntries={['/opencode-chat']}>
<Routes>
<Route element={<MainLayout />}>
<Route path="*" element={null} />
</Route>
</Routes>
</MemoryRouter>,
);
}
describe('MainLayout sidebar hover preview', () => {
beforeEach(() => {
vi.useFakeTimers();
useSettingsStore.setState({ sidebarCollapsed: true });
useOpencodeStore.setState({ activeProject: null });
});
afterEach(() => {
vi.useRealTimers();
});
it('does not close while the pointer moves from the toggle into the preview', () => {
renderLayout();
const trigger = screen.getByTestId('peek-trigger');
const sidebar = screen.getByTestId('peek-sidebar');
fireEvent.pointerEnter(trigger);
expect(trigger).toHaveAttribute('data-peek-open', 'true');
fireEvent.pointerLeave(trigger);
fireEvent.pointerEnter(sidebar);
act(() => {
vi.advanceTimersByTime(180);
});
expect(sidebar).toHaveAttribute('data-peek-open', 'true');
fireEvent.pointerLeave(sidebar);
act(() => {
vi.advanceTimersByTime(179);
});
expect(sidebar).toHaveAttribute('data-peek-open', 'true');
act(() => {
vi.advanceTimersByTime(1);
});
expect(sidebar).toHaveAttribute('data-peek-open', 'false');
});
it('keeps the preview open while the pointer crosses the expanded titlebar surface', () => {
renderLayout();
const trigger = screen.getByTestId('peek-trigger');
const titlebar = screen.getByTestId('peek-titlebar');
fireEvent.pointerEnter(trigger);
fireEvent.pointerLeave(trigger);
fireEvent.pointerEnter(titlebar);
act(() => vi.advanceTimersByTime(180));
expect(screen.getByTestId('peek-trigger')).toHaveAttribute('data-peek-open', 'true');
fireEvent.pointerLeave(titlebar);
act(() => vi.advanceTimersByTime(180));
expect(screen.getByTestId('peek-trigger')).toHaveAttribute('data-peek-open', 'false');
});
it('closes once after leaving the only hover zone', () => {
renderLayout();
const trigger = screen.getByTestId('peek-trigger');
fireEvent.pointerEnter(trigger);
fireEvent.pointerLeave(trigger);
act(() => {
vi.advanceTimersByTime(179);
});
expect(trigger).toHaveAttribute('data-peek-open', 'true');
act(() => {
vi.advanceTimersByTime(1);
});
expect(trigger).toHaveAttribute('data-peek-open', 'false');
});
it('treats repeated pointer-enter notifications as one hover source', () => {
renderLayout();
const trigger = screen.getByTestId('peek-trigger');
fireEvent.pointerEnter(trigger);
fireEvent.pointerEnter(trigger);
fireEvent.pointerLeave(trigger);
fireEvent.pointerLeave(trigger);
act(() => {
vi.advanceTimersByTime(180);
});
expect(trigger).toHaveAttribute('data-peek-open', 'false');
});
});