/** * @license * Copyright 2025 Google LLC * SPDX-License-Identifier: Apache-2.0 */ import { render } from '../../test-utils/render.js'; import { describe, it, expect, vi, beforeEach } from 'vitest'; import { DefaultAppLayout } from './DefaultAppLayout.js'; import { StreamingState } from '../types.js'; import { Text } from 'ink'; import type { UIState } from '../contexts/UIStateContext.js'; import type { BackgroundTask } from '../hooks/useExecutionLifecycle.js'; // Mock dependencies const mockUIState = { rootUiRef: { current: null }, terminalHeight: 24, terminalWidth: 80, mainAreaWidth: 80, backgroundTasks: new Map(), activeBackgroundTaskPid: null as number | null, backgroundTaskHeight: 10, embeddedShellFocused: false, dialogsVisible: false, streamingState: StreamingState.Idle, isBackgroundTaskListOpen: false, mainControlsRef: vi.fn(), customDialog: null, historyManager: { addItem: vi.fn() }, history: [], pendingHistoryItems: [], slashCommands: [], constrainHeight: false, availableTerminalHeight: 20, activePtyId: null, isBackgroundTaskVisible: true, } as unknown as UIState; vi.mock('../contexts/UIStateContext.js', () => ({ useUIState: () => mockUIState, })); vi.mock('../contexts/AppContext.js', () => ({ useAppContext: () => ({ version: '1.2.3', startupWarnings: [] }), })); vi.mock('../hooks/useFlickerDetector.js', () => ({ useFlickerDetector: vi.fn(), })); vi.mock('../hooks/useAlternateBuffer.js', () => ({ useAlternateBuffer: vi.fn(() => false), })); vi.mock('../contexts/ConfigContext.js', () => ({ useConfig: () => ({ getAccessibility: vi.fn(() => ({ enableLoadingPhrases: true, })), }), })); // Mock child components to simplify output vi.mock('../components/LoadingIndicator.js', () => ({ LoadingIndicator: () => LoadingIndicator, })); vi.mock('../components/MainContent.js', () => ({ MainContent: () => MainContent, })); vi.mock('../components/Notifications.js', () => ({ Notifications: () => Notifications, })); vi.mock('../components/DialogManager.js', () => ({ DialogManager: () => DialogManager, })); vi.mock('../components/Composer.js', () => ({ Composer: () => Composer, })); vi.mock('../components/ExitWarning.js', () => ({ ExitWarning: () => ExitWarning, })); vi.mock('../components/CopyModeWarning.js', () => ({ CopyModeWarning: () => CopyModeWarning, })); vi.mock('../components/BackgroundTaskDisplay.js', () => ({ BackgroundTaskDisplay: () => BackgroundTaskDisplay, })); const createMockShell = (pid: number): BackgroundTask => ({ pid, command: 'test command', output: 'test output', isBinary: false, binaryBytesReceived: 0, status: 'running', }); describe('', () => { beforeEach(() => { vi.clearAllMocks(); // Reset mock state defaults mockUIState.backgroundTasks = new Map(); mockUIState.activeBackgroundTaskPid = null; mockUIState.streamingState = StreamingState.Idle; }); it('renders BackgroundTaskDisplay when shells exist and active', async () => { mockUIState.backgroundTasks.set(123, createMockShell(123)); mockUIState.activeBackgroundTaskPid = 123; mockUIState.backgroundTaskHeight = 5; const { lastFrame, unmount } = await render(); expect(lastFrame()).toMatchSnapshot(); unmount(); }); it('hides BackgroundTaskDisplay when StreamingState is WaitingForConfirmation', async () => { mockUIState.backgroundTasks.set(123, createMockShell(123)); mockUIState.activeBackgroundTaskPid = 123; mockUIState.backgroundTaskHeight = 5; mockUIState.streamingState = StreamingState.WaitingForConfirmation; const { lastFrame, unmount } = await render(); expect(lastFrame()).toMatchSnapshot(); unmount(); }); it('shows BackgroundTaskDisplay when StreamingState is NOT WaitingForConfirmation', async () => { mockUIState.backgroundTasks.set(123, createMockShell(123)); mockUIState.activeBackgroundTaskPid = 123; mockUIState.backgroundTaskHeight = 5; mockUIState.streamingState = StreamingState.Responding; const { lastFrame, unmount } = await render(); expect(lastFrame()).toMatchSnapshot(); unmount(); }); });