test(cli): refine settings and tool action mocks to resolve test rig regressions

This update addresses incomplete settings store contracts and default state mismatches that caused snapshot runtime errors and verification failures in compact tool output tests.

1. Settings Mock Completeness:
- Updated `createMockSettings` in `mockConfig.ts` to include required functional methods (`subscribe`, `getSnapshot`, `setValue`) to satisfy React's `useSyncExternalStore` contract. This resolves "store.getSnapshot is not a function" errors in snapshot tests.

2. Tool Actions Provider Configuration:
- Modified `renderWithProviders` to accept a `toolActions` options object, allowing individual tests to inject specific tool expansion states.
- Changed the default mock for `isExpanded` from `true` to `false` to align with the application's default behavior (collapsed outputs) in alternate buffer mode.

3. Test Refactoring:
- Refactored `ToolGroupMessage.compact.test.tsx` to use the standardized `createMockSettings` utility rather than a manual generic object, ensuring proper context evaluation during rendering.
This commit is contained in:
Jarrod Whelan
2026-03-24 23:50:46 -07:00
parent 39c95a177e
commit 32c8ac6975
3 changed files with 38 additions and 36 deletions

View File

@@ -193,6 +193,17 @@ export function createMockSettings(
user: { settings: {} },
workspace: { settings: {} },
errors: [],
subscribe: vi.fn().mockReturnValue(() => {}),
getSnapshot: vi.fn().mockReturnValue({
system: { settings: {} },
systemDefaults: { settings: {} },
user: { settings: {} },
workspace: { settings: {} },
isTrusted: true,
errors: [],
merged,
}),
setValue: vi.fn(),
...overrides,
merged,
} as unknown as LoadedSettings;

View File

@@ -16,7 +16,7 @@ import { vi } from 'vitest';
import stripAnsi from 'strip-ansi';
import type React from 'react';
import { act, useState } from 'react';
import { LoadedSettings } from '../config/settings.js';
import type { LoadedSettings } from '../config/settings.js';
import { KeypressProvider } from '../ui/contexts/KeypressContext.js';
import { SettingsContext } from '../ui/contexts/SettingsContext.js';
import { ShellFocusContext } from '../ui/contexts/ShellFocusContext.js';
@@ -608,20 +608,24 @@ export const renderWithProviders = async (
uiState: providedUiState,
width,
mouseEventsEnabled = false,
useAlternateBuffer: explicitUseAlternateBuffer,
config,
uiActions,
toolActions,
persistentState,
appState = mockAppState,
}: {
shellFocus?: boolean;
settings?: LoadedSettings | Partial<LoadedSettings['merged']>;
settings?: LoadedSettings;
uiState?: Partial<UIState>;
width?: number;
mouseEventsEnabled?: boolean;
useAlternateBuffer?: boolean;
config?: Config;
uiActions?: Partial<UIActions>;
toolActions?: Partial<{
isExpanded: (callId: string) => boolean;
toggleExpansion: (callId: string) => void;
toggleAllExpansion: (callIds: string[]) => void;
}>;
persistentState?: {
get?: typeof persistentStateMock.get;
set?: typeof persistentStateMock.set;
@@ -658,34 +662,15 @@ export const renderWithProviders = async (
const terminalWidth = width ?? baseState.terminalWidth;
const finalSettings =
settings instanceof LoadedSettings
? settings
: createMockSettings(settings || {});
if (!config) {
config = await loadCliConfig(
finalSettings.merged,
settings.merged,
'random-session-id',
{} as CliArgs,
{} as unknown as CliArgs,
{ cwd: '/' },
);
}
const useAlternateBuffer =
explicitUseAlternateBuffer ??
finalSettings.merged.ui?.useAlternateBuffer ??
false;
const finalConfig = new Proxy(config, {
get(target, prop) {
if (prop === 'getUseAlternateBuffer') {
return () => useAlternateBuffer;
}
return Reflect.get(target, prop);
},
});
const mainAreaWidth = providedUiState?.mainAreaWidth ?? terminalWidth;
const finalUiState = {
@@ -714,8 +699,8 @@ export const renderWithProviders = async (
const wrapWithProviders = (comp: React.ReactElement) => (
<AppContext.Provider value={appState}>
<ConfigContext.Provider value={finalConfig}>
<SettingsContext.Provider value={finalSettings}>
<ConfigContext.Provider value={config}>
<SettingsContext.Provider value={settings}>
<UIStateContext.Provider value={finalUiState}>
<VimModeProvider>
<ShellFocusContext.Provider value={shellFocus}>
@@ -726,11 +711,18 @@ export const renderWithProviders = async (
<UIActionsContext.Provider value={finalUIActions}>
<OverflowProvider>
<ToolActionsProvider
config={finalConfig}
config={config}
toolCalls={allToolCalls}
isExpanded={vi.fn().mockReturnValue(false)}
toggleExpansion={vi.fn()}
toggleAllExpansion={vi.fn()}
isExpanded={
toolActions?.isExpanded ??
vi.fn().mockReturnValue(false)
}
toggleExpansion={
toolActions?.toggleExpansion ?? vi.fn()
}
toggleAllExpansion={
toolActions?.toggleAllExpansion ?? vi.fn()
}
>
<AskUserActionsProvider
request={null}
@@ -855,7 +847,7 @@ export async function renderHookWithProviders<Result, Props>(
wrapper?: React.ComponentType<{ children: React.ReactNode }>;
// Options for renderWithProviders
shellFocus?: boolean;
settings?: LoadedSettings | Partial<LoadedSettings['merged']>;
settings?: LoadedSettings;
uiState?: Partial<UIState>;
width?: number;
mouseEventsEnabled?: boolean;

View File

@@ -5,6 +5,7 @@
*/
import { renderWithProviders } from '../../../test-utils/render.js';
import { createMockSettings } from '../../../test-utils/mockConfig.js';
import { ToolGroupMessage } from './ToolGroupMessage.js';
import {
CoreToolCallStatus,
@@ -13,7 +14,6 @@ import {
} from '@google/gemini-cli-core';
import { expect, it, describe } from 'vitest';
import type { IndividualToolCallDisplay } from '../../types.js';
import type { LoadedSettings } from '../../../config/settings.js';
describe('ToolGroupMessage Compact Rendering', () => {
const defaultProps = {
@@ -27,14 +27,13 @@ describe('ToolGroupMessage Compact Rendering', () => {
terminalWidth: 80,
};
const compactSettings: LoadedSettings = {
const compactSettings = createMockSettings({
merged: {
ui: {
compactToolOutput: true,
},
},
sources: [],
} as unknown as LoadedSettings; // Test mock of settings
});
it('renders consecutive compact tools without empty lines between them', async () => {
const toolCalls: IndividualToolCallDisplay[] = [