收口 Makelore 客户端变更
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { act, fireEvent, render, screen, waitFor } from '@testing-library/react';
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { AgentBrowserPanel } from '@/pages/Chat/AgentBrowserPanel';
|
||||
import { TitleBar } from '@/components/layout/TitleBar';
|
||||
import { deriveAgentBrowserDiagnostics } from '@/lib/agent-browser';
|
||||
import type {
|
||||
AgentBrowserCdpEvent,
|
||||
@@ -123,6 +124,10 @@ describe('AgentBrowserPanel', () => {
|
||||
beforeEach(() => {
|
||||
hostEventListeners.clear();
|
||||
resizeCallback = null;
|
||||
Object.defineProperty(document, 'elementsFromPoint', {
|
||||
configurable: true,
|
||||
value: vi.fn().mockReturnValue([]),
|
||||
});
|
||||
Object.defineProperty(window, 'ResizeObserver', {
|
||||
configurable: true,
|
||||
value: MockResizeObserver,
|
||||
@@ -144,6 +149,126 @@ describe('AgentBrowserPanel', () => {
|
||||
expect(screen.getByRole('button', { name: '打开开发浏览器' })).toBeDisabled();
|
||||
});
|
||||
|
||||
it('renders the collapsed toggle in the fixed titlebar layer', async () => {
|
||||
installBrowserApi(snapshot());
|
||||
render(<AgentBrowserPanel projectPath="D:/repo" />);
|
||||
|
||||
const titlebarToggle = await screen.findByTestId('agent-browser-titlebar-toggle');
|
||||
const button = titlebarToggle.querySelector('[data-testid="agent-browser-panel-open"]') as HTMLElement;
|
||||
expect(button).toHaveAttribute('aria-label', '打开开发浏览器');
|
||||
expect(button).toHaveClass('no-drag');
|
||||
expect(button).toHaveClass('bg-transparent');
|
||||
expect(button).not.toHaveClass('rounded-full');
|
||||
expect(screen.queryByTestId('agent-browser-panel')).not.toBeInTheDocument();
|
||||
|
||||
fireEvent.click(button);
|
||||
expect(await screen.findByTestId('agent-browser-panel')).toBeInTheDocument();
|
||||
fireEvent.click(titlebarToggle.querySelector('[data-testid="agent-browser-panel-open"]') as HTMLElement);
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByTestId('agent-browser-panel')).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('keeps the active browser indicator inside the titlebar toggle bounds', async () => {
|
||||
installBrowserApi(snapshot('attached'));
|
||||
render(<AgentBrowserPanel projectPath="D:/repo" />);
|
||||
|
||||
const titlebarToggle = await screen.findByTestId('agent-browser-titlebar-toggle');
|
||||
await waitFor(() => {
|
||||
expect(titlebarToggle.querySelector('span[aria-hidden="true"]')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
const indicator = titlebarToggle.querySelector('span[aria-hidden="true"]');
|
||||
expect(indicator).toHaveClass('absolute', 'right-2', 'top-2');
|
||||
expect(indicator).not.toHaveClass('right-0.5', 'top-0.5');
|
||||
});
|
||||
|
||||
it('keeps the toggle visible when mounted with the integrated titlebar', async () => {
|
||||
window.electron.platform = 'darwin';
|
||||
installBrowserApi(snapshot());
|
||||
|
||||
render(
|
||||
<>
|
||||
<TitleBar integrated />
|
||||
<AgentBrowserPanel projectPath="D:/repo" />
|
||||
</>,
|
||||
);
|
||||
|
||||
const titlebarToggle = await screen.findByTestId('agent-browser-titlebar-toggle');
|
||||
await waitFor(() => {
|
||||
expect(titlebarToggle.querySelector('[data-testid="agent-browser-panel-open"]')).toBeInTheDocument();
|
||||
});
|
||||
expect(titlebarToggle).toHaveClass('fixed', 'top-0', 'right-0', 'z-[100]', 'pointer-events-auto');
|
||||
expect(titlebarToggle).toHaveStyle({ right: '0px' });
|
||||
expect(document.documentElement.style.getPropertyValue('--agent-browser-titlebar-logo-gap')).toBe('');
|
||||
expect(screen.queryByTestId('agent-browser-panel-close')).not.toBeInTheDocument();
|
||||
|
||||
fireEvent.click(titlebarToggle.querySelector('[data-testid="agent-browser-panel-open"]') as HTMLElement);
|
||||
await waitFor(() => {
|
||||
expect(document.documentElement.style.getPropertyValue('--agent-browser-titlebar-logo-gap')).toBe('4px');
|
||||
});
|
||||
});
|
||||
|
||||
it('starts the browser at the same baseline width as the other workspace columns', async () => {
|
||||
installBrowserApi(snapshot());
|
||||
render(
|
||||
<div data-testid="opencode-chat-layout">
|
||||
<div data-testid="agent-conversation-sidebar" />
|
||||
<div data-testid="opencode-chat-canvas" />
|
||||
<AgentBrowserPanel projectPath="D:/repo" />
|
||||
</div>,
|
||||
);
|
||||
|
||||
vi.spyOn(screen.getByTestId('opencode-chat-layout'), 'getBoundingClientRect')
|
||||
.mockReturnValue({ width: 960 } as DOMRect);
|
||||
fireEvent.click(screen.getByTestId('agent-browser-panel-open'));
|
||||
|
||||
expect(await screen.findByTestId('agent-browser-panel')).toHaveStyle({ width: '320px' });
|
||||
expect(screen.getByTestId('agent-browser-panel-spacer')).toHaveStyle({ width: '320px' });
|
||||
});
|
||||
|
||||
it('keeps diagnostics collapsed and expands Console or Network upward from the bottom', async () => {
|
||||
installBrowserApi(snapshot());
|
||||
render(<AgentBrowserPanel projectPath="D:/repo" />);
|
||||
|
||||
fireEvent.click(screen.getByTestId('agent-browser-panel-open'));
|
||||
const diagnostics = await screen.findByTestId('agent-browser-diagnostics');
|
||||
const consoleTab = screen.getByRole('tab', { name: /Console/ });
|
||||
|
||||
expect(screen.queryByText('尚未开启')).not.toBeInTheDocument();
|
||||
expect(screen.queryByRole('button', { name: '开启 AI 调试' })).not.toBeInTheDocument();
|
||||
expect(screen.queryByRole('button', { name: '打开' })).not.toBeInTheDocument();
|
||||
expect(screen.queryByRole('button', { name: '清空调试记录' })).not.toBeInTheDocument();
|
||||
expect(diagnostics).toHaveAttribute('data-state', 'closed');
|
||||
expect(diagnostics).toHaveStyle({ height: '42px' });
|
||||
expect(consoleTab).toHaveAttribute('aria-expanded', 'false');
|
||||
expect(screen.queryByTestId('agent-browser-diagnostics-resize-handle')).not.toBeInTheDocument();
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: '展开调试面板' }));
|
||||
expect(diagnostics).toHaveAttribute('data-state', 'open');
|
||||
fireEvent.click(screen.getByRole('button', { name: '收起调试面板' }));
|
||||
expect(diagnostics).toHaveAttribute('data-state', 'closed');
|
||||
|
||||
fireEvent.click(consoleTab);
|
||||
expect(diagnostics).toHaveAttribute('data-state', 'open');
|
||||
expect(diagnostics).toHaveStyle({ height: '260px' });
|
||||
expect(consoleTab).toHaveAttribute('aria-expanded', 'true');
|
||||
expect(screen.getByTestId('agent-browser-diagnostics-resize-handle')).toBeInTheDocument();
|
||||
|
||||
fireEvent.click(screen.getByRole('tab', { name: /Network/ }));
|
||||
expect(screen.getByLabelText('Network 请求')).toBeInTheDocument();
|
||||
|
||||
const resizeHandle = screen.getByTestId('agent-browser-diagnostics-resize-handle');
|
||||
fireEvent.pointerDown(resizeHandle, { button: 0, clientY: 500, pointerId: 1 });
|
||||
fireEvent.pointerMove(resizeHandle, { clientY: 420, pointerId: 1 });
|
||||
expect(diagnostics).toHaveStyle({ height: '340px' });
|
||||
fireEvent.pointerUp(resizeHandle, { pointerId: 1 });
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: '收起调试面板' }));
|
||||
expect(diagnostics).toHaveAttribute('data-state', 'closed');
|
||||
expect(diagnostics).toHaveStyle({ height: '42px' });
|
||||
});
|
||||
|
||||
it('keeps bounded placeholders for oversized Console and Network events', () => {
|
||||
const diagnostics = deriveAgentBrowserDiagnostics([
|
||||
{
|
||||
@@ -231,7 +356,7 @@ describe('AgentBrowserPanel', () => {
|
||||
fireEvent.change(screen.getByRole('textbox', { name: '网页地址' }), {
|
||||
target: { value: 'localhost:4173' },
|
||||
});
|
||||
fireEvent.click(screen.getByRole('button', { name: '打开' }));
|
||||
fireEvent.submit(screen.getByRole('textbox', { name: '网页地址' }).closest('form') as HTMLFormElement);
|
||||
|
||||
await waitFor(() => {
|
||||
const call = hostApiFetchMock.mock.calls.find(
|
||||
@@ -248,7 +373,20 @@ describe('AgentBrowserPanel', () => {
|
||||
expect(window.devicePixelRatio).toBe(2);
|
||||
});
|
||||
|
||||
it('expands when the agent opens the shared browser', async () => {
|
||||
it('does not invent a URL when the address field is empty', async () => {
|
||||
installBrowserApi(snapshot());
|
||||
render(<AgentBrowserPanel projectPath="D:/repo" />);
|
||||
|
||||
fireEvent.click(screen.getByTestId('agent-browser-panel-open'));
|
||||
const addressInput = screen.getByRole('textbox', { name: '网页地址' });
|
||||
expect(addressInput).toHaveValue('');
|
||||
fireEvent.submit(addressInput.closest('form') as HTMLFormElement);
|
||||
|
||||
await new Promise((resolve) => window.setTimeout(resolve, 0));
|
||||
expect(hostApiFetchMock.mock.calls.some(([path]) => path === '/api/agent-browser/open')).toBe(false);
|
||||
});
|
||||
|
||||
it('keeps the panel collapsed when the agent opens the shared browser', async () => {
|
||||
installBrowserApi(snapshot('attached'));
|
||||
render(<AgentBrowserPanel projectId="project-1" projectPath="D:/repo" />);
|
||||
|
||||
@@ -257,8 +395,13 @@ describe('AgentBrowserPanel', () => {
|
||||
hostEventListeners.get('agent-browser:show')?.(snapshot('attached'));
|
||||
});
|
||||
|
||||
expect(screen.queryByTestId('agent-browser-panel')).not.toBeInTheDocument();
|
||||
expect(screen.getByTestId('agent-browser-panel-open')).toHaveAttribute(
|
||||
'title',
|
||||
'开发浏览器已收起,AI 调试已暂停',
|
||||
);
|
||||
fireEvent.click(screen.getByTestId('agent-browser-panel-open'));
|
||||
expect(await screen.findByTestId('agent-browser-panel')).toBeInTheDocument();
|
||||
expect(screen.getByTestId('agent-browser-debug-status')).toHaveTextContent('AI 可调试');
|
||||
});
|
||||
|
||||
it('ignores a delayed show event from the previous project', () => {
|
||||
@@ -277,12 +420,14 @@ describe('AgentBrowserPanel', () => {
|
||||
expect(screen.queryByTestId('agent-browser-panel')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('restores an already active shared browser after remounting', async () => {
|
||||
it('restores an already active shared browser without expanding the panel', async () => {
|
||||
installBrowserApi(snapshot('attached'));
|
||||
render(<AgentBrowserPanel projectId="project-1" projectPath="D:/repo" />);
|
||||
|
||||
expect(await screen.findByTestId('agent-browser-panel-open')).toBeInTheDocument();
|
||||
expect(screen.queryByTestId('agent-browser-panel')).not.toBeInTheDocument();
|
||||
fireEvent.click(screen.getByTestId('agent-browser-panel-open'));
|
||||
expect(await screen.findByTestId('agent-browser-panel')).toBeInTheDocument();
|
||||
expect(screen.getByTestId('agent-browser-debug-status')).toHaveTextContent('AI 可调试');
|
||||
});
|
||||
|
||||
it('updates native view bounds and hides it when collapsed', async () => {
|
||||
@@ -290,7 +435,6 @@ describe('AgentBrowserPanel', () => {
|
||||
render(<AgentBrowserPanel projectPath="D:/repo" />);
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: '打开开发浏览器' }));
|
||||
expect(await screen.findByText('AI 可调试')).toBeInTheDocument();
|
||||
const viewport = screen.getByTestId('agent-browser-viewport');
|
||||
vi.spyOn(viewport, 'getBoundingClientRect').mockReturnValue({
|
||||
x: 240,
|
||||
@@ -324,10 +468,51 @@ describe('AgentBrowserPanel', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('resizes the panel from its left edge and auto-collapses below the threshold', async () => {
|
||||
installBrowserApi(snapshot('attached'));
|
||||
render(<AgentBrowserPanel projectPath="D:/repo" />);
|
||||
|
||||
fireEvent.click(screen.getByTestId('agent-browser-panel-open'));
|
||||
const panel = await screen.findByTestId('agent-browser-panel');
|
||||
const handle = screen.getByTestId('agent-browser-panel-resize-handle');
|
||||
const panelRect = vi.spyOn(panel, 'getBoundingClientRect');
|
||||
panelRect.mockReturnValue({ width: 440 } as DOMRect);
|
||||
vi.spyOn(panel.parentElement as HTMLElement, 'getBoundingClientRect').mockReturnValue({
|
||||
width: 1200,
|
||||
} as DOMRect);
|
||||
|
||||
fireEvent.pointerDown(handle, {
|
||||
button: 0,
|
||||
clientX: 600,
|
||||
pointerId: 1,
|
||||
});
|
||||
fireEvent.pointerMove(handle, {
|
||||
clientX: 440,
|
||||
pointerId: 1,
|
||||
});
|
||||
expect(panel).toHaveStyle({ width: '600px' });
|
||||
|
||||
panelRect.mockReturnValue({ width: 600 } as DOMRect);
|
||||
fireEvent.pointerDown(handle, {
|
||||
button: 0,
|
||||
clientX: 600,
|
||||
pointerId: 2,
|
||||
});
|
||||
fireEvent.pointerMove(handle, {
|
||||
clientX: 950,
|
||||
pointerId: 2,
|
||||
});
|
||||
|
||||
expect(screen.getByTestId('agent-browser-panel')).toHaveAttribute('data-state', 'closed');
|
||||
await waitFor(() => expect(screen.queryByTestId('agent-browser-panel')).not.toBeInTheDocument());
|
||||
expect(screen.getByTestId('agent-browser-panel-open')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('hides the native view while a renderer modal is open', async () => {
|
||||
installBrowserApi(snapshot('attached'));
|
||||
render(<AgentBrowserPanel projectPath="D:/repo" />);
|
||||
|
||||
fireEvent.click(screen.getByTestId('agent-browser-panel-open'));
|
||||
const viewport = await screen.findByTestId('agent-browser-viewport');
|
||||
vi.spyOn(viewport, 'getBoundingClientRect').mockReturnValue({
|
||||
x: 240,
|
||||
@@ -420,6 +605,7 @@ describe('AgentBrowserPanel', () => {
|
||||
render(<AgentBrowserPanel projectPath="D:/repo" />);
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: '打开开发浏览器' }));
|
||||
fireEvent.click(screen.getByRole('tab', { name: /Console/ }));
|
||||
expect(await screen.findByText('ready')).toBeInTheDocument();
|
||||
|
||||
fireEvent.click(screen.getByRole('tab', { name: /Network/ }));
|
||||
|
||||
Reference in New Issue
Block a user