mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-08-08 16:11:58 -07:00
refactor(cli): simplify keypress and mouse providers and update tests (#22853)
This commit is contained in:
committed by
GitHub
parent
81a97e78f1
commit
d7dfcf7f99
@@ -4,21 +4,14 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { render } from '../../test-utils/render.js';
|
||||
import { renderWithProviders } from '../../test-utils/render.js';
|
||||
import { waitFor } from '../../test-utils/async.js';
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { act } from 'react';
|
||||
import { AgentConfigDialog } from './AgentConfigDialog.js';
|
||||
import { LoadedSettings, SettingScope } from '../../config/settings.js';
|
||||
import { KeypressProvider } from '../contexts/KeypressContext.js';
|
||||
import type { AgentDefinition } from '@google/gemini-cli-core';
|
||||
|
||||
vi.mock('../contexts/UIStateContext.js', () => ({
|
||||
useUIState: () => ({
|
||||
mainAreaWidth: 100,
|
||||
}),
|
||||
}));
|
||||
|
||||
enum TerminalKeys {
|
||||
ENTER = '\u000D',
|
||||
TAB = '\t',
|
||||
@@ -122,17 +115,16 @@ describe('AgentConfigDialog', () => {
|
||||
settings: LoadedSettings,
|
||||
definition: AgentDefinition = createMockAgentDefinition(),
|
||||
) => {
|
||||
const result = render(
|
||||
<KeypressProvider>
|
||||
<AgentConfigDialog
|
||||
agentName="test-agent"
|
||||
displayName="Test Agent"
|
||||
definition={definition}
|
||||
settings={settings}
|
||||
onClose={mockOnClose}
|
||||
onSave={mockOnSave}
|
||||
/>
|
||||
</KeypressProvider>,
|
||||
const result = renderWithProviders(
|
||||
<AgentConfigDialog
|
||||
agentName="test-agent"
|
||||
displayName="Test Agent"
|
||||
definition={definition}
|
||||
settings={settings}
|
||||
onClose={mockOnClose}
|
||||
onSave={mockOnSave}
|
||||
/>,
|
||||
{ settings, uiState: { mainAreaWidth: 100 } },
|
||||
);
|
||||
await result.waitUntilReady();
|
||||
return result;
|
||||
@@ -331,18 +323,17 @@ describe('AgentConfigDialog', () => {
|
||||
const settings = createMockSettings();
|
||||
// Agent config has about 6 base items + 2 per tool
|
||||
// Render with very small height (20)
|
||||
const { lastFrame, unmount } = render(
|
||||
<KeypressProvider>
|
||||
<AgentConfigDialog
|
||||
agentName="test-agent"
|
||||
displayName="Test Agent"
|
||||
definition={createMockAgentDefinition()}
|
||||
settings={settings}
|
||||
onClose={mockOnClose}
|
||||
onSave={mockOnSave}
|
||||
availableTerminalHeight={20}
|
||||
/>
|
||||
</KeypressProvider>,
|
||||
const { lastFrame, unmount } = renderWithProviders(
|
||||
<AgentConfigDialog
|
||||
agentName="test-agent"
|
||||
displayName="Test Agent"
|
||||
definition={createMockAgentDefinition()}
|
||||
settings={settings}
|
||||
onClose={mockOnClose}
|
||||
onSave={mockOnSave}
|
||||
availableTerminalHeight={20}
|
||||
/>,
|
||||
{ settings, uiState: { mainAreaWidth: 100 } },
|
||||
);
|
||||
await waitFor(() =>
|
||||
expect(lastFrame()).toContain('Configure: Test Agent'),
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
import { describe, it, expect, vi, afterEach, beforeEach } from 'vitest';
|
||||
import { act } from 'react';
|
||||
import { renderWithProviders } from '../../test-utils/render.js';
|
||||
import { createMockSettings } from '../../test-utils/settings.js';
|
||||
import { makeFakeConfig } from '@google/gemini-cli-core';
|
||||
import { waitFor } from '../../test-utils/async.js';
|
||||
import { AskUserDialog } from './AskUserDialog.js';
|
||||
import { QuestionType, type Question } from '@google/gemini-cli-core';
|
||||
@@ -313,7 +315,12 @@ describe('AskUserDialog', () => {
|
||||
width={80}
|
||||
availableHeight={10} // Small height to force scrolling
|
||||
/>,
|
||||
{ useAlternateBuffer },
|
||||
{
|
||||
config: makeFakeConfig({ useAlternateBuffer }),
|
||||
settings: createMockSettings({
|
||||
merged: { ui: { useAlternateBuffer } },
|
||||
}),
|
||||
},
|
||||
);
|
||||
|
||||
await waitFor(async () => {
|
||||
@@ -1291,7 +1298,12 @@ describe('AskUserDialog', () => {
|
||||
width={80}
|
||||
/>
|
||||
</UIStateContext.Provider>,
|
||||
{ useAlternateBuffer: false },
|
||||
{
|
||||
config: makeFakeConfig({ useAlternateBuffer: false }),
|
||||
settings: createMockSettings({
|
||||
merged: { ui: { useAlternateBuffer: false } },
|
||||
}),
|
||||
},
|
||||
);
|
||||
|
||||
// With height 5 and alternate buffer disabled, it should show scroll arrows (▲)
|
||||
@@ -1327,7 +1339,12 @@ describe('AskUserDialog', () => {
|
||||
width={40} // Small width to force wrapping
|
||||
/>
|
||||
</UIStateContext.Provider>,
|
||||
{ useAlternateBuffer: true },
|
||||
{
|
||||
config: makeFakeConfig({ useAlternateBuffer: true }),
|
||||
settings: createMockSettings({
|
||||
merged: { ui: { useAlternateBuffer: true } },
|
||||
}),
|
||||
},
|
||||
);
|
||||
|
||||
// Should NOT contain the truncation message
|
||||
|
||||
@@ -4,11 +4,10 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { render } from '../../test-utils/render.js';
|
||||
import { renderWithProviders } from '../../test-utils/render.js';
|
||||
import { EditorSettingsDialog } from './EditorSettingsDialog.js';
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { SettingScope, type LoadedSettings } from '../../config/settings.js';
|
||||
import { KeypressProvider } from '../contexts/KeypressContext.js';
|
||||
import { act } from 'react';
|
||||
import { waitFor } from '../../test-utils/async.js';
|
||||
import { debugLogger } from '@google/gemini-cli-core';
|
||||
@@ -52,8 +51,8 @@ describe('EditorSettingsDialog', () => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
const renderWithProvider = (ui: React.ReactNode) =>
|
||||
render(<KeypressProvider>{ui}</KeypressProvider>);
|
||||
const renderWithProvider = (ui: React.ReactElement) =>
|
||||
renderWithProviders(ui);
|
||||
|
||||
it('renders correctly', async () => {
|
||||
const { lastFrame, waitUntilReady } = renderWithProvider(
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
import { describe, it, expect, vi, afterEach, beforeEach } from 'vitest';
|
||||
import { act } from 'react';
|
||||
import { renderWithProviders } from '../../test-utils/render.js';
|
||||
import { createMockSettings } from '../../test-utils/settings.js';
|
||||
import { waitFor } from '../../test-utils/async.js';
|
||||
import { ExitPlanModeDialog } from './ExitPlanModeDialog.js';
|
||||
import { useKeypress } from '../hooks/useKeypress.js';
|
||||
@@ -138,8 +139,9 @@ Implement a comprehensive authentication system with multiple providers.
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
const renderDialog = (options?: { useAlternateBuffer?: boolean }) =>
|
||||
renderWithProviders(
|
||||
const renderDialog = (options?: { useAlternateBuffer?: boolean }) => {
|
||||
const useAlternateBuffer = options?.useAlternateBuffer ?? true;
|
||||
return renderWithProviders(
|
||||
<ExitPlanModeDialog
|
||||
planPath={mockPlanFullPath}
|
||||
onApprove={onApprove}
|
||||
@@ -163,10 +165,14 @@ Implement a comprehensive authentication system with multiple providers.
|
||||
readTextFile: vi.fn(),
|
||||
writeTextFile: vi.fn(),
|
||||
}),
|
||||
getUseAlternateBuffer: () => options?.useAlternateBuffer ?? true,
|
||||
getUseAlternateBuffer: () => useAlternateBuffer,
|
||||
} as unknown as import('@google/gemini-cli-core').Config,
|
||||
settings: createMockSettings({
|
||||
merged: { ui: { useAlternateBuffer } },
|
||||
}),
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
describe.each([{ useAlternateBuffer: true }, { useAlternateBuffer: false }])(
|
||||
'useAlternateBuffer: $useAlternateBuffer',
|
||||
@@ -429,7 +435,6 @@ Implement a comprehensive authentication system with multiple providers.
|
||||
/>
|
||||
</BubbleListener>,
|
||||
{
|
||||
useAlternateBuffer,
|
||||
config: {
|
||||
getTargetDir: () => mockTargetDir,
|
||||
getIdeMode: () => false,
|
||||
@@ -443,6 +448,11 @@ Implement a comprehensive authentication system with multiple providers.
|
||||
}),
|
||||
getUseAlternateBuffer: () => useAlternateBuffer ?? true,
|
||||
} as unknown as import('@google/gemini-cli-core').Config,
|
||||
settings: createMockSettings({
|
||||
merged: {
|
||||
ui: { useAlternateBuffer: useAlternateBuffer ?? true },
|
||||
},
|
||||
}),
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
@@ -5,11 +5,12 @@
|
||||
*/
|
||||
|
||||
import { renderWithProviders } from '../../test-utils/render.js';
|
||||
import { createMockSettings } from '../../test-utils/settings.js';
|
||||
import { makeFakeConfig, ExitCodes } from '@google/gemini-cli-core';
|
||||
import { waitFor } from '../../test-utils/async.js';
|
||||
import { act } from 'react';
|
||||
import { vi, describe, it, expect, beforeEach, afterEach } from 'vitest';
|
||||
import { FolderTrustDialog } from './FolderTrustDialog.js';
|
||||
import { ExitCodes } from '@google/gemini-cli-core';
|
||||
import * as processUtils from '../../utils/processUtils.js';
|
||||
|
||||
vi.mock('../../utils/processUtils.js', () => ({
|
||||
@@ -78,7 +79,10 @@ describe('FolderTrustDialog', () => {
|
||||
/>,
|
||||
{
|
||||
width: 80,
|
||||
useAlternateBuffer: false,
|
||||
config: makeFakeConfig({ useAlternateBuffer: false }),
|
||||
settings: createMockSettings({
|
||||
merged: { ui: { useAlternateBuffer: false } },
|
||||
}),
|
||||
uiState: { constrainHeight: true, terminalHeight: 24 },
|
||||
},
|
||||
);
|
||||
@@ -108,7 +112,10 @@ describe('FolderTrustDialog', () => {
|
||||
/>,
|
||||
{
|
||||
width: 80,
|
||||
useAlternateBuffer: false,
|
||||
config: makeFakeConfig({ useAlternateBuffer: false }),
|
||||
settings: createMockSettings({
|
||||
merged: { ui: { useAlternateBuffer: false } },
|
||||
}),
|
||||
uiState: { constrainHeight: true, terminalHeight: 14 },
|
||||
},
|
||||
);
|
||||
@@ -139,7 +146,10 @@ describe('FolderTrustDialog', () => {
|
||||
/>,
|
||||
{
|
||||
width: 80,
|
||||
useAlternateBuffer: false,
|
||||
config: makeFakeConfig({ useAlternateBuffer: false }),
|
||||
settings: createMockSettings({
|
||||
merged: { ui: { useAlternateBuffer: false } },
|
||||
}),
|
||||
uiState: { constrainHeight: true, terminalHeight: 10 },
|
||||
},
|
||||
);
|
||||
@@ -168,7 +178,10 @@ describe('FolderTrustDialog', () => {
|
||||
/>,
|
||||
{
|
||||
width: 80,
|
||||
useAlternateBuffer: false,
|
||||
config: makeFakeConfig({ useAlternateBuffer: false }),
|
||||
settings: createMockSettings({
|
||||
merged: { ui: { useAlternateBuffer: false } },
|
||||
}),
|
||||
// Initially constrained
|
||||
uiState: { constrainHeight: true, terminalHeight: 24 },
|
||||
},
|
||||
@@ -194,7 +207,10 @@ describe('FolderTrustDialog', () => {
|
||||
/>,
|
||||
{
|
||||
width: 80,
|
||||
useAlternateBuffer: false,
|
||||
config: makeFakeConfig({ useAlternateBuffer: false }),
|
||||
settings: createMockSettings({
|
||||
merged: { ui: { useAlternateBuffer: false } },
|
||||
}),
|
||||
uiState: { constrainHeight: false, terminalHeight: 24 },
|
||||
},
|
||||
);
|
||||
@@ -434,7 +450,10 @@ describe('FolderTrustDialog', () => {
|
||||
/>,
|
||||
{
|
||||
width: 80,
|
||||
useAlternateBuffer: true,
|
||||
config: makeFakeConfig({ useAlternateBuffer: true }),
|
||||
settings: createMockSettings({
|
||||
merged: { ui: { useAlternateBuffer: true } },
|
||||
}),
|
||||
uiState: { constrainHeight: false, terminalHeight: 15 },
|
||||
},
|
||||
);
|
||||
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
import { ToolGroupMessage } from './messages/ToolGroupMessage.js';
|
||||
import { renderWithProviders } from '../../test-utils/render.js';
|
||||
import { createMockSettings } from '../../test-utils/settings.js';
|
||||
import { makeFakeConfig } from '@google/gemini-cli-core';
|
||||
|
||||
// Mock child components
|
||||
vi.mock('./messages/ToolGroupMessage.js', () => ({
|
||||
@@ -84,7 +85,12 @@ describe('<HistoryItemDisplay />', () => {
|
||||
};
|
||||
const { lastFrame, waitUntilReady, unmount } = renderWithProviders(
|
||||
<HistoryItemDisplay {...baseItem} item={item} />,
|
||||
{ useAlternateBuffer },
|
||||
{
|
||||
config: makeFakeConfig({ useAlternateBuffer }),
|
||||
settings: createMockSettings({
|
||||
merged: { ui: { useAlternateBuffer } },
|
||||
}),
|
||||
},
|
||||
);
|
||||
await waitUntilReady();
|
||||
expect(lastFrame()).toMatchSnapshot();
|
||||
@@ -352,7 +358,12 @@ describe('<HistoryItemDisplay />', () => {
|
||||
terminalWidth={80}
|
||||
availableTerminalHeight={10}
|
||||
/>,
|
||||
{ useAlternateBuffer },
|
||||
{
|
||||
config: makeFakeConfig({ useAlternateBuffer }),
|
||||
settings: createMockSettings({
|
||||
merged: { ui: { useAlternateBuffer } },
|
||||
}),
|
||||
},
|
||||
);
|
||||
await waitUntilReady();
|
||||
|
||||
@@ -374,7 +385,12 @@ describe('<HistoryItemDisplay />', () => {
|
||||
availableTerminalHeight={10}
|
||||
availableTerminalHeightGemini={Number.MAX_SAFE_INTEGER}
|
||||
/>,
|
||||
{ useAlternateBuffer },
|
||||
{
|
||||
config: makeFakeConfig({ useAlternateBuffer }),
|
||||
settings: createMockSettings({
|
||||
merged: { ui: { useAlternateBuffer } },
|
||||
}),
|
||||
},
|
||||
);
|
||||
await waitUntilReady();
|
||||
|
||||
@@ -395,7 +411,12 @@ describe('<HistoryItemDisplay />', () => {
|
||||
terminalWidth={80}
|
||||
availableTerminalHeight={10}
|
||||
/>,
|
||||
{ useAlternateBuffer },
|
||||
{
|
||||
config: makeFakeConfig({ useAlternateBuffer }),
|
||||
settings: createMockSettings({
|
||||
merged: { ui: { useAlternateBuffer } },
|
||||
}),
|
||||
},
|
||||
);
|
||||
await waitUntilReady();
|
||||
|
||||
@@ -417,7 +438,12 @@ describe('<HistoryItemDisplay />', () => {
|
||||
availableTerminalHeight={10}
|
||||
availableTerminalHeightGemini={Number.MAX_SAFE_INTEGER}
|
||||
/>,
|
||||
{ useAlternateBuffer },
|
||||
{
|
||||
config: makeFakeConfig({ useAlternateBuffer }),
|
||||
settings: createMockSettings({
|
||||
merged: { ui: { useAlternateBuffer } },
|
||||
}),
|
||||
},
|
||||
);
|
||||
await waitUntilReady();
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
import { renderWithProviders } from '../../test-utils/render.js';
|
||||
import { createMockSettings } from '../../test-utils/settings.js';
|
||||
import { makeFakeConfig } from '@google/gemini-cli-core';
|
||||
import { waitFor } from '../../test-utils/async.js';
|
||||
import { act, useState } from 'react';
|
||||
import {
|
||||
@@ -3512,7 +3513,10 @@ describe('InputPrompt', () => {
|
||||
<TestWrapper />,
|
||||
{
|
||||
mouseEventsEnabled: true,
|
||||
useAlternateBuffer: true,
|
||||
config: makeFakeConfig({ useAlternateBuffer: true }),
|
||||
settings: createMockSettings({
|
||||
merged: { ui: { useAlternateBuffer: true } },
|
||||
}),
|
||||
uiActions,
|
||||
},
|
||||
);
|
||||
@@ -3603,7 +3607,10 @@ describe('InputPrompt', () => {
|
||||
<TestWrapper />,
|
||||
{
|
||||
mouseEventsEnabled: true,
|
||||
useAlternateBuffer: true,
|
||||
config: makeFakeConfig({ useAlternateBuffer: true }),
|
||||
settings: createMockSettings({
|
||||
merged: { ui: { useAlternateBuffer: true } },
|
||||
}),
|
||||
uiActions,
|
||||
},
|
||||
);
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
*/
|
||||
|
||||
import { renderWithProviders } from '../../test-utils/render.js';
|
||||
import { createMockSettings } from '../../test-utils/settings.js';
|
||||
import { makeFakeConfig, CoreToolCallStatus } from '@google/gemini-cli-core';
|
||||
import { waitFor } from '../../test-utils/async.js';
|
||||
import { MainContent } from './MainContent.js';
|
||||
import { getToolGroupBorderAppearance } from '../utils/borderStyles.js';
|
||||
@@ -18,7 +20,6 @@ import {
|
||||
useUIState,
|
||||
type UIState,
|
||||
} from '../contexts/UIStateContext.js';
|
||||
import { CoreToolCallStatus } from '@google/gemini-cli-core';
|
||||
import { type IndividualToolCallDisplay } from '../types.js';
|
||||
|
||||
// Mock dependencies
|
||||
@@ -482,7 +483,10 @@ describe('MainContent', () => {
|
||||
<MainContent />,
|
||||
{
|
||||
uiState: uiState as Partial<UIState>,
|
||||
useAlternateBuffer: true,
|
||||
config: makeFakeConfig({ useAlternateBuffer: true }),
|
||||
settings: createMockSettings({
|
||||
merged: { ui: { useAlternateBuffer: true } },
|
||||
}),
|
||||
},
|
||||
);
|
||||
|
||||
@@ -509,7 +513,10 @@ describe('MainContent', () => {
|
||||
<MainContent />,
|
||||
{
|
||||
uiState: uiState as unknown as Partial<UIState>,
|
||||
useAlternateBuffer: true,
|
||||
config: makeFakeConfig({ useAlternateBuffer: true }),
|
||||
settings: createMockSettings({
|
||||
merged: { ui: { useAlternateBuffer: true } },
|
||||
}),
|
||||
},
|
||||
);
|
||||
|
||||
@@ -733,7 +740,10 @@ describe('MainContent', () => {
|
||||
<MainContent />,
|
||||
{
|
||||
uiState: uiState as Partial<UIState>,
|
||||
useAlternateBuffer: isAlternateBuffer,
|
||||
config: makeFakeConfig({ useAlternateBuffer: isAlternateBuffer }),
|
||||
settings: createMockSettings({
|
||||
merged: { ui: { useAlternateBuffer: isAlternateBuffer } },
|
||||
}),
|
||||
},
|
||||
);
|
||||
await waitUntilReady();
|
||||
|
||||
@@ -20,16 +20,14 @@
|
||||
*
|
||||
*/
|
||||
|
||||
import { render } from '../../test-utils/render.js';
|
||||
import { renderWithProviders } from '../../test-utils/render.js';
|
||||
import { waitFor } from '../../test-utils/async.js';
|
||||
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
||||
import { SettingsDialog } from './SettingsDialog.js';
|
||||
import { SettingScope } from '../../config/settings.js';
|
||||
import { createMockSettings } from '../../test-utils/settings.js';
|
||||
import { KeypressProvider } from '../contexts/KeypressContext.js';
|
||||
import { act } from 'react';
|
||||
import { TEST_ONLY } from '../../utils/settingsUtils.js';
|
||||
import { SettingsContext } from '../contexts/SettingsContext.js';
|
||||
import {
|
||||
getSettingsSchema,
|
||||
type SettingDefinition,
|
||||
@@ -37,12 +35,6 @@ import {
|
||||
} from '../../config/settingsSchema.js';
|
||||
import { terminalCapabilityManager } from '../utils/terminalCapabilityManager.js';
|
||||
|
||||
vi.mock('../contexts/UIStateContext.js', () => ({
|
||||
useUIState: () => ({
|
||||
terminalWidth: 100, // Fixed width for consistent snapshots
|
||||
}),
|
||||
}));
|
||||
|
||||
enum TerminalKeys {
|
||||
ENTER = '\u000D',
|
||||
TAB = '\t',
|
||||
@@ -96,7 +88,25 @@ const ENUM_SETTING: SettingDefinition = {
|
||||
showInDialog: true,
|
||||
};
|
||||
|
||||
// Minimal general schema for KeypressProvider
|
||||
const MINIMAL_GENERAL_SCHEMA = {
|
||||
general: {
|
||||
showInDialog: false,
|
||||
properties: {
|
||||
debugKeystrokeLogging: {
|
||||
type: 'boolean',
|
||||
label: 'Debug Keystroke Logging',
|
||||
category: 'General',
|
||||
requiresRestart: false,
|
||||
default: false,
|
||||
showInDialog: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const ENUM_FAKE_SCHEMA: SettingsSchemaType = {
|
||||
...MINIMAL_GENERAL_SCHEMA,
|
||||
ui: {
|
||||
showInDialog: false,
|
||||
properties: {
|
||||
@@ -108,6 +118,7 @@ const ENUM_FAKE_SCHEMA: SettingsSchemaType = {
|
||||
} as unknown as SettingsSchemaType;
|
||||
|
||||
const ARRAY_FAKE_SCHEMA: SettingsSchemaType = {
|
||||
...MINIMAL_GENERAL_SCHEMA,
|
||||
context: {
|
||||
type: 'object',
|
||||
label: 'Context',
|
||||
@@ -164,6 +175,7 @@ const ARRAY_FAKE_SCHEMA: SettingsSchemaType = {
|
||||
} as unknown as SettingsSchemaType;
|
||||
|
||||
const TOOLS_SHELL_FAKE_SCHEMA: SettingsSchemaType = {
|
||||
...MINIMAL_GENERAL_SCHEMA,
|
||||
tools: {
|
||||
type: 'object',
|
||||
label: 'Tools',
|
||||
@@ -224,16 +236,16 @@ const renderDialog = (
|
||||
availableTerminalHeight?: number;
|
||||
},
|
||||
) =>
|
||||
render(
|
||||
<SettingsContext.Provider value={settings}>
|
||||
<KeypressProvider>
|
||||
<SettingsDialog
|
||||
onSelect={onSelect}
|
||||
onRestartRequest={options?.onRestartRequest}
|
||||
availableTerminalHeight={options?.availableTerminalHeight}
|
||||
/>
|
||||
</KeypressProvider>
|
||||
</SettingsContext.Provider>,
|
||||
renderWithProviders(
|
||||
<SettingsDialog
|
||||
onSelect={onSelect}
|
||||
onRestartRequest={options?.onRestartRequest}
|
||||
availableTerminalHeight={options?.availableTerminalHeight}
|
||||
/>,
|
||||
{
|
||||
settings,
|
||||
uiState: { terminalBackgroundColor: undefined },
|
||||
},
|
||||
);
|
||||
|
||||
describe('SettingsDialog', () => {
|
||||
@@ -1344,17 +1356,14 @@ describe('SettingsDialog', () => {
|
||||
|
||||
describe('String Settings Editing', () => {
|
||||
it('should allow editing and committing a string setting', async () => {
|
||||
let settings = createMockSettings({
|
||||
const settings = createMockSettings({
|
||||
'general.sessionCleanup.maxAge': 'initial',
|
||||
});
|
||||
const onSelect = vi.fn();
|
||||
|
||||
const { stdin, unmount, rerender, waitUntilReady } = render(
|
||||
<SettingsContext.Provider value={settings}>
|
||||
<KeypressProvider>
|
||||
<SettingsDialog onSelect={onSelect} />
|
||||
</KeypressProvider>
|
||||
</SettingsContext.Provider>,
|
||||
const { stdin, unmount, waitUntilReady } = renderWithProviders(
|
||||
<SettingsDialog onSelect={onSelect} />,
|
||||
{ settings },
|
||||
);
|
||||
await waitUntilReady();
|
||||
|
||||
@@ -1384,20 +1393,15 @@ describe('SettingsDialog', () => {
|
||||
});
|
||||
await waitUntilReady();
|
||||
|
||||
settings = createMockSettings({
|
||||
user: {
|
||||
settings: { 'general.sessionCleanup.maxAge': 'new value' },
|
||||
originalSettings: { 'general.sessionCleanup.maxAge': 'new value' },
|
||||
path: '',
|
||||
},
|
||||
// Simulate the settings file being updated on disk
|
||||
await act(async () => {
|
||||
settings.setValue(
|
||||
SettingScope.User,
|
||||
'general.sessionCleanup.maxAge',
|
||||
'new value',
|
||||
);
|
||||
});
|
||||
rerender(
|
||||
<SettingsContext.Provider value={settings}>
|
||||
<KeypressProvider>
|
||||
<SettingsDialog onSelect={onSelect} />
|
||||
</KeypressProvider>
|
||||
</SettingsContext.Provider>,
|
||||
);
|
||||
await waitUntilReady();
|
||||
|
||||
// Press Escape to exit
|
||||
await act(async () => {
|
||||
|
||||
@@ -9,6 +9,7 @@ import { Box } from 'ink';
|
||||
import { ToolConfirmationQueue } from './ToolConfirmationQueue.js';
|
||||
import { StreamingState } from '../types.js';
|
||||
import { renderWithProviders } from '../../test-utils/render.js';
|
||||
import { createMockSettings } from '../../test-utils/settings.js';
|
||||
import { waitFor } from '../../test-utils/async.js';
|
||||
import { type Config, CoreToolCallStatus } from '@google/gemini-cli-core';
|
||||
import type { ConfirmingToolState } from '../hooks/useConfirmingTool.js';
|
||||
@@ -162,8 +163,13 @@ describe('ToolConfirmationQueue', () => {
|
||||
/>
|
||||
</Box>,
|
||||
{
|
||||
config: mockConfig,
|
||||
useAlternateBuffer: true,
|
||||
config: {
|
||||
...mockConfig,
|
||||
getUseAlternateBuffer: () => true,
|
||||
} as unknown as Config,
|
||||
settings: createMockSettings({
|
||||
merged: { ui: { useAlternateBuffer: true } },
|
||||
}),
|
||||
uiState: {
|
||||
terminalWidth: 80,
|
||||
terminalHeight: 20,
|
||||
@@ -212,7 +218,9 @@ describe('ToolConfirmationQueue', () => {
|
||||
/>,
|
||||
{
|
||||
config: mockConfig,
|
||||
useAlternateBuffer: false,
|
||||
settings: createMockSettings({
|
||||
merged: { ui: { useAlternateBuffer: false } },
|
||||
}),
|
||||
uiState: {
|
||||
terminalWidth: 80,
|
||||
terminalHeight: 40,
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
|
||||
import { OverflowProvider } from '../../contexts/OverflowContext.js';
|
||||
import { renderWithProviders } from '../../../test-utils/render.js';
|
||||
import { createMockSettings } from '../../../test-utils/settings.js';
|
||||
import { makeFakeConfig } from '@google/gemini-cli-core';
|
||||
import { waitFor } from '../../../test-utils/async.js';
|
||||
import { DiffRenderer } from './DiffRenderer.js';
|
||||
import * as CodeColorizer from '../../utils/CodeColorizer.js';
|
||||
@@ -42,7 +44,12 @@ index 0000000..e69de29
|
||||
terminalWidth={80}
|
||||
/>
|
||||
</OverflowProvider>,
|
||||
{ useAlternateBuffer },
|
||||
{
|
||||
config: makeFakeConfig({ useAlternateBuffer }),
|
||||
settings: createMockSettings({
|
||||
merged: { ui: { useAlternateBuffer } },
|
||||
}),
|
||||
},
|
||||
);
|
||||
await waitFor(() =>
|
||||
expect(mockColorizeCode).toHaveBeenCalledWith({
|
||||
@@ -74,7 +81,12 @@ index 0000000..e69de29
|
||||
terminalWidth={80}
|
||||
/>
|
||||
</OverflowProvider>,
|
||||
{ useAlternateBuffer },
|
||||
{
|
||||
config: makeFakeConfig({ useAlternateBuffer }),
|
||||
settings: createMockSettings({
|
||||
merged: { ui: { useAlternateBuffer } },
|
||||
}),
|
||||
},
|
||||
);
|
||||
await waitFor(() =>
|
||||
expect(mockColorizeCode).toHaveBeenCalledWith({
|
||||
@@ -102,7 +114,12 @@ index 0000000..e69de29
|
||||
<OverflowProvider>
|
||||
<DiffRenderer diffContent={newFileDiffContent} terminalWidth={80} />
|
||||
</OverflowProvider>,
|
||||
{ useAlternateBuffer },
|
||||
{
|
||||
config: makeFakeConfig({ useAlternateBuffer }),
|
||||
settings: createMockSettings({
|
||||
merged: { ui: { useAlternateBuffer } },
|
||||
}),
|
||||
},
|
||||
);
|
||||
await waitFor(() =>
|
||||
expect(mockColorizeCode).toHaveBeenCalledWith({
|
||||
@@ -135,7 +152,12 @@ index 0000001..0000002 100644
|
||||
terminalWidth={80}
|
||||
/>
|
||||
</OverflowProvider>,
|
||||
{ useAlternateBuffer },
|
||||
{
|
||||
config: makeFakeConfig({ useAlternateBuffer }),
|
||||
settings: createMockSettings({
|
||||
merged: { ui: { useAlternateBuffer } },
|
||||
}),
|
||||
},
|
||||
);
|
||||
// colorizeCode is used internally by the line-by-line rendering, not for the whole block
|
||||
await waitFor(() => expect(lastFrame()).toContain('new line'));
|
||||
@@ -166,7 +188,12 @@ index 1234567..1234567 100644
|
||||
terminalWidth={80}
|
||||
/>
|
||||
</OverflowProvider>,
|
||||
{ useAlternateBuffer },
|
||||
{
|
||||
config: makeFakeConfig({ useAlternateBuffer }),
|
||||
settings: createMockSettings({
|
||||
merged: { ui: { useAlternateBuffer } },
|
||||
}),
|
||||
},
|
||||
);
|
||||
await waitFor(() => expect(lastFrame()).toBeDefined());
|
||||
expect(lastFrame()).toMatchSnapshot();
|
||||
@@ -178,7 +205,12 @@ index 1234567..1234567 100644
|
||||
<OverflowProvider>
|
||||
<DiffRenderer diffContent="" terminalWidth={80} />
|
||||
</OverflowProvider>,
|
||||
{ useAlternateBuffer },
|
||||
{
|
||||
config: makeFakeConfig({ useAlternateBuffer }),
|
||||
settings: createMockSettings({
|
||||
merged: { ui: { useAlternateBuffer } },
|
||||
}),
|
||||
},
|
||||
);
|
||||
await waitFor(() => expect(lastFrame()).toBeDefined());
|
||||
expect(lastFrame()).toMatchSnapshot();
|
||||
@@ -208,7 +240,12 @@ index 123..456 100644
|
||||
terminalWidth={80}
|
||||
/>
|
||||
</OverflowProvider>,
|
||||
{ useAlternateBuffer },
|
||||
{
|
||||
config: makeFakeConfig({ useAlternateBuffer }),
|
||||
settings: createMockSettings({
|
||||
merged: { ui: { useAlternateBuffer } },
|
||||
}),
|
||||
},
|
||||
);
|
||||
await waitFor(() => expect(lastFrame()).toContain('added line'));
|
||||
expect(lastFrame()).toMatchSnapshot();
|
||||
@@ -242,7 +279,12 @@ index abc..def 100644
|
||||
terminalWidth={80}
|
||||
/>
|
||||
</OverflowProvider>,
|
||||
{ useAlternateBuffer },
|
||||
{
|
||||
config: makeFakeConfig({ useAlternateBuffer }),
|
||||
settings: createMockSettings({
|
||||
merged: { ui: { useAlternateBuffer } },
|
||||
}),
|
||||
},
|
||||
);
|
||||
await waitFor(() => expect(lastFrame()).toContain('context line 15'));
|
||||
expect(lastFrame()).toMatchSnapshot();
|
||||
@@ -292,7 +334,12 @@ index 123..789 100644
|
||||
availableTerminalHeight={height}
|
||||
/>
|
||||
</OverflowProvider>,
|
||||
{ useAlternateBuffer },
|
||||
{
|
||||
config: makeFakeConfig({ useAlternateBuffer }),
|
||||
settings: createMockSettings({
|
||||
merged: { ui: { useAlternateBuffer } },
|
||||
}),
|
||||
},
|
||||
);
|
||||
await waitFor(() => expect(lastFrame()).toContain('anotherNew'));
|
||||
const output = lastFrame();
|
||||
@@ -326,7 +373,12 @@ fileDiff Index: file.txt
|
||||
terminalWidth={80}
|
||||
/>
|
||||
</OverflowProvider>,
|
||||
{ useAlternateBuffer },
|
||||
{
|
||||
config: makeFakeConfig({ useAlternateBuffer }),
|
||||
settings: createMockSettings({
|
||||
merged: { ui: { useAlternateBuffer } },
|
||||
}),
|
||||
},
|
||||
);
|
||||
await waitFor(() => expect(lastFrame()).toContain('newVar'));
|
||||
expect(lastFrame()).toMatchSnapshot();
|
||||
@@ -353,7 +405,12 @@ fileDiff Index: Dockerfile
|
||||
terminalWidth={80}
|
||||
/>
|
||||
</OverflowProvider>,
|
||||
{ useAlternateBuffer },
|
||||
{
|
||||
config: makeFakeConfig({ useAlternateBuffer }),
|
||||
settings: createMockSettings({
|
||||
merged: { ui: { useAlternateBuffer } },
|
||||
}),
|
||||
},
|
||||
);
|
||||
await waitFor(() => expect(lastFrame()).toContain('RUN npm run build'));
|
||||
expect(lastFrame()).toMatchSnapshot();
|
||||
|
||||
@@ -16,6 +16,8 @@ import {
|
||||
CoreToolCallStatus,
|
||||
} from '@google/gemini-cli-core';
|
||||
import { renderWithProviders } from '../../../test-utils/render.js';
|
||||
import { createMockSettings } from '../../../test-utils/settings.js';
|
||||
import { makeFakeConfig } from '@google/gemini-cli-core';
|
||||
import { waitFor } from '../../../test-utils/async.js';
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { SHELL_COMMAND_NAME, ACTIVE_SHELL_MAX_LINES } from '../../constants.js';
|
||||
@@ -48,14 +50,6 @@ describe('<ShellToolMessage />', () => {
|
||||
setEmbeddedShellFocused: mockSetEmbeddedShellFocused,
|
||||
};
|
||||
|
||||
const renderShell = (
|
||||
props: Partial<ShellToolMessageProps> = {},
|
||||
options: Parameters<typeof renderWithProviders>[1] = {},
|
||||
) =>
|
||||
renderWithProviders(<ShellToolMessage {...baseProps} {...props} />, {
|
||||
uiActions,
|
||||
...options,
|
||||
});
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
@@ -65,9 +59,9 @@ describe('<ShellToolMessage />', () => {
|
||||
['SHELL_COMMAND_NAME', SHELL_COMMAND_NAME],
|
||||
['SHELL_TOOL_NAME', SHELL_TOOL_NAME],
|
||||
])('clicks inside the shell area sets focus for %s', async (_, name) => {
|
||||
const { lastFrame, simulateClick, unmount } = renderShell(
|
||||
{ name },
|
||||
{ mouseEventsEnabled: true },
|
||||
const { lastFrame, simulateClick, unmount } = renderWithProviders(
|
||||
<ShellToolMessage {...baseProps} name={name} />,
|
||||
{ uiActions, mouseEventsEnabled: true },
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
@@ -152,7 +146,10 @@ describe('<ShellToolMessage />', () => {
|
||||
ptyId: 1,
|
||||
},
|
||||
{
|
||||
useAlternateBuffer: true,
|
||||
config: makeFakeConfig({ useAlternateBuffer: true }),
|
||||
settings: createMockSettings({
|
||||
merged: { ui: { useAlternateBuffer: true } },
|
||||
}),
|
||||
uiState: {
|
||||
embeddedShellFocused: true,
|
||||
activePtyId: 1,
|
||||
@@ -166,7 +163,10 @@ describe('<ShellToolMessage />', () => {
|
||||
ptyId: 1,
|
||||
},
|
||||
{
|
||||
useAlternateBuffer: true,
|
||||
config: makeFakeConfig({ useAlternateBuffer: true }),
|
||||
settings: createMockSettings({
|
||||
merged: { ui: { useAlternateBuffer: true } },
|
||||
}),
|
||||
uiState: {
|
||||
embeddedShellFocused: false,
|
||||
activePtyId: 1,
|
||||
@@ -174,9 +174,9 @@ describe('<ShellToolMessage />', () => {
|
||||
},
|
||||
],
|
||||
])('%s', async (_, props, options) => {
|
||||
const { lastFrame, waitUntilReady, unmount } = renderShell(
|
||||
props,
|
||||
options,
|
||||
const { lastFrame, waitUntilReady, unmount } = renderWithProviders(
|
||||
<ShellToolMessage {...baseProps} {...props} />,
|
||||
{ uiActions, ...options },
|
||||
);
|
||||
await waitUntilReady();
|
||||
expect(lastFrame()).toMatchSnapshot();
|
||||
@@ -223,16 +223,21 @@ describe('<ShellToolMessage />', () => {
|
||||
focused,
|
||||
constrainHeight,
|
||||
) => {
|
||||
const { lastFrame, waitUntilReady, unmount } = renderShell(
|
||||
const { lastFrame, waitUntilReady, unmount } = renderWithProviders(
|
||||
<ShellToolMessage
|
||||
{...baseProps}
|
||||
resultDisplay={LONG_OUTPUT}
|
||||
renderOutputAsMarkdown={false}
|
||||
availableTerminalHeight={availableTerminalHeight}
|
||||
ptyId={1}
|
||||
status={CoreToolCallStatus.Executing}
|
||||
/>,
|
||||
{
|
||||
resultDisplay: LONG_OUTPUT,
|
||||
renderOutputAsMarkdown: false,
|
||||
availableTerminalHeight,
|
||||
ptyId: 1,
|
||||
status: CoreToolCallStatus.Executing,
|
||||
},
|
||||
{
|
||||
useAlternateBuffer: true,
|
||||
uiActions,
|
||||
config: makeFakeConfig({ useAlternateBuffer: true }),
|
||||
settings: createMockSettings({
|
||||
merged: { ui: { useAlternateBuffer: true } },
|
||||
}),
|
||||
uiState: {
|
||||
activePtyId: focused ? 1 : 2,
|
||||
embeddedShellFocused: focused,
|
||||
@@ -250,14 +255,21 @@ describe('<ShellToolMessage />', () => {
|
||||
);
|
||||
|
||||
it('fully expands in standard mode when availableTerminalHeight is undefined', async () => {
|
||||
const { lastFrame, unmount } = renderShell(
|
||||
const { lastFrame, unmount } = renderWithProviders(
|
||||
<ShellToolMessage
|
||||
{...baseProps}
|
||||
resultDisplay={LONG_OUTPUT}
|
||||
renderOutputAsMarkdown={false}
|
||||
availableTerminalHeight={undefined}
|
||||
status={CoreToolCallStatus.Executing}
|
||||
/>,
|
||||
{
|
||||
resultDisplay: LONG_OUTPUT,
|
||||
renderOutputAsMarkdown: false,
|
||||
availableTerminalHeight: undefined,
|
||||
status: CoreToolCallStatus.Executing,
|
||||
uiActions,
|
||||
config: makeFakeConfig({ useAlternateBuffer: false }),
|
||||
settings: createMockSettings({
|
||||
merged: { ui: { useAlternateBuffer: false } },
|
||||
}),
|
||||
},
|
||||
{ useAlternateBuffer: false },
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
@@ -269,16 +281,21 @@ describe('<ShellToolMessage />', () => {
|
||||
});
|
||||
|
||||
it('fully expands in alternate buffer mode when constrainHeight is false and isExpandable is true', async () => {
|
||||
const { lastFrame, waitUntilReady, unmount } = renderShell(
|
||||
const { lastFrame, waitUntilReady, unmount } = renderWithProviders(
|
||||
<ShellToolMessage
|
||||
{...baseProps}
|
||||
resultDisplay={LONG_OUTPUT}
|
||||
renderOutputAsMarkdown={false}
|
||||
availableTerminalHeight={undefined}
|
||||
status={CoreToolCallStatus.Success}
|
||||
isExpandable={true}
|
||||
/>,
|
||||
{
|
||||
resultDisplay: LONG_OUTPUT,
|
||||
renderOutputAsMarkdown: false,
|
||||
availableTerminalHeight: undefined,
|
||||
status: CoreToolCallStatus.Success,
|
||||
isExpandable: true,
|
||||
},
|
||||
{
|
||||
useAlternateBuffer: true,
|
||||
uiActions,
|
||||
config: makeFakeConfig({ useAlternateBuffer: true }),
|
||||
settings: createMockSettings({
|
||||
merged: { ui: { useAlternateBuffer: true } },
|
||||
}),
|
||||
uiState: {
|
||||
constrainHeight: false,
|
||||
},
|
||||
@@ -296,16 +313,21 @@ describe('<ShellToolMessage />', () => {
|
||||
});
|
||||
|
||||
it('stays constrained in alternate buffer mode when isExpandable is false even if constrainHeight is false', async () => {
|
||||
const { lastFrame, waitUntilReady, unmount } = renderShell(
|
||||
const { lastFrame, waitUntilReady, unmount } = renderWithProviders(
|
||||
<ShellToolMessage
|
||||
{...baseProps}
|
||||
resultDisplay={LONG_OUTPUT}
|
||||
renderOutputAsMarkdown={false}
|
||||
availableTerminalHeight={undefined}
|
||||
status={CoreToolCallStatus.Success}
|
||||
isExpandable={false}
|
||||
/>,
|
||||
{
|
||||
resultDisplay: LONG_OUTPUT,
|
||||
renderOutputAsMarkdown: false,
|
||||
availableTerminalHeight: undefined,
|
||||
status: CoreToolCallStatus.Success,
|
||||
isExpandable: false,
|
||||
},
|
||||
{
|
||||
useAlternateBuffer: true,
|
||||
uiActions,
|
||||
config: makeFakeConfig({ useAlternateBuffer: true }),
|
||||
settings: createMockSettings({
|
||||
merged: { ui: { useAlternateBuffer: true } },
|
||||
}),
|
||||
uiState: {
|
||||
constrainHeight: false,
|
||||
},
|
||||
|
||||
@@ -4,12 +4,10 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
import { waitFor } from '../../../test-utils/async.js';
|
||||
import { render } from '../../../test-utils/render.js';
|
||||
import { renderWithProviders } from '../../../test-utils/render.js';
|
||||
import { SubagentGroupDisplay } from './SubagentGroupDisplay.js';
|
||||
import { Kind, CoreToolCallStatus } from '@google/gemini-cli-core';
|
||||
import type { IndividualToolCallDisplay } from '../../types.js';
|
||||
import { KeypressProvider } from '../../contexts/KeypressContext.js';
|
||||
import { OverflowProvider } from '../../contexts/OverflowContext.js';
|
||||
import { vi } from 'vitest';
|
||||
import { Text } from 'ink';
|
||||
|
||||
@@ -69,36 +67,32 @@ describe('<SubagentGroupDisplay />', () => {
|
||||
const renderSubagentGroup = (
|
||||
toolCallsToRender: IndividualToolCallDisplay[],
|
||||
height?: number,
|
||||
) => (
|
||||
<OverflowProvider>
|
||||
<KeypressProvider>
|
||||
<SubagentGroupDisplay
|
||||
toolCalls={toolCallsToRender}
|
||||
terminalWidth={80}
|
||||
availableTerminalHeight={height}
|
||||
isExpandable={true}
|
||||
/>
|
||||
</KeypressProvider>
|
||||
</OverflowProvider>
|
||||
);
|
||||
) =>
|
||||
renderWithProviders(
|
||||
<SubagentGroupDisplay
|
||||
toolCalls={toolCallsToRender}
|
||||
terminalWidth={80}
|
||||
availableTerminalHeight={height}
|
||||
isExpandable={true}
|
||||
/>,
|
||||
);
|
||||
|
||||
it('renders nothing if there are no agent tool calls', async () => {
|
||||
const { lastFrame } = render(renderSubagentGroup([], 40));
|
||||
const { lastFrame } = renderSubagentGroup([], 40);
|
||||
expect(lastFrame({ allowEmpty: true })).toBe('');
|
||||
});
|
||||
|
||||
it('renders collapsed view by default with correct agent counts and states', async () => {
|
||||
const { lastFrame, waitUntilReady } = render(
|
||||
renderSubagentGroup(mockToolCalls, 40),
|
||||
const { lastFrame, waitUntilReady } = renderSubagentGroup(
|
||||
mockToolCalls,
|
||||
40,
|
||||
);
|
||||
await waitUntilReady();
|
||||
expect(lastFrame()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('expands when availableTerminalHeight is undefined', async () => {
|
||||
const { lastFrame, rerender } = render(
|
||||
renderSubagentGroup(mockToolCalls, 40),
|
||||
);
|
||||
const { lastFrame, rerender } = renderSubagentGroup(mockToolCalls, 40);
|
||||
|
||||
// Default collapsed view
|
||||
await waitFor(() => {
|
||||
@@ -106,13 +100,27 @@ describe('<SubagentGroupDisplay />', () => {
|
||||
});
|
||||
|
||||
// Expand view
|
||||
rerender(renderSubagentGroup(mockToolCalls, undefined));
|
||||
rerender(
|
||||
<SubagentGroupDisplay
|
||||
toolCalls={mockToolCalls}
|
||||
terminalWidth={80}
|
||||
availableTerminalHeight={undefined}
|
||||
isExpandable={true}
|
||||
/>,
|
||||
);
|
||||
await waitFor(() => {
|
||||
expect(lastFrame()).toContain('(ctrl+o to collapse)');
|
||||
});
|
||||
|
||||
// Collapse view
|
||||
rerender(renderSubagentGroup(mockToolCalls, 40));
|
||||
rerender(
|
||||
<SubagentGroupDisplay
|
||||
toolCalls={mockToolCalls}
|
||||
terminalWidth={80}
|
||||
availableTerminalHeight={40}
|
||||
isExpandable={true}
|
||||
/>,
|
||||
);
|
||||
await waitFor(() => {
|
||||
expect(lastFrame()).toContain('(ctrl+o to expand)');
|
||||
});
|
||||
|
||||
@@ -13,8 +13,10 @@ import {
|
||||
type AnsiOutput,
|
||||
CoreToolCallStatus,
|
||||
Kind,
|
||||
makeFakeConfig,
|
||||
} from '@google/gemini-cli-core';
|
||||
import { renderWithProviders } from '../../../test-utils/render.js';
|
||||
import { createMockSettings } from '../../../test-utils/settings.js';
|
||||
import { tryParseJSON } from '../../../utils/jsonoutput.js';
|
||||
|
||||
vi.mock('../GeminiRespondingSpinner.js', () => ({
|
||||
@@ -462,7 +464,10 @@ describe('<ToolMessage />', () => {
|
||||
constrainHeight: true,
|
||||
},
|
||||
width: 80,
|
||||
useAlternateBuffer: false,
|
||||
config: makeFakeConfig({ useAlternateBuffer: false }),
|
||||
settings: createMockSettings({
|
||||
merged: { ui: { useAlternateBuffer: false } },
|
||||
}),
|
||||
},
|
||||
);
|
||||
await waitUntilReady();
|
||||
@@ -495,7 +500,10 @@ describe('<ToolMessage />', () => {
|
||||
uiActions,
|
||||
uiState: { streamingState: StreamingState.Idle },
|
||||
width: 80,
|
||||
useAlternateBuffer: false,
|
||||
config: makeFakeConfig({ useAlternateBuffer: false }),
|
||||
settings: createMockSettings({
|
||||
merged: { ui: { useAlternateBuffer: false } },
|
||||
}),
|
||||
},
|
||||
);
|
||||
await waitUntilReady();
|
||||
@@ -523,7 +531,10 @@ describe('<ToolMessage />', () => {
|
||||
uiActions,
|
||||
uiState: { streamingState: StreamingState.Idle },
|
||||
width: 80,
|
||||
useAlternateBuffer: false,
|
||||
config: makeFakeConfig({ useAlternateBuffer: false }),
|
||||
settings: createMockSettings({
|
||||
merged: { ui: { useAlternateBuffer: false } },
|
||||
}),
|
||||
},
|
||||
);
|
||||
await waitUntilReady();
|
||||
|
||||
@@ -5,11 +5,12 @@
|
||||
*/
|
||||
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { ToolMessage, type ToolMessageProps } from './ToolMessage.js';
|
||||
import { type ToolMessageProps, ToolMessage } from './ToolMessage.js';
|
||||
import { StreamingState } from '../../types.js';
|
||||
import { StreamingContext } from '../../contexts/StreamingContext.js';
|
||||
import { renderWithProviders } from '../../../test-utils/render.js';
|
||||
import { CoreToolCallStatus } from '@google/gemini-cli-core';
|
||||
import { createMockSettings } from '../../../test-utils/settings.js';
|
||||
import { CoreToolCallStatus, makeFakeConfig } from '@google/gemini-cli-core';
|
||||
|
||||
describe('<ToolMessage /> - Raw Markdown Display Snapshots', () => {
|
||||
const baseProps: ToolMessageProps = {
|
||||
@@ -72,7 +73,10 @@ describe('<ToolMessage /> - Raw Markdown Display Snapshots', () => {
|
||||
</StreamingContext.Provider>,
|
||||
{
|
||||
uiState: { renderMarkdown, streamingState: StreamingState.Idle },
|
||||
useAlternateBuffer,
|
||||
config: makeFakeConfig({ useAlternateBuffer }),
|
||||
settings: createMockSettings({
|
||||
merged: { ui: { useAlternateBuffer } },
|
||||
}),
|
||||
},
|
||||
);
|
||||
await waitUntilReady();
|
||||
|
||||
@@ -7,9 +7,10 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { ToolGroupMessage } from './ToolGroupMessage.js';
|
||||
import { renderWithProviders } from '../../../test-utils/render.js';
|
||||
import { createMockSettings } from '../../../test-utils/settings.js';
|
||||
import { StreamingState, type IndividualToolCallDisplay } from '../../types.js';
|
||||
import { waitFor } from '../../../test-utils/async.js';
|
||||
import { CoreToolCallStatus } from '@google/gemini-cli-core';
|
||||
import { CoreToolCallStatus, makeFakeConfig } from '@google/gemini-cli-core';
|
||||
import { useOverflowState } from '../../contexts/OverflowContext.js';
|
||||
|
||||
describe('ToolOverflowConsistencyChecks: ToolGroupMessage and ToolResultDisplay synchronization', () => {
|
||||
@@ -56,7 +57,10 @@ describe('ToolOverflowConsistencyChecks: ToolGroupMessage and ToolResultDisplay
|
||||
streamingState: StreamingState.Idle,
|
||||
constrainHeight: true,
|
||||
},
|
||||
useAlternateBuffer: true,
|
||||
config: makeFakeConfig({ useAlternateBuffer: true }),
|
||||
settings: createMockSettings({
|
||||
merged: { ui: { useAlternateBuffer: true } },
|
||||
}),
|
||||
},
|
||||
);
|
||||
|
||||
@@ -106,7 +110,10 @@ describe('ToolOverflowConsistencyChecks: ToolGroupMessage and ToolResultDisplay
|
||||
streamingState: StreamingState.Idle,
|
||||
constrainHeight: true,
|
||||
},
|
||||
useAlternateBuffer: false,
|
||||
config: makeFakeConfig({ useAlternateBuffer: false }),
|
||||
settings: createMockSettings({
|
||||
merged: { ui: { useAlternateBuffer: false } },
|
||||
}),
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
@@ -5,9 +5,10 @@
|
||||
*/
|
||||
|
||||
import { renderWithProviders } from '../../../test-utils/render.js';
|
||||
import { createMockSettings } from '../../../test-utils/settings.js';
|
||||
import { ToolResultDisplay } from './ToolResultDisplay.js';
|
||||
import { describe, it, expect, vi } from 'vitest';
|
||||
import type { AnsiOutput } from '@google/gemini-cli-core';
|
||||
import { makeFakeConfig, type AnsiOutput } from '@google/gemini-cli-core';
|
||||
|
||||
describe('ToolResultDisplay', () => {
|
||||
beforeEach(() => {
|
||||
@@ -36,7 +37,12 @@ describe('ToolResultDisplay', () => {
|
||||
terminalWidth={80}
|
||||
maxLines={10}
|
||||
/>,
|
||||
{ useAlternateBuffer: true },
|
||||
{
|
||||
config: makeFakeConfig({ useAlternateBuffer: true }),
|
||||
settings: createMockSettings({
|
||||
merged: { ui: { useAlternateBuffer: true } },
|
||||
}),
|
||||
},
|
||||
);
|
||||
await waitUntilReady();
|
||||
const output = lastFrame();
|
||||
@@ -52,7 +58,12 @@ describe('ToolResultDisplay', () => {
|
||||
terminalWidth={80}
|
||||
maxLines={10}
|
||||
/>,
|
||||
{ useAlternateBuffer: true },
|
||||
{
|
||||
config: makeFakeConfig({ useAlternateBuffer: true }),
|
||||
settings: createMockSettings({
|
||||
merged: { ui: { useAlternateBuffer: true } },
|
||||
}),
|
||||
},
|
||||
);
|
||||
await waitUntilReady();
|
||||
const output = lastFrame();
|
||||
@@ -69,7 +80,12 @@ describe('ToolResultDisplay', () => {
|
||||
terminalWidth={80}
|
||||
hasFocus={true}
|
||||
/>,
|
||||
{ useAlternateBuffer: true },
|
||||
{
|
||||
config: makeFakeConfig({ useAlternateBuffer: true }),
|
||||
settings: createMockSettings({
|
||||
merged: { ui: { useAlternateBuffer: true } },
|
||||
}),
|
||||
},
|
||||
);
|
||||
await waitUntilReady();
|
||||
|
||||
@@ -80,7 +96,12 @@ describe('ToolResultDisplay', () => {
|
||||
it('renders string result as markdown by default', async () => {
|
||||
const { lastFrame, waitUntilReady, unmount } = renderWithProviders(
|
||||
<ToolResultDisplay resultDisplay="**Some result**" terminalWidth={80} />,
|
||||
{ useAlternateBuffer: false },
|
||||
{
|
||||
config: makeFakeConfig({ useAlternateBuffer: false }),
|
||||
settings: createMockSettings({
|
||||
merged: { ui: { useAlternateBuffer: false } },
|
||||
}),
|
||||
},
|
||||
);
|
||||
await waitUntilReady();
|
||||
const output = lastFrame();
|
||||
@@ -98,7 +119,10 @@ describe('ToolResultDisplay', () => {
|
||||
renderOutputAsMarkdown={false}
|
||||
/>,
|
||||
{
|
||||
useAlternateBuffer: false,
|
||||
config: makeFakeConfig({ useAlternateBuffer: false }),
|
||||
settings: createMockSettings({
|
||||
merged: { ui: { useAlternateBuffer: false } },
|
||||
}),
|
||||
uiState: { constrainHeight: true },
|
||||
},
|
||||
);
|
||||
@@ -118,7 +142,10 @@ describe('ToolResultDisplay', () => {
|
||||
availableTerminalHeight={20}
|
||||
/>,
|
||||
{
|
||||
useAlternateBuffer: false,
|
||||
config: makeFakeConfig({ useAlternateBuffer: false }),
|
||||
settings: createMockSettings({
|
||||
merged: { ui: { useAlternateBuffer: false } },
|
||||
}),
|
||||
uiState: { constrainHeight: true },
|
||||
},
|
||||
);
|
||||
@@ -140,7 +167,12 @@ describe('ToolResultDisplay', () => {
|
||||
terminalWidth={80}
|
||||
availableTerminalHeight={20}
|
||||
/>,
|
||||
{ useAlternateBuffer: false },
|
||||
{
|
||||
config: makeFakeConfig({ useAlternateBuffer: false }),
|
||||
settings: createMockSettings({
|
||||
merged: { ui: { useAlternateBuffer: false } },
|
||||
}),
|
||||
},
|
||||
);
|
||||
await waitUntilReady();
|
||||
const output = lastFrame();
|
||||
@@ -170,7 +202,12 @@ describe('ToolResultDisplay', () => {
|
||||
terminalWidth={80}
|
||||
availableTerminalHeight={20}
|
||||
/>,
|
||||
{ useAlternateBuffer: false },
|
||||
{
|
||||
config: makeFakeConfig({ useAlternateBuffer: false }),
|
||||
settings: createMockSettings({
|
||||
merged: { ui: { useAlternateBuffer: false } },
|
||||
}),
|
||||
},
|
||||
);
|
||||
await waitUntilReady();
|
||||
const output = lastFrame();
|
||||
@@ -189,7 +226,12 @@ describe('ToolResultDisplay', () => {
|
||||
terminalWidth={80}
|
||||
availableTerminalHeight={20}
|
||||
/>,
|
||||
{ useAlternateBuffer: false },
|
||||
{
|
||||
config: makeFakeConfig({ useAlternateBuffer: false }),
|
||||
settings: createMockSettings({
|
||||
merged: { ui: { useAlternateBuffer: false } },
|
||||
}),
|
||||
},
|
||||
);
|
||||
await waitUntilReady();
|
||||
const output = lastFrame({ allowEmpty: true });
|
||||
@@ -208,7 +250,10 @@ describe('ToolResultDisplay', () => {
|
||||
renderOutputAsMarkdown={true}
|
||||
/>,
|
||||
{
|
||||
useAlternateBuffer: false,
|
||||
config: makeFakeConfig({ useAlternateBuffer: false }),
|
||||
settings: createMockSettings({
|
||||
merged: { ui: { useAlternateBuffer: false } },
|
||||
}),
|
||||
uiState: { constrainHeight: true },
|
||||
},
|
||||
);
|
||||
@@ -226,7 +271,12 @@ describe('ToolResultDisplay', () => {
|
||||
availableTerminalHeight={20}
|
||||
renderOutputAsMarkdown={true}
|
||||
/>,
|
||||
{ useAlternateBuffer: true },
|
||||
{
|
||||
config: makeFakeConfig({ useAlternateBuffer: true }),
|
||||
settings: createMockSettings({
|
||||
merged: { ui: { useAlternateBuffer: true } },
|
||||
}),
|
||||
},
|
||||
);
|
||||
await waitUntilReady();
|
||||
const output = lastFrame();
|
||||
@@ -306,7 +356,10 @@ describe('ToolResultDisplay', () => {
|
||||
maxLines={3}
|
||||
/>,
|
||||
{
|
||||
useAlternateBuffer: false,
|
||||
config: makeFakeConfig({ useAlternateBuffer: false }),
|
||||
settings: createMockSettings({
|
||||
merged: { ui: { useAlternateBuffer: false } },
|
||||
}),
|
||||
uiState: { constrainHeight: true },
|
||||
},
|
||||
);
|
||||
@@ -342,7 +395,10 @@ describe('ToolResultDisplay', () => {
|
||||
availableTerminalHeight={undefined}
|
||||
/>,
|
||||
{
|
||||
useAlternateBuffer: false,
|
||||
config: makeFakeConfig({ useAlternateBuffer: false }),
|
||||
settings: createMockSettings({
|
||||
merged: { ui: { useAlternateBuffer: false } },
|
||||
}),
|
||||
uiState: { constrainHeight: true },
|
||||
},
|
||||
);
|
||||
|
||||
@@ -5,9 +5,10 @@
|
||||
*/
|
||||
|
||||
import { renderWithProviders } from '../../../test-utils/render.js';
|
||||
import { createMockSettings } from '../../../test-utils/settings.js';
|
||||
import { ToolResultDisplay } from './ToolResultDisplay.js';
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { type AnsiOutput } from '@google/gemini-cli-core';
|
||||
import { makeFakeConfig, type AnsiOutput } from '@google/gemini-cli-core';
|
||||
|
||||
describe('ToolResultDisplay Overflow', () => {
|
||||
it('shows the head of the content when overflowDirection is bottom (string)', async () => {
|
||||
@@ -20,7 +21,10 @@ describe('ToolResultDisplay Overflow', () => {
|
||||
overflowDirection="bottom"
|
||||
/>,
|
||||
{
|
||||
useAlternateBuffer: false,
|
||||
config: makeFakeConfig({ useAlternateBuffer: false }),
|
||||
settings: createMockSettings({
|
||||
merged: { ui: { useAlternateBuffer: false } },
|
||||
}),
|
||||
uiState: { constrainHeight: true },
|
||||
},
|
||||
);
|
||||
@@ -46,7 +50,10 @@ describe('ToolResultDisplay Overflow', () => {
|
||||
overflowDirection="top"
|
||||
/>,
|
||||
{
|
||||
useAlternateBuffer: false,
|
||||
config: makeFakeConfig({ useAlternateBuffer: false }),
|
||||
settings: createMockSettings({
|
||||
merged: { ui: { useAlternateBuffer: false } },
|
||||
}),
|
||||
uiState: { constrainHeight: true },
|
||||
},
|
||||
);
|
||||
@@ -83,7 +90,10 @@ describe('ToolResultDisplay Overflow', () => {
|
||||
overflowDirection="bottom"
|
||||
/>,
|
||||
{
|
||||
useAlternateBuffer: false,
|
||||
config: makeFakeConfig({ useAlternateBuffer: false }),
|
||||
settings: createMockSettings({
|
||||
merged: { ui: { useAlternateBuffer: false } },
|
||||
}),
|
||||
uiState: { constrainHeight: true },
|
||||
},
|
||||
);
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { render } from '../../../test-utils/render.js';
|
||||
import { renderWithProviders } from '../../../test-utils/render.js';
|
||||
import { waitFor } from '../../../test-utils/async.js';
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { act } from 'react';
|
||||
@@ -14,15 +14,8 @@ import {
|
||||
type BaseSettingsDialogProps,
|
||||
type SettingsDialogItem,
|
||||
} from './BaseSettingsDialog.js';
|
||||
import { KeypressProvider } from '../../contexts/KeypressContext.js';
|
||||
import { SettingScope } from '../../../config/settings.js';
|
||||
|
||||
vi.mock('../../contexts/UIStateContext.js', () => ({
|
||||
useUIState: () => ({
|
||||
mainAreaWidth: 100,
|
||||
}),
|
||||
}));
|
||||
|
||||
enum TerminalKeys {
|
||||
ENTER = '\u000D',
|
||||
TAB = '\t',
|
||||
@@ -115,10 +108,8 @@ describe('BaseSettingsDialog', () => {
|
||||
...props,
|
||||
};
|
||||
|
||||
const result = render(
|
||||
<KeypressProvider>
|
||||
<BaseSettingsDialog {...defaultProps} />
|
||||
</KeypressProvider>,
|
||||
const result = renderWithProviders(
|
||||
<BaseSettingsDialog {...defaultProps} />,
|
||||
);
|
||||
await result.waitUntilReady();
|
||||
return result;
|
||||
@@ -331,22 +322,18 @@ describe('BaseSettingsDialog', () => {
|
||||
const filteredItems = [items[0], items[2], items[4]];
|
||||
await act(async () => {
|
||||
rerender(
|
||||
<KeypressProvider>
|
||||
<BaseSettingsDialog
|
||||
title="Test Settings"
|
||||
items={filteredItems}
|
||||
selectedScope={SettingScope.User}
|
||||
maxItemsToShow={5}
|
||||
onItemToggle={mockOnItemToggle}
|
||||
onEditCommit={mockOnEditCommit}
|
||||
onItemClear={mockOnItemClear}
|
||||
onClose={mockOnClose}
|
||||
/>
|
||||
</KeypressProvider>,
|
||||
<BaseSettingsDialog
|
||||
title="Test Settings"
|
||||
items={filteredItems}
|
||||
selectedScope={SettingScope.User}
|
||||
maxItemsToShow={5}
|
||||
onItemToggle={mockOnItemToggle}
|
||||
onEditCommit={mockOnEditCommit}
|
||||
onItemClear={mockOnItemClear}
|
||||
onClose={mockOnClose}
|
||||
/>,
|
||||
);
|
||||
});
|
||||
await waitUntilReady();
|
||||
|
||||
// Verify the dialog hasn't crashed and the items are displayed
|
||||
await waitFor(() => {
|
||||
const frame = lastFrame();
|
||||
@@ -391,22 +378,18 @@ describe('BaseSettingsDialog', () => {
|
||||
const filteredItems = [items[0], items[1]];
|
||||
await act(async () => {
|
||||
rerender(
|
||||
<KeypressProvider>
|
||||
<BaseSettingsDialog
|
||||
title="Test Settings"
|
||||
items={filteredItems}
|
||||
selectedScope={SettingScope.User}
|
||||
maxItemsToShow={5}
|
||||
onItemToggle={mockOnItemToggle}
|
||||
onEditCommit={mockOnEditCommit}
|
||||
onItemClear={mockOnItemClear}
|
||||
onClose={mockOnClose}
|
||||
/>
|
||||
</KeypressProvider>,
|
||||
<BaseSettingsDialog
|
||||
title="Test Settings"
|
||||
items={filteredItems}
|
||||
selectedScope={SettingScope.User}
|
||||
maxItemsToShow={5}
|
||||
onItemToggle={mockOnItemToggle}
|
||||
onEditCommit={mockOnEditCommit}
|
||||
onItemClear={mockOnItemClear}
|
||||
onClose={mockOnClose}
|
||||
/>,
|
||||
);
|
||||
});
|
||||
await waitUntilReady();
|
||||
|
||||
await waitFor(() => {
|
||||
const frame = lastFrame();
|
||||
expect(frame).toContain('Boolean Setting');
|
||||
|
||||
@@ -5,21 +5,12 @@
|
||||
*/
|
||||
|
||||
import { useState, useEffect, useRef, act } from 'react';
|
||||
import { render } from '../../../test-utils/render.js';
|
||||
import { renderWithProviders } from '../../../test-utils/render.js';
|
||||
import { Box, Text } from 'ink';
|
||||
import { ScrollableList, type ScrollableListRef } from './ScrollableList.js';
|
||||
import { ScrollProvider } from '../../contexts/ScrollProvider.js';
|
||||
import { KeypressProvider } from '../../contexts/KeypressContext.js';
|
||||
import { MouseProvider } from '../../contexts/MouseContext.js';
|
||||
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
||||
import { waitFor } from '../../../test-utils/async.js';
|
||||
|
||||
vi.mock('../../contexts/UIStateContext.js', () => ({
|
||||
useUIState: vi.fn(() => ({
|
||||
copyModeEnabled: false,
|
||||
})),
|
||||
}));
|
||||
|
||||
// Mock useStdout to provide a fixed size for testing
|
||||
vi.mock('ink', async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import('ink')>();
|
||||
@@ -85,51 +76,45 @@ const TestComponent = ({
|
||||
}, [onRef]);
|
||||
|
||||
return (
|
||||
<MouseProvider mouseEventsEnabled={false}>
|
||||
<KeypressProvider>
|
||||
<ScrollProvider>
|
||||
<Box flexDirection="column" width={80} height={24} padding={1}>
|
||||
<Box flexGrow={1} borderStyle="round" borderColor="cyan">
|
||||
<ScrollableList
|
||||
ref={listRef}
|
||||
data={items}
|
||||
renderItem={({ item, index }) => (
|
||||
<Box flexDirection="column" paddingBottom={2}>
|
||||
<Box flexDirection="column" width={80} height={24} padding={1}>
|
||||
<Box flexGrow={1} borderStyle="round" borderColor="cyan">
|
||||
<ScrollableList
|
||||
ref={listRef}
|
||||
data={items}
|
||||
renderItem={({ item, index }) => (
|
||||
<Box flexDirection="column" paddingBottom={2}>
|
||||
<Box
|
||||
sticky
|
||||
flexDirection="column"
|
||||
width={78}
|
||||
opaque
|
||||
stickyChildren={
|
||||
<Box flexDirection="column" width={78} opaque>
|
||||
<Text>{item.title}</Text>
|
||||
<Box
|
||||
sticky
|
||||
flexDirection="column"
|
||||
width={78}
|
||||
opaque
|
||||
stickyChildren={
|
||||
<Box flexDirection="column" width={78} opaque>
|
||||
<Text>{item.title}</Text>
|
||||
<Box
|
||||
borderStyle="single"
|
||||
borderTop={true}
|
||||
borderBottom={false}
|
||||
borderLeft={false}
|
||||
borderRight={false}
|
||||
borderColor="gray"
|
||||
/>
|
||||
</Box>
|
||||
}
|
||||
>
|
||||
<Text>{item.title}</Text>
|
||||
</Box>
|
||||
<Text color="gray">{getLorem(index)}</Text>
|
||||
borderStyle="single"
|
||||
borderTop={true}
|
||||
borderBottom={false}
|
||||
borderLeft={false}
|
||||
borderRight={false}
|
||||
borderColor="gray"
|
||||
/>
|
||||
</Box>
|
||||
)}
|
||||
estimatedItemHeight={() => 14}
|
||||
keyExtractor={(item) => item.id}
|
||||
hasFocus={true}
|
||||
initialScrollIndex={Number.MAX_SAFE_INTEGER}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<Text>{item.title}</Text>
|
||||
</Box>
|
||||
<Text color="gray">{getLorem(index)}</Text>
|
||||
</Box>
|
||||
<Text>Count: {items.length}</Text>
|
||||
</Box>
|
||||
</ScrollProvider>
|
||||
</KeypressProvider>
|
||||
</MouseProvider>
|
||||
)}
|
||||
estimatedItemHeight={() => 14}
|
||||
keyExtractor={(item) => item.id}
|
||||
hasFocus={true}
|
||||
initialScrollIndex={Number.MAX_SAFE_INTEGER}
|
||||
/>
|
||||
</Box>
|
||||
<Text>Count: {items.length}</Text>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
describe('ScrollableList Demo Behavior', () => {
|
||||
@@ -147,10 +132,10 @@ describe('ScrollableList Demo Behavior', () => {
|
||||
let lastFrame: (options?: { allowEmpty?: boolean }) => string | undefined;
|
||||
let waitUntilReady: () => Promise<void>;
|
||||
|
||||
let result: ReturnType<typeof render>;
|
||||
let result: ReturnType<typeof renderWithProviders>;
|
||||
|
||||
await act(async () => {
|
||||
result = render(
|
||||
result = renderWithProviders(
|
||||
<TestComponent
|
||||
onAddItem={(add) => {
|
||||
addItem = add;
|
||||
@@ -230,45 +215,39 @@ describe('ScrollableList Demo Behavior', () => {
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<MouseProvider mouseEventsEnabled={false}>
|
||||
<KeypressProvider>
|
||||
<ScrollProvider>
|
||||
<Box flexDirection="column" width={80} height={10}>
|
||||
<ScrollableList
|
||||
ref={ref}
|
||||
data={items}
|
||||
renderItem={({ item, index }) => (
|
||||
<Box flexDirection="column" height={3}>
|
||||
{index === 0 ? (
|
||||
<Box
|
||||
sticky
|
||||
stickyChildren={<Text>[STICKY] {item.title}</Text>}
|
||||
>
|
||||
<Text>[Normal] {item.title}</Text>
|
||||
</Box>
|
||||
) : (
|
||||
<Text>[Normal] {item.title}</Text>
|
||||
)}
|
||||
<Text>Content for {item.title}</Text>
|
||||
<Text>More content for {item.title}</Text>
|
||||
</Box>
|
||||
)}
|
||||
estimatedItemHeight={() => 3}
|
||||
keyExtractor={(item) => item.id}
|
||||
hasFocus={true}
|
||||
/>
|
||||
<Box flexDirection="column" width={80} height={10}>
|
||||
<ScrollableList
|
||||
ref={ref}
|
||||
data={items}
|
||||
renderItem={({ item, index }) => (
|
||||
<Box flexDirection="column" height={3}>
|
||||
{index === 0 ? (
|
||||
<Box
|
||||
sticky
|
||||
stickyChildren={<Text>[STICKY] {item.title}</Text>}
|
||||
>
|
||||
<Text>[Normal] {item.title}</Text>
|
||||
</Box>
|
||||
) : (
|
||||
<Text>[Normal] {item.title}</Text>
|
||||
)}
|
||||
<Text>Content for {item.title}</Text>
|
||||
<Text>More content for {item.title}</Text>
|
||||
</Box>
|
||||
</ScrollProvider>
|
||||
</KeypressProvider>
|
||||
</MouseProvider>
|
||||
)}
|
||||
estimatedItemHeight={() => 3}
|
||||
keyExtractor={(item) => item.id}
|
||||
hasFocus={true}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
let lastFrame: () => string | undefined;
|
||||
let waitUntilReady: () => Promise<void>;
|
||||
let result: ReturnType<typeof render>;
|
||||
let result: ReturnType<typeof renderWithProviders>;
|
||||
await act(async () => {
|
||||
result = render(<StickyTestComponent />);
|
||||
result = renderWithProviders(<StickyTestComponent />);
|
||||
lastFrame = result.lastFrame;
|
||||
waitUntilReady = result.waitUntilReady;
|
||||
});
|
||||
@@ -334,27 +313,21 @@ describe('ScrollableList Demo Behavior', () => {
|
||||
title: `Item ${i}`,
|
||||
}));
|
||||
|
||||
let result: ReturnType<typeof render>;
|
||||
let result: ReturnType<typeof renderWithProviders>;
|
||||
await act(async () => {
|
||||
result = render(
|
||||
<MouseProvider mouseEventsEnabled={false}>
|
||||
<KeypressProvider>
|
||||
<ScrollProvider>
|
||||
<Box flexDirection="column" width={80} height={10}>
|
||||
<ScrollableList
|
||||
ref={(ref) => {
|
||||
listRef = ref;
|
||||
}}
|
||||
data={items}
|
||||
renderItem={({ item }) => <Text>{item.title}</Text>}
|
||||
estimatedItemHeight={() => 1}
|
||||
keyExtractor={(item) => item.id}
|
||||
hasFocus={true}
|
||||
/>
|
||||
</Box>
|
||||
</ScrollProvider>
|
||||
</KeypressProvider>
|
||||
</MouseProvider>,
|
||||
result = renderWithProviders(
|
||||
<Box flexDirection="column" width={80} height={10}>
|
||||
<ScrollableList
|
||||
ref={(ref) => {
|
||||
listRef = ref;
|
||||
}}
|
||||
data={items}
|
||||
renderItem={({ item }) => <Text>{item.title}</Text>}
|
||||
estimatedItemHeight={() => 1}
|
||||
keyExtractor={(item) => item.id}
|
||||
hasFocus={true}
|
||||
/>
|
||||
</Box>,
|
||||
);
|
||||
lastFrame = result.lastFrame;
|
||||
stdin = result.stdin;
|
||||
@@ -444,25 +417,19 @@ describe('ScrollableList Demo Behavior', () => {
|
||||
let lastFrame: (options?: { allowEmpty?: boolean }) => string | undefined;
|
||||
let waitUntilReady: () => Promise<void>;
|
||||
|
||||
let result: ReturnType<typeof render>;
|
||||
let result: ReturnType<typeof renderWithProviders>;
|
||||
await act(async () => {
|
||||
result = render(
|
||||
<MouseProvider mouseEventsEnabled={false}>
|
||||
<KeypressProvider>
|
||||
<ScrollProvider>
|
||||
<Box width={100} height={20}>
|
||||
<ScrollableList
|
||||
data={items}
|
||||
renderItem={({ item }) => <Text>{item.title}</Text>}
|
||||
estimatedItemHeight={() => 1}
|
||||
keyExtractor={(item) => item.id}
|
||||
hasFocus={true}
|
||||
width={50}
|
||||
/>
|
||||
</Box>
|
||||
</ScrollProvider>
|
||||
</KeypressProvider>
|
||||
</MouseProvider>,
|
||||
result = renderWithProviders(
|
||||
<Box width={100} height={20}>
|
||||
<ScrollableList
|
||||
data={items}
|
||||
renderItem={({ item }) => <Text>{item.title}</Text>}
|
||||
estimatedItemHeight={() => 1}
|
||||
keyExtractor={(item) => item.id}
|
||||
hasFocus={true}
|
||||
width={50}
|
||||
/>
|
||||
</Box>,
|
||||
);
|
||||
lastFrame = result.lastFrame;
|
||||
waitUntilReady = result.waitUntilReady;
|
||||
@@ -497,31 +464,25 @@ describe('ScrollableList Demo Behavior', () => {
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<MouseProvider mouseEventsEnabled={false}>
|
||||
<KeypressProvider>
|
||||
<ScrollProvider>
|
||||
<Box flexDirection="column" width={80} height={5}>
|
||||
<ScrollableList
|
||||
ref={(ref) => {
|
||||
listRef = ref;
|
||||
}}
|
||||
data={items}
|
||||
renderItem={({ item }) => <Text>{item.title}</Text>}
|
||||
estimatedItemHeight={() => 1}
|
||||
keyExtractor={(item) => item.id}
|
||||
hasFocus={true}
|
||||
initialScrollIndex={Number.MAX_SAFE_INTEGER}
|
||||
/>
|
||||
</Box>
|
||||
</ScrollProvider>
|
||||
</KeypressProvider>
|
||||
</MouseProvider>
|
||||
<Box flexDirection="column" width={80} height={5}>
|
||||
<ScrollableList
|
||||
ref={(ref) => {
|
||||
listRef = ref;
|
||||
}}
|
||||
data={items}
|
||||
renderItem={({ item }) => <Text>{item.title}</Text>}
|
||||
estimatedItemHeight={() => 1}
|
||||
keyExtractor={(item) => item.id}
|
||||
hasFocus={true}
|
||||
initialScrollIndex={Number.MAX_SAFE_INTEGER}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
let result: ReturnType<typeof render>;
|
||||
let result: ReturnType<typeof renderWithProviders>;
|
||||
await act(async () => {
|
||||
result = render(<TestComp />);
|
||||
result = renderWithProviders(<TestComp />);
|
||||
});
|
||||
|
||||
await result!.waitUntilReady();
|
||||
@@ -622,33 +583,27 @@ describe('ScrollableList Demo Behavior', () => {
|
||||
);
|
||||
|
||||
return (
|
||||
<MouseProvider mouseEventsEnabled={false}>
|
||||
<KeypressProvider>
|
||||
<ScrollProvider>
|
||||
<Box flexDirection="column" width={80} height={4}>
|
||||
<ScrollableList
|
||||
ref={(ref) => {
|
||||
listRef = ref;
|
||||
}}
|
||||
data={items}
|
||||
renderItem={({ item, index }) => (
|
||||
<ItemWithState item={item} isLast={index === 4} />
|
||||
)}
|
||||
estimatedItemHeight={() => 1}
|
||||
keyExtractor={(item) => item.id}
|
||||
hasFocus={true}
|
||||
initialScrollIndex={Number.MAX_SAFE_INTEGER}
|
||||
/>
|
||||
</Box>
|
||||
</ScrollProvider>
|
||||
</KeypressProvider>
|
||||
</MouseProvider>
|
||||
<Box flexDirection="column" width={80} height={4}>
|
||||
<ScrollableList
|
||||
ref={(ref) => {
|
||||
listRef = ref;
|
||||
}}
|
||||
data={items}
|
||||
renderItem={({ item, index }) => (
|
||||
<ItemWithState item={item} isLast={index === 4} />
|
||||
)}
|
||||
estimatedItemHeight={() => 1}
|
||||
keyExtractor={(item) => item.id}
|
||||
hasFocus={true}
|
||||
initialScrollIndex={Number.MAX_SAFE_INTEGER}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
let result: ReturnType<typeof render>;
|
||||
let result: ReturnType<typeof renderWithProviders>;
|
||||
await act(async () => {
|
||||
result = render(<TestComp />);
|
||||
result = renderWithProviders(<TestComp />);
|
||||
});
|
||||
|
||||
await result!.waitUntilReady();
|
||||
@@ -696,35 +651,29 @@ describe('ScrollableList Demo Behavior', () => {
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<MouseProvider mouseEventsEnabled={false}>
|
||||
<KeypressProvider>
|
||||
<ScrollProvider>
|
||||
<Box flexDirection="column" width={80} height={10}>
|
||||
<ScrollableList
|
||||
ref={(ref) => {
|
||||
listRef = ref;
|
||||
}}
|
||||
data={items}
|
||||
renderItem={({ item }) => (
|
||||
<Box height={item.id === '1' ? 10 : 2}>
|
||||
<Text>{item.title}</Text>
|
||||
</Box>
|
||||
)}
|
||||
estimatedItemHeight={() => 2}
|
||||
keyExtractor={(item) => item.id}
|
||||
hasFocus={true}
|
||||
initialScrollIndex={Number.MAX_SAFE_INTEGER}
|
||||
/>
|
||||
<Box flexDirection="column" width={80} height={10}>
|
||||
<ScrollableList
|
||||
ref={(ref) => {
|
||||
listRef = ref;
|
||||
}}
|
||||
data={items}
|
||||
renderItem={({ item }) => (
|
||||
<Box height={item.id === '1' ? 10 : 2}>
|
||||
<Text>{item.title}</Text>
|
||||
</Box>
|
||||
</ScrollProvider>
|
||||
</KeypressProvider>
|
||||
</MouseProvider>
|
||||
)}
|
||||
estimatedItemHeight={() => 2}
|
||||
keyExtractor={(item) => item.id}
|
||||
hasFocus={true}
|
||||
initialScrollIndex={Number.MAX_SAFE_INTEGER}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
let result: ReturnType<typeof render>;
|
||||
let result: ReturnType<typeof renderWithProviders>;
|
||||
await act(async () => {
|
||||
result = render(<TestComp />);
|
||||
result = renderWithProviders(<TestComp />);
|
||||
});
|
||||
|
||||
await result!.waitUntilReady();
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { render } from '../../../test-utils/render.js';
|
||||
import { renderWithProviders } from '../../../test-utils/render.js';
|
||||
import { waitFor } from '../../../test-utils/async.js';
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import {
|
||||
@@ -14,7 +14,6 @@ import {
|
||||
type SearchListState,
|
||||
type GenericListItem,
|
||||
} from './SearchableList.js';
|
||||
import { KeypressProvider } from '../../contexts/KeypressContext.js';
|
||||
import { useTextBuffer } from './text-buffer.js';
|
||||
|
||||
const useMockSearch = (props: {
|
||||
@@ -52,12 +51,6 @@ const useMockSearch = (props: {
|
||||
};
|
||||
};
|
||||
|
||||
vi.mock('../../contexts/UIStateContext.js', () => ({
|
||||
useUIState: () => ({
|
||||
mainAreaWidth: 100,
|
||||
}),
|
||||
}));
|
||||
|
||||
const mockItems: GenericListItem[] = [
|
||||
{
|
||||
key: 'item-1',
|
||||
@@ -98,11 +91,7 @@ describe('SearchableList', () => {
|
||||
...props,
|
||||
};
|
||||
|
||||
return render(
|
||||
<KeypressProvider>
|
||||
<SearchableList {...defaultProps} />
|
||||
</KeypressProvider>,
|
||||
);
|
||||
return renderWithProviders(<SearchableList {...defaultProps} />);
|
||||
};
|
||||
|
||||
it('should render all items initially', async () => {
|
||||
|
||||
@@ -5,11 +5,10 @@
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { render } from '../../../test-utils/render.js';
|
||||
import { renderWithProviders } from '../../../test-utils/render.js';
|
||||
import { waitFor } from '../../../test-utils/async.js';
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { ExtensionDetails } from './ExtensionDetails.js';
|
||||
import { KeypressProvider } from '../../contexts/KeypressContext.js';
|
||||
import { type RegistryExtension } from '../../../config/extensionRegistryClient.js';
|
||||
|
||||
const mockExtension: RegistryExtension = {
|
||||
@@ -43,15 +42,13 @@ describe('ExtensionDetails', () => {
|
||||
});
|
||||
|
||||
const renderDetails = (isInstalled = false) =>
|
||||
render(
|
||||
<KeypressProvider>
|
||||
<ExtensionDetails
|
||||
extension={mockExtension}
|
||||
onBack={mockOnBack}
|
||||
onInstall={mockOnInstall}
|
||||
isInstalled={isInstalled}
|
||||
/>
|
||||
</KeypressProvider>,
|
||||
renderWithProviders(
|
||||
<ExtensionDetails
|
||||
extension={mockExtension}
|
||||
onBack={mockOnBack}
|
||||
onInstall={mockOnInstall}
|
||||
isInstalled={isInstalled}
|
||||
/>,
|
||||
);
|
||||
|
||||
it('should render extension details correctly', async () => {
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { render } from '../../../test-utils/render.js';
|
||||
import { renderWithProviders } from '../../../test-utils/render.js';
|
||||
import { waitFor } from '../../../test-utils/async.js';
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { ExtensionRegistryView } from './ExtensionRegistryView.js';
|
||||
@@ -14,9 +14,7 @@ import { useExtensionRegistry } from '../../hooks/useExtensionRegistry.js';
|
||||
import { useExtensionUpdates } from '../../hooks/useExtensionUpdates.js';
|
||||
import { useRegistrySearch } from '../../hooks/useRegistrySearch.js';
|
||||
import { type RegistryExtension } from '../../../config/extensionRegistryClient.js';
|
||||
import { useUIState } from '../../contexts/UIStateContext.js';
|
||||
import { useConfig } from '../../contexts/ConfigContext.js';
|
||||
import { KeypressProvider } from '../../contexts/KeypressContext.js';
|
||||
import { type UIState } from '../../contexts/UIStateContext.js';
|
||||
import {
|
||||
type SearchListState,
|
||||
type GenericListItem,
|
||||
@@ -28,8 +26,6 @@ vi.mock('../../hooks/useExtensionRegistry.js');
|
||||
vi.mock('../../hooks/useExtensionUpdates.js');
|
||||
vi.mock('../../hooks/useRegistrySearch.js');
|
||||
vi.mock('../../../config/extension-manager.js');
|
||||
vi.mock('../../contexts/UIStateContext.js');
|
||||
vi.mock('../../contexts/ConfigContext.js');
|
||||
|
||||
const mockExtensions: RegistryExtension[] = [
|
||||
{
|
||||
@@ -123,34 +119,27 @@ describe('ExtensionRegistryView', () => {
|
||||
maxLabelWidth: 10,
|
||||
}) as unknown as SearchListState<GenericListItem>,
|
||||
);
|
||||
|
||||
vi.mocked(useUIState).mockReturnValue({
|
||||
mainAreaWidth: 100,
|
||||
terminalHeight: 40,
|
||||
staticExtraHeight: 5,
|
||||
} as unknown as ReturnType<typeof useUIState>);
|
||||
|
||||
vi.mocked(useConfig).mockReturnValue({
|
||||
getEnableExtensionReloading: vi.fn().mockReturnValue(false),
|
||||
getExtensionRegistryURI: vi
|
||||
.fn()
|
||||
.mockReturnValue('https://geminicli.com/extensions.json'),
|
||||
} as unknown as ReturnType<typeof useConfig>);
|
||||
});
|
||||
|
||||
const renderView = () =>
|
||||
render(
|
||||
<KeypressProvider>
|
||||
<ExtensionRegistryView
|
||||
extensionManager={mockExtensionManager}
|
||||
onSelect={mockOnSelect}
|
||||
onClose={mockOnClose}
|
||||
/>
|
||||
</KeypressProvider>,
|
||||
renderWithProviders(
|
||||
<ExtensionRegistryView
|
||||
extensionManager={mockExtensionManager}
|
||||
onSelect={mockOnSelect}
|
||||
onClose={mockOnClose}
|
||||
/>,
|
||||
{
|
||||
uiState: {
|
||||
staticExtraHeight: 5,
|
||||
terminalHeight: 40,
|
||||
} as Partial<UIState>,
|
||||
},
|
||||
);
|
||||
|
||||
it('should render extensions', async () => {
|
||||
const { lastFrame } = renderView();
|
||||
const { lastFrame, waitUntilReady } = renderView();
|
||||
await waitUntilReady();
|
||||
|
||||
await waitFor(() => {
|
||||
expect(lastFrame()).toContain('Test Extension 1');
|
||||
expect(lastFrame()).toContain('Test Extension 2');
|
||||
|
||||
Reference in New Issue
Block a user