add unit test for console patcher & noninteractive

This commit is contained in:
Cynthia Long
2026-03-16 21:30:16 +00:00
parent 02eff4efb3
commit c6f6fb00c9
2 changed files with 144 additions and 0 deletions
@@ -235,6 +235,30 @@ describe('runNonInteractive', () => {
const getWrittenOutput = () =>
processStdoutSpy.mock.calls.map((c) => c[0]).join('');
it('should initialize ConsolePatcher with correct value', async () => {
const { ConsolePatcher } = await import('./ui/utils/ConsolePatcher.js');
const patcherSpy = vi.spyOn(ConsolePatcher.prototype, 'patch');
const events: ServerGeminiStreamEvent[] = [
{
type: GeminiEventType.DONE,
metrics: { ...MOCK_SESSION_METRICS },
},
];
mockGeminiClient.sendMessageStream.mockReturnValueOnce(
createStreamFromEvents(events),
);
await runNonInteractive({
config: mockConfig,
settings: mockSettings,
input: 'test input',
prompt_id: 'test-prompt-id',
});
expect(patcherSpy).toHaveBeenCalled();
});
it('should process input and write text output', async () => {
const events: ServerGeminiStreamEvent[] = [
{ type: GeminiEventType.Content, value: 'Hello' },
@@ -0,0 +1,120 @@
/**
* @license
* Copyright 2025 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import { ConsolePatcher } from './ConsolePatcher.js';
describe('ConsolePatcher', () => {
let patcher: ConsolePatcher;
const onNewMessage = vi.fn();
beforeEach(() => {
vi.clearAllMocks();
});
afterEach(() => {
if (patcher) {
patcher.cleanup();
}
});
it('should suppress output when suppressConsoleOutput is true and debugMode is false', () => {
// We need to spy on the original console methods that ConsolePatcher will call
// ConsolePatcher captures the original methods at construction time or patch time?
// It captures them at construction time.
const originalLog = console.log;
const logSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
patcher = new ConsolePatcher({
debugMode: false,
suppressConsoleOutput: true,
stderr: true,
});
patcher.patch();
console.log('test log');
expect(logSpy).not.toHaveBeenCalled();
patcher.cleanup();
logSpy.mockRestore();
console.log = originalLog;
});
it('should NOT suppress output when suppressConsoleOutput is true but debugMode is true', () => {
const originalError = console.error;
const errorSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
patcher = new ConsolePatcher({
debugMode: true,
suppressConsoleOutput: true,
stderr: true,
});
patcher.patch();
console.log('test log');
// When stderr is true, log goes to originalConsoleError
expect(errorSpy).toHaveBeenCalled();
patcher.cleanup();
errorSpy.mockRestore();
console.error = originalError;
});
it('should NOT suppress output when suppressConsoleOutput is false', () => {
const originalError = console.error;
const errorSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
patcher = new ConsolePatcher({
debugMode: false,
suppressConsoleOutput: false,
stderr: true,
});
patcher.patch();
console.error('test error');
expect(errorSpy).toHaveBeenCalled();
patcher.cleanup();
errorSpy.mockRestore();
console.error = originalError;
});
it('should call onNewMessage when stderr is false and not suppressed', () => {
patcher = new ConsolePatcher({
debugMode: false,
suppressConsoleOutput: false,
stderr: false,
onNewMessage,
});
patcher.patch();
console.log('test log');
expect(onNewMessage).toHaveBeenCalledWith(expect.objectContaining({
type: 'log',
content: 'test log',
}));
patcher.cleanup();
});
it('should NOT suppress output when suppressConsoleOutput is true but debugMode is true (explicit check)', () => {
const onNewMessage = vi.fn();
patcher = new ConsolePatcher({
debugMode: true,
suppressConsoleOutput: true,
stderr: false,
onNewMessage,
});
patcher.patch();
console.log('test log');
expect(onNewMessage).toHaveBeenCalled();
patcher.cleanup();
});
});