/** * @license * Copyright 2025 Google LLC * SPDX-License-Identifier: Apache-2.0 */ import { describe, it, expect, beforeEach, vi, afterEach } from 'vitest'; import { planCommand } from './planCommand.js'; import { type CommandContext } from './types.js'; import { createMockCommandContext } from '../../test-utils/mockCommandContext.js'; import { MessageType } from '../types.js'; import { ApprovalMode, coreEvents, processSingleFileContent, type ProcessedFileReadResult, } from '@google/gemini-cli-core'; vi.mock('@google/gemini-cli-core', async (importOriginal) => { const actual = await importOriginal(); return { ...actual, coreEvents: { emitFeedback: vi.fn(), }, processSingleFileContent: vi.fn(), partToString: vi.fn((val) => val), }; }); vi.mock('node:path', async (importOriginal) => { const actual = await importOriginal(); return { ...actual, default: { ...actual }, join: vi.fn((...args) => args.join('/')), }; }); describe('planCommand', () => { let mockContext: CommandContext; beforeEach(() => { mockContext = createMockCommandContext({ services: { config: { isPlanEnabled: vi.fn(), setApprovalMode: vi.fn(), getApprovedPlanPath: vi.fn(), getApprovalMode: vi.fn(), getFileSystemService: vi.fn(), storage: { getProjectTempPlansDir: vi.fn().mockReturnValue('/mock/plans/dir'), }, }, }, ui: { addItem: vi.fn(), }, } as unknown as CommandContext); vi.clearAllMocks(); }); afterEach(() => { vi.restoreAllMocks(); }); it('should have the correct name and description', () => { expect(planCommand.name).toBe('plan'); expect(planCommand.description).toBe( 'Switch to Plan Mode and view current plan', ); }); it('should switch to plan mode if enabled', async () => { vi.mocked(mockContext.services.config!.isPlanEnabled).mockReturnValue(true); vi.mocked(mockContext.services.config!.getApprovedPlanPath).mockReturnValue( undefined, ); if (!planCommand.action) throw new Error('Action missing'); await planCommand.action(mockContext, ''); expect(mockContext.services.config!.setApprovalMode).toHaveBeenCalledWith( ApprovalMode.PLAN, ); expect(coreEvents.emitFeedback).toHaveBeenCalledWith( 'info', 'Switched to Plan Mode.', ); }); it('should display the approved plan from config', async () => { const mockPlanPath = '/mock/plans/dir/approved-plan.md'; vi.mocked(mockContext.services.config!.isPlanEnabled).mockReturnValue(true); vi.mocked(mockContext.services.config!.getApprovedPlanPath).mockReturnValue( mockPlanPath, ); vi.mocked(processSingleFileContent).mockResolvedValue({ llmContent: '# Approved Plan Content', returnDisplay: '# Approved Plan Content', } as ProcessedFileReadResult); if (!planCommand.action) throw new Error('Action missing'); await planCommand.action(mockContext, ''); expect(coreEvents.emitFeedback).toHaveBeenCalledWith( 'info', 'Approved Plan: approved-plan.md', ); expect(mockContext.ui.addItem).toHaveBeenCalledWith({ type: MessageType.GEMINI, text: '# Approved Plan Content', }); }); });