Download packages/cli/src/commands/extensions/configure.test.ts from SaylorTwift/gemini-cli: direct link, hf CLI and curl.
- Browser
- Download file 8.77 kB
-
https://huggingface.co/SaylorTwift/gemini-cli/resolve/main/packages/cli/src/commands/extensions/configure.test.ts
- Command line
-
hf download hf://SaylorTwift/gemini-cli/packages/cli/src/commands/extensions/configure.test.ts
-
curl -L -o configure.test.ts https://huggingface.co/SaylorTwift/gemini-cli/resolve/main/packages/cli/src/commands/extensions/configure.test.ts
8.77 kB
| /** | |
| * @license | |
| * Copyright 2026 Google LLC | |
| * SPDX-License-Identifier: Apache-2.0 | |
| */ | |
| import { | |
| describe, | |
| it, | |
| expect, | |
| vi, | |
| beforeEach, | |
| afterEach, | |
| type Mock, | |
| } from 'vitest'; | |
| import { configureCommand } from './configure.js'; | |
| import yargs from 'yargs'; | |
| import { debugLogger } from '@google/gemini-cli-core'; | |
| import { | |
| updateSetting, | |
| getScopedEnvContents, | |
| type ExtensionSetting, | |
| } from '../../config/extensions/extensionSettings.js'; | |
| import { cleanupTmpDir } from '@google/gemini-cli-test-utils'; | |
| import prompts from 'prompts'; | |
| import * as fs from 'node:fs'; | |
| import * as os from 'node:os'; | |
| import * as path from 'node:path'; | |
| const { mockExtensionManager, mockGetExtensionManager, mockLoadSettings } = | |
| vi.hoisted(() => { | |
| const extensionManager = { | |
| loadExtensionConfig: vi.fn(), | |
| getExtensions: vi.fn(), | |
| loadExtensions: vi.fn(), | |
| getSettings: vi.fn(), | |
| }; | |
| return { | |
| mockExtensionManager: extensionManager, | |
| mockGetExtensionManager: vi.fn(), | |
| mockLoadSettings: vi.fn().mockReturnValue({ merged: {} }), | |
| }; | |
| }); | |
| vi.mock('../../config/extension-manager.js', () => ({ | |
| ExtensionManager: vi.fn().mockImplementation(() => mockExtensionManager), | |
| })); | |
| vi.mock('../../config/extensions/extensionSettings.js', () => ({ | |
| updateSetting: vi.fn(), | |
| promptForSetting: vi.fn(), | |
| getScopedEnvContents: vi.fn(), | |
| ExtensionSettingScope: { | |
| USER: 'user', | |
| WORKSPACE: 'workspace', | |
| }, | |
| })); | |
| vi.mock('../utils.js', () => ({ | |
| exitCli: vi.fn(), | |
| })); | |
| vi.mock('./utils.js', async (importOriginal) => { | |
| const actual = await importOriginal<typeof import('./utils.js')>(); | |
| return { | |
| ...actual, | |
| getExtensionManager: mockGetExtensionManager, | |
| }; | |
| }); | |
| vi.mock('prompts'); | |
| vi.mock('../../config/extensions/consent.js', () => ({ | |
| requestConsentNonInteractive: vi.fn(), | |
| })); | |
| import { ExtensionManager } from '../../config/extension-manager.js'; | |
| vi.mock('../../config/settings.js', () => ({ | |
| loadSettings: mockLoadSettings, | |
| })); | |
| describe('extensions configure command', () => { | |
| let tempWorkspaceDir: string; | |
| beforeEach(() => { | |
| vi.spyOn(debugLogger, 'log'); | |
| vi.spyOn(debugLogger, 'error'); | |
| vi.clearAllMocks(); | |
| tempWorkspaceDir = fs.mkdtempSync( | |
| path.join(os.tmpdir(), 'gemini-cli-test-workspace-'), | |
| ); | |
| vi.spyOn(process, 'cwd').mockReturnValue(tempWorkspaceDir); | |
| // Default behaviors | |
| mockLoadSettings.mockReturnValue({ merged: {} }); | |
| mockGetExtensionManager.mockResolvedValue(mockExtensionManager); | |
| (ExtensionManager as unknown as Mock).mockImplementation( | |
| () => mockExtensionManager, | |
| ); | |
| }); | |
| afterEach(async () => { | |
| await cleanupTmpDir(tempWorkspaceDir); | |
| vi.restoreAllMocks(); | |
| }); | |
| const runCommand = async (command: string) => { | |
| const parser = yargs().command(configureCommand).help(false).version(false); | |
| await parser.parse(command); | |
| }; | |
| const setupExtension = ( | |
| name: string, | |
| settings: Array<Partial<ExtensionSetting>> = [], | |
| id = 'test-id', | |
| path = '/test/path', | |
| ) => { | |
| const extension = { name, path, id }; | |
| mockExtensionManager.getExtensions.mockReturnValue([extension]); | |
| mockExtensionManager.loadExtensionConfig.mockResolvedValue({ | |
| name, | |
| settings, | |
| }); | |
| return extension; | |
| }; | |
| describe('Specific setting configuration', () => { | |
| it('should configure a specific setting', async () => { | |
| setupExtension('test-ext', [ | |
| { name: 'Test Setting', envVar: 'TEST_VAR' }, | |
| ]); | |
| (updateSetting as Mock).mockResolvedValue(undefined); | |
| await runCommand('config test-ext TEST_VAR'); | |
| expect(updateSetting).toHaveBeenCalledWith( | |
| expect.objectContaining({ name: 'test-ext' }), | |
| 'test-id', | |
| 'TEST_VAR', | |
| expect.any(Function), | |
| 'user', | |
| tempWorkspaceDir, | |
| ); | |
| }); | |
| it('should handle missing extension', async () => { | |
| mockExtensionManager.getExtensions.mockReturnValue([]); | |
| await runCommand('config missing-ext TEST_VAR'); | |
| expect(updateSetting).not.toHaveBeenCalled(); | |
| }); | |
| it('should reject invalid extension names', async () => { | |
| await runCommand('config ../invalid TEST_VAR'); | |
| expect(debugLogger.error).toHaveBeenCalledWith( | |
| expect.stringContaining('Invalid extension name'), | |
| ); | |
| await runCommand('config ext/with/slash TEST_VAR'); | |
| expect(debugLogger.error).toHaveBeenCalledWith( | |
| expect.stringContaining('Invalid extension name'), | |
| ); | |
| }); | |
| }); | |
| describe('Extension configuration (all settings)', () => { | |
| it('should configure all settings for an extension', async () => { | |
| const settings = [{ name: 'Setting 1', envVar: 'VAR_1' }]; | |
| setupExtension('test-ext', settings); | |
| (getScopedEnvContents as Mock).mockResolvedValue({}); | |
| (updateSetting as Mock).mockResolvedValue(undefined); | |
| await runCommand('config test-ext'); | |
| expect(debugLogger.log).toHaveBeenCalledWith( | |
| 'Configuring settings for "test-ext"...', | |
| ); | |
| expect(updateSetting).toHaveBeenCalledWith( | |
| expect.objectContaining({ name: 'test-ext' }), | |
| 'test-id', | |
| 'VAR_1', | |
| expect.any(Function), | |
| 'user', | |
| tempWorkspaceDir, | |
| ); | |
| }); | |
| it('should verify overwrite if setting is already set', async () => { | |
| const settings = [{ name: 'Setting 1', envVar: 'VAR_1' }]; | |
| setupExtension('test-ext', settings); | |
| (getScopedEnvContents as Mock).mockImplementation( | |
| async (_config, _id, scope) => { | |
| if (scope === 'user') return { VAR_1: 'existing' }; | |
| return {}; | |
| }, | |
| ); | |
| (prompts as unknown as Mock).mockResolvedValue({ confirm: true }); | |
| (updateSetting as Mock).mockResolvedValue(undefined); | |
| await runCommand('config test-ext'); | |
| expect(prompts).toHaveBeenCalledWith( | |
| expect.objectContaining({ | |
| type: 'confirm', | |
| message: expect.stringContaining('is already set. Overwrite?'), | |
| }), | |
| ); | |
| expect(updateSetting).toHaveBeenCalled(); | |
| }); | |
| it('should note if setting is configured in workspace', async () => { | |
| const settings = [{ name: 'Setting 1', envVar: 'VAR_1' }]; | |
| setupExtension('test-ext', settings); | |
| (getScopedEnvContents as Mock).mockImplementation( | |
| async (_config, _id, scope) => { | |
| if (scope === 'workspace') return { VAR_1: 'workspace_value' }; | |
| return {}; | |
| }, | |
| ); | |
| (updateSetting as Mock).mockResolvedValue(undefined); | |
| await runCommand('config test-ext'); | |
| expect(debugLogger.log).toHaveBeenCalledWith( | |
| expect.stringContaining('is already configured in the workspace scope'), | |
| ); | |
| }); | |
| it('should skip update if user denies overwrite', async () => { | |
| const settings = [{ name: 'Setting 1', envVar: 'VAR_1' }]; | |
| setupExtension('test-ext', settings); | |
| (getScopedEnvContents as Mock).mockResolvedValue({ VAR_1: 'existing' }); | |
| (prompts as unknown as Mock).mockResolvedValue({ confirm: false }); | |
| await runCommand('config test-ext'); | |
| expect(prompts).toHaveBeenCalled(); | |
| expect(updateSetting).not.toHaveBeenCalled(); | |
| }); | |
| }); | |
| describe('Configure all extensions', () => { | |
| it('should configure settings for all installed extensions', async () => { | |
| const ext1 = { | |
| name: 'ext1', | |
| path: '/p1', | |
| id: 'id1', | |
| settings: [{ envVar: 'V1' }], | |
| }; | |
| const ext2 = { | |
| name: 'ext2', | |
| path: '/p2', | |
| id: 'id2', | |
| settings: [{ envVar: 'V2' }], | |
| }; | |
| mockExtensionManager.getExtensions.mockReturnValue([ext1, ext2]); | |
| mockExtensionManager.loadExtensionConfig.mockImplementation( | |
| async (path) => { | |
| if (path === '/p1') | |
| return { name: 'ext1', settings: [{ name: 'S1', envVar: 'V1' }] }; | |
| if (path === '/p2') | |
| return { name: 'ext2', settings: [{ name: 'S2', envVar: 'V2' }] }; | |
| return null; | |
| }, | |
| ); | |
| (getScopedEnvContents as Mock).mockResolvedValue({}); | |
| (updateSetting as Mock).mockResolvedValue(undefined); | |
| await runCommand('config'); | |
| expect(debugLogger.log).toHaveBeenCalledWith( | |
| expect.stringContaining('Configuring settings for "ext1"'), | |
| ); | |
| expect(debugLogger.log).toHaveBeenCalledWith( | |
| expect.stringContaining('Configuring settings for "ext2"'), | |
| ); | |
| expect(updateSetting).toHaveBeenCalledTimes(2); | |
| }); | |
| it('should log if no extensions installed', async () => { | |
| mockExtensionManager.getExtensions.mockReturnValue([]); | |
| await runCommand('config'); | |
| expect(debugLogger.log).toHaveBeenCalledWith('No extensions installed.'); | |
| }); | |
| }); | |
| }); | |