Download packages/cli/src/ui/components/messages/ToolMessageFocusHint.test.tsx from SaylorTwift/gemini-cli: direct link, hf CLI and curl.
- Browser
- Download file 3.97 kB
-
https://huggingface.co/SaylorTwift/gemini-cli/resolve/main/packages/cli/src/ui/components/messages/ToolMessageFocusHint.test.tsx
- Command line
-
hf download hf://SaylorTwift/gemini-cli/packages/cli/src/ui/components/messages/ToolMessageFocusHint.test.tsx
-
curl -L -o ToolMessageFocusHint.test.tsx https://huggingface.co/SaylorTwift/gemini-cli/resolve/main/packages/cli/src/ui/components/messages/ToolMessageFocusHint.test.tsx
3.97 kB
| /** | |
| * @license | |
| * Copyright 2025 Google LLC | |
| * SPDX-License-Identifier: Apache-2.0 | |
| */ | |
| import { act } from 'react'; | |
| import { ToolMessage } from './ToolMessage.js'; | |
| import { ShellToolMessage } from './ShellToolMessage.js'; | |
| import { StreamingState } from '../../types.js'; | |
| import { renderWithProviders } from '../../../test-utils/render.js'; | |
| import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; | |
| import { | |
| SHELL_COMMAND_NAME, | |
| SHELL_FOCUS_HINT_DELAY_MS, | |
| } from '../../constants.js'; | |
| import { | |
| type Config, | |
| type ToolResultDisplay, | |
| CoreToolCallStatus, | |
| } from '@google/gemini-cli-core'; | |
| vi.mock('../GeminiRespondingSpinner.js', () => ({ | |
| GeminiRespondingSpinner: () => null, | |
| })); | |
| vi.mock('./ToolResultDisplay.js', () => ({ | |
| ToolResultDisplay: () => null, | |
| })); | |
| describe('Focus Hint', () => { | |
| const mockConfig = { | |
| getEnableInteractiveShell: () => true, | |
| } as Config; | |
| const baseProps = { | |
| callId: 'tool-123', | |
| name: SHELL_COMMAND_NAME, | |
| description: 'A tool for testing', | |
| resultDisplay: undefined as ToolResultDisplay | undefined, | |
| status: CoreToolCallStatus.Executing, | |
| terminalWidth: 80, | |
| confirmationDetails: undefined, | |
| emphasis: 'medium' as const, | |
| isFirst: true, | |
| borderColor: 'green', | |
| borderDimColor: false, | |
| config: mockConfig, | |
| ptyId: 1, | |
| activeShellPtyId: 1, | |
| }; | |
| beforeEach(() => { | |
| vi.useFakeTimers(); | |
| }); | |
| afterEach(() => { | |
| vi.restoreAllMocks(); | |
| vi.useRealTimers(); | |
| }); | |
| const testCases = [ | |
| { Component: ToolMessage, componentName: 'ToolMessage' }, | |
| { Component: ShellToolMessage, componentName: 'ShellToolMessage' }, | |
| ]; | |
| describe.each(testCases)('$componentName', ({ Component }) => { | |
| it('shows focus hint after delay even with NO output', async () => { | |
| const { lastFrame, waitUntilReady, unmount } = await renderWithProviders( | |
| <Component {...baseProps} resultDisplay={undefined} />, | |
| { uiState: { streamingState: StreamingState.Idle } }, | |
| ); | |
| // Initially, no focus hint | |
| expect(lastFrame()).toMatchSnapshot('initial-no-output'); | |
| // Advance timers by the delay | |
| await act(async () => { | |
| vi.advanceTimersByTime(SHELL_FOCUS_HINT_DELAY_MS + 100); | |
| }); | |
| await waitUntilReady(); | |
| // Now it SHOULD contain the focus hint | |
| expect(lastFrame()).toMatchSnapshot('after-delay-no-output'); | |
| expect(lastFrame()).toContain('(Tab to focus)'); | |
| unmount(); | |
| }); | |
| it('shows focus hint after delay with output', async () => { | |
| const { lastFrame, waitUntilReady, unmount } = await renderWithProviders( | |
| <Component {...baseProps} resultDisplay="Some output" />, | |
| { uiState: { streamingState: StreamingState.Idle } }, | |
| ); | |
| // Initially, no focus hint | |
| expect(lastFrame()).toMatchSnapshot('initial-with-output'); | |
| // Advance timers | |
| await act(async () => { | |
| vi.advanceTimersByTime(SHELL_FOCUS_HINT_DELAY_MS + 100); | |
| }); | |
| await waitUntilReady(); | |
| expect(lastFrame()).toMatchSnapshot('after-delay-with-output'); | |
| expect(lastFrame()).toContain('(Tab to focus)'); | |
| unmount(); | |
| }); | |
| }); | |
| it('handles long descriptions by shrinking them to show the focus hint', async () => { | |
| const longDescription = 'A'.repeat(100); | |
| const { lastFrame, waitUntilReady, unmount } = await renderWithProviders( | |
| <ToolMessage | |
| {...baseProps} | |
| description={longDescription} | |
| resultDisplay="output" | |
| />, | |
| { uiState: { streamingState: StreamingState.Idle } }, | |
| ); | |
| await act(async () => { | |
| vi.advanceTimersByTime(SHELL_FOCUS_HINT_DELAY_MS + 100); | |
| }); | |
| await waitUntilReady(); | |
| // The focus hint should be visible | |
| expect(lastFrame()).toMatchSnapshot('long-description'); | |
| expect(lastFrame()).toContain('(Tab to focus)'); | |
| // The name should still be visible | |
| expect(lastFrame()).toContain(SHELL_COMMAND_NAME); | |
| unmount(); | |
| }); | |
| }); | |