Files
gemini-cli/packages/cli/test-setup.ts
T

95 lines
2.9 KiB
TypeScript

/**
* @license
* Copyright 2025 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import { vi, beforeEach, afterEach, act } from 'vitest';
import {
coreEvents,
uiTelemetryService,
resetBrowserSession,
} from '@google/gemini-cli-core';
import { themeManager } from './src/ui/themes/theme-manager.js';
import { mockInkSpinner } from './src/test-utils/mockSpinner.js';
import { cleanup } from './src/test-utils/render.js';
// Globally mock ink-spinner to prevent non-deterministic snapshot/act flakes.
mockInkSpinner();
global.IS_REACT_ACT_ENVIRONMENT = true;
// Increase max listeners to avoid warnings in large test suites
coreEvents.setMaxListeners(0);
uiTelemetryService.setMaxListeners(0);
process.setMaxListeners(0);
import './src/test-utils/customMatchers.js';
const noiseStrings = [
'was not wrapped in act(...)',
'The current testing environment is not configured to support act(...)',
'Warning: React does not recognize',
'Loading ignore patterns from',
"Can't find node-pty",
'Skipping inaccessible workspace folder',
];
// PROXY CONSOLE TO FILTER NOISE WITHOUT BREAKING SPIES
const createNoiseFilter = (method: keyof Console) => {
const original = console[method];
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(console as any)[method] = new Proxy(original, {
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
apply(target: Function, thisArg: unknown, argArray: unknown[]) {
const firstArg = String(argArray[0]);
if (noiseStrings.some((s) => firstArg.includes(s))) {
return;
}
return Reflect.apply(target, thisArg, argArray);
},
});
};
['log', 'info', 'warn', 'error', 'debug'].forEach((m) =>
createNoiseFilter(m as keyof Console),
);
// THE "HEALTHY FIX": Wrap telemetry events in act() automatically
const originalEmit = uiTelemetryService.emit;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
uiTelemetryService.emit = function (event: string | symbol, ...args: any[]) {
let result: boolean = false;
try {
act(() => {
result = originalEmit.apply(this, [event, ...args]);
});
} catch {
// If act() is not available or fails, fall back to normal emit
result = originalEmit.apply(this, [event, ...args]);
}
return result;
};
beforeEach(async () => {
// Reset singletons to ensure test isolation
themeManager.resetForTesting();
uiTelemetryService.clear();
// We do NOT remove all listeners here because it would break the
// SessionContext subscription created during component mount.
// Instead, we rely on individual tests to manage their specific listeners
// or the clear() method to reset state.
await resetBrowserSession();
// Force specific env for test stability
vi.stubEnv('FORCE_COLOR', '3');
vi.stubEnv('FORCE_GENERIC_KEYBINDING_HINTS', 'true');
vi.stubEnv('TERM_PROGRAM', 'generic');
});
afterEach(() => {
cleanup();
vi.unstubAllEnvs();
});