mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-04-26 04:54:25 -07:00
feat(cli): enable mouse clicking for cursor positioning in AskUser multi-line answers (#24630)
This commit is contained in:
@@ -4,7 +4,8 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { describe, it, expect, vi, beforeEach, type Mock } from 'vitest';
|
||||
import { act } from 'react';
|
||||
import { renderWithProviders } from '../../../test-utils/render.js';
|
||||
import {
|
||||
BaseSelectionList,
|
||||
@@ -14,8 +15,10 @@ import {
|
||||
import { useSelectionList } from '../../hooks/useSelectionList.js';
|
||||
import { Text } from 'ink';
|
||||
import type { theme } from '../../semantic-colors.js';
|
||||
import { useMouseClick } from '../../hooks/useMouseClick.js';
|
||||
|
||||
vi.mock('../../hooks/useSelectionList.js');
|
||||
vi.mock('../../hooks/useMouseClick.js');
|
||||
|
||||
const mockTheme = {
|
||||
text: { primary: 'COLOR_PRIMARY', secondary: 'COLOR_SECONDARY' },
|
||||
@@ -35,6 +38,7 @@ describe('BaseSelectionList', () => {
|
||||
const mockOnSelect = vi.fn();
|
||||
const mockOnHighlight = vi.fn();
|
||||
const mockRenderItem = vi.fn();
|
||||
const mockSetActiveIndex = vi.fn();
|
||||
|
||||
const items = [
|
||||
{ value: 'A', label: 'Item A', key: 'A' },
|
||||
@@ -54,7 +58,7 @@ describe('BaseSelectionList', () => {
|
||||
) => {
|
||||
vi.mocked(useSelectionList).mockReturnValue({
|
||||
activeIndex,
|
||||
setActiveIndex: vi.fn(),
|
||||
setActiveIndex: mockSetActiveIndex,
|
||||
});
|
||||
|
||||
mockRenderItem.mockImplementation(
|
||||
@@ -484,6 +488,79 @@ describe('BaseSelectionList', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Mouse Interaction', () => {
|
||||
it('should register mouse click handler for each item', async () => {
|
||||
const { unmount } = await renderComponent();
|
||||
|
||||
// items are A, B (disabled), C
|
||||
expect(useMouseClick).toHaveBeenCalledTimes(3);
|
||||
unmount();
|
||||
});
|
||||
|
||||
it('should update activeIndex on first click and call onSelect on second click', async () => {
|
||||
const { unmount, waitUntilReady } = await renderComponent();
|
||||
await waitUntilReady();
|
||||
|
||||
// items[0] is 'A' (enabled)
|
||||
// items[1] is 'B' (disabled)
|
||||
// items[2] is 'C' (enabled)
|
||||
|
||||
// Get the mouse click handler for the third item (index 2)
|
||||
const mouseClickHandler = (useMouseClick as Mock).mock.calls[2][1];
|
||||
|
||||
// First click on item C
|
||||
act(() => {
|
||||
mouseClickHandler();
|
||||
});
|
||||
|
||||
expect(mockSetActiveIndex).toHaveBeenCalledWith(2);
|
||||
expect(mockOnSelect).not.toHaveBeenCalled();
|
||||
|
||||
// Now simulate being on item C (isSelected = true)
|
||||
// Rerender or update mocks for the next check
|
||||
await renderComponent({}, 2);
|
||||
|
||||
// Get the updated mouse click handler for item C
|
||||
// useMouseClick is called 3 more times on rerender
|
||||
const updatedMouseClickHandler = (useMouseClick as Mock).mock.calls[5][1];
|
||||
|
||||
// Second click on item C
|
||||
act(() => {
|
||||
updatedMouseClickHandler();
|
||||
});
|
||||
|
||||
expect(mockOnSelect).toHaveBeenCalledWith('C');
|
||||
unmount();
|
||||
});
|
||||
|
||||
it('should not call onSelect when a disabled item is clicked', async () => {
|
||||
const { unmount, waitUntilReady } = await renderComponent();
|
||||
await waitUntilReady();
|
||||
|
||||
// items[1] is 'B' (disabled)
|
||||
const mouseClickHandler = (useMouseClick as Mock).mock.calls[1][1];
|
||||
|
||||
act(() => {
|
||||
mouseClickHandler();
|
||||
});
|
||||
|
||||
expect(mockSetActiveIndex).not.toHaveBeenCalled();
|
||||
expect(mockOnSelect).not.toHaveBeenCalled();
|
||||
unmount();
|
||||
});
|
||||
|
||||
it('should pass isActive: isFocused to useMouseClick', async () => {
|
||||
const { unmount } = await renderComponent({ isFocused: false });
|
||||
|
||||
expect(useMouseClick).toHaveBeenCalledWith(
|
||||
expect.any(Object),
|
||||
expect.any(Function),
|
||||
{ isActive: false },
|
||||
);
|
||||
unmount();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Scroll Arrows (showScrollArrows)', () => {
|
||||
const longList = Array.from({ length: 10 }, (_, i) => ({
|
||||
value: `Item ${i + 1}`,
|
||||
|
||||
Reference in New Issue
Block a user