mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-05-15 14:23:02 -07:00
95 lines
2.9 KiB
TypeScript
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();
|
|
});
|