gemini-cli/packages/cli/src/ui/hooks/useConsoleMessages.test.ts

148 lines
3.8 KiB
TypeScript

/**
* @license
* Copyright 2025 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import { act, renderHook } from '@testing-library/react';
import { vi } from 'vitest';
import { useConsoleMessages } from './useConsoleMessages';
import { useCallback } from 'react';
describe('useConsoleMessages', () => {
beforeEach(() => {
vi.useFakeTimers();
});
afterEach(() => {
vi.runOnlyPendingTimers();
vi.useRealTimers();
});
const useTestableConsoleMessages = () => {
const { handleNewMessage, ...rest } = useConsoleMessages();
const log = useCallback(
(content: string) => handleNewMessage({ type: 'log', content, count: 1 }),
[handleNewMessage],
);
const error = useCallback(
(content: string) =>
handleNewMessage({ type: 'error', content, count: 1 }),
[handleNewMessage],
);
return {
...rest,
log,
error,
clearConsoleMessages: rest.clearConsoleMessages,
};
};
it('should initialize with an empty array of console messages', () => {
const { result } = renderHook(() => useTestableConsoleMessages());
expect(result.current.consoleMessages).toEqual([]);
});
it('should add a new message when log is called', async () => {
const { result } = renderHook(() => useTestableConsoleMessages());
act(() => {
result.current.log('Test message');
});
await act(async () => {
await vi.advanceTimersByTimeAsync(20);
});
expect(result.current.consoleMessages).toEqual([
{ type: 'log', content: 'Test message', count: 1 },
]);
});
it('should batch and count identical consecutive messages', async () => {
const { result } = renderHook(() => useTestableConsoleMessages());
act(() => {
result.current.log('Test message');
result.current.log('Test message');
result.current.log('Test message');
});
await act(async () => {
await vi.advanceTimersByTimeAsync(20);
});
expect(result.current.consoleMessages).toEqual([
{ type: 'log', content: 'Test message', count: 3 },
]);
});
it('should not batch different messages', async () => {
const { result } = renderHook(() => useTestableConsoleMessages());
act(() => {
result.current.log('First message');
result.current.error('Second message');
});
await act(async () => {
await vi.advanceTimersByTimeAsync(20);
});
expect(result.current.consoleMessages).toEqual([
{ type: 'log', content: 'First message', count: 1 },
{ type: 'error', content: 'Second message', count: 1 },
]);
});
it('should clear all messages when clearConsoleMessages is called', async () => {
const { result } = renderHook(() => useTestableConsoleMessages());
act(() => {
result.current.log('A message');
});
await act(async () => {
await vi.advanceTimersByTimeAsync(20);
});
expect(result.current.consoleMessages).toHaveLength(1);
act(() => {
result.current.clearConsoleMessages();
});
expect(result.current.consoleMessages).toHaveLength(0);
});
it('should clear the pending timeout when clearConsoleMessages is called', () => {
const { result } = renderHook(() => useTestableConsoleMessages());
const clearTimeoutSpy = vi.spyOn(global, 'clearTimeout');
act(() => {
result.current.log('A message');
});
act(() => {
result.current.clearConsoleMessages();
});
expect(clearTimeoutSpy).toHaveBeenCalled();
clearTimeoutSpy.mockRestore();
});
it('should clean up the timeout on unmount', () => {
const { result, unmount } = renderHook(() => useTestableConsoleMessages());
const clearTimeoutSpy = vi.spyOn(global, 'clearTimeout');
act(() => {
result.current.log('A message');
});
unmount();
expect(clearTimeoutSpy).toHaveBeenCalled();
clearTimeoutSpy.mockRestore();
});
});