From 497c075806a2940d5376fecb92fb4985deddbd0b 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 260bafdf2b..daf109d928 100644 --- a/packages/cli/src/test-utils/mockConfig.ts +++ b/packages/cli/src/test-utils/mockConfig.ts @@ -194,6 +194,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 acdb557dd8..d718d4284c 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'; @@ -611,20 +611,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; @@ -661,34 +665,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 = { @@ -717,8 +702,8 @@ export const renderWithProviders = async ( const wrapWithProviders = (comp: React.ReactElement) => ( - - + + @@ -729,11 +714,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[] = [