From 32c8ac69751b1e62f893562e425815c76e9c1e6e Mon Sep 17 00:00:00 2001 From: Jarrod Whelan <150866123+jwhelangoog@users.noreply.github.com> Date: Tue, 24 Mar 2026 23:50:46 -0700 Subject: [PATCH] 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. --- packages/cli/src/test-utils/mockConfig.ts | 11 ++++ packages/cli/src/test-utils/render.tsx | 56 ++++++++----------- .../ToolGroupMessage.compact.test.tsx | 7 +-- 3 files changed, 38 insertions(+), 36 deletions(-) diff --git a/packages/cli/src/test-utils/mockConfig.ts b/packages/cli/src/test-utils/mockConfig.ts index e1505df970..cbf24c7838 100644 --- a/packages/cli/src/test-utils/mockConfig.ts +++ b/packages/cli/src/test-utils/mockConfig.ts @@ -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; diff --git a/packages/cli/src/test-utils/render.tsx b/packages/cli/src/test-utils/render.tsx index 3234498a28..a5737f6961 100644 --- a/packages/cli/src/test-utils/render.tsx +++ b/packages/cli/src/test-utils/render.tsx @@ -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; + settings?: LoadedSettings; uiState?: Partial; width?: number; mouseEventsEnabled?: boolean; - useAlternateBuffer?: boolean; config?: Config; uiActions?: Partial; + 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) => ( - - + + @@ -726,11 +711,18 @@ export const renderWithProviders = async ( ( wrapper?: React.ComponentType<{ children: React.ReactNode }>; // Options for renderWithProviders shellFocus?: boolean; - settings?: LoadedSettings | Partial; + settings?: LoadedSettings; uiState?: Partial; width?: number; mouseEventsEnabled?: boolean; diff --git a/packages/cli/src/ui/components/messages/ToolGroupMessage.compact.test.tsx b/packages/cli/src/ui/components/messages/ToolGroupMessage.compact.test.tsx index 188c037641..659ae48bbf 100644 --- a/packages/cli/src/ui/components/messages/ToolGroupMessage.compact.test.tsx +++ b/packages/cli/src/ui/components/messages/ToolGroupMessage.compact.test.tsx @@ -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[] = [