Download integration-tests/extensions-reload.test.ts from SaylorTwift/gemini-cli: direct link, hf CLI and curl.
- Browser
- Download file 4.65 kB
-
https://huggingface.co/SaylorTwift/gemini-cli/resolve/main/integration-tests/extensions-reload.test.ts
- Command line
-
hf download hf://SaylorTwift/gemini-cli/integration-tests/extensions-reload.test.ts
-
curl -L -o extensions-reload.test.ts https://huggingface.co/SaylorTwift/gemini-cli/resolve/main/integration-tests/extensions-reload.test.ts
4.65 kB
| /** | |
| * @license | |
| * Copyright 2025 Google LLC | |
| * SPDX-License-Identifier: Apache-2.0 | |
| */ | |
| import { expect, it, describe, beforeEach, afterEach } from 'vitest'; | |
| import { TestRig } from './test-helper.js'; | |
| import { TestMcpServer } from './test-mcp-server.js'; | |
| import { writeFileSync } from 'node:fs'; | |
| import { join } from 'node:path'; | |
| import { safeJsonStringify } from '@google/gemini-cli-core/src/utils/safeJsonStringify.js'; | |
| import stripAnsi from 'strip-ansi'; | |
| describe('extension reloading', () => { | |
| let rig: TestRig; | |
| beforeEach(() => { | |
| rig = new TestRig(); | |
| }); | |
| afterEach(async () => await rig.cleanup()); | |
| // always fails | |
| // TODO(#14527): Re-enable this once fixed | |
| it.skip('installs a local extension, updates it, checks it was reloaded properly', async () => { | |
| const serverA = new TestMcpServer(); | |
| const portA = await serverA.start({ | |
| hello: () => ({ content: [{ type: 'text', text: 'world' }] }), | |
| }); | |
| const extension = { | |
| name: 'test-extension', | |
| version: '0.0.1', | |
| mcpServers: { | |
| 'test-server': { | |
| httpUrl: `http://localhost:${portA}/mcp`, | |
| }, | |
| }, | |
| }; | |
| rig.setup('extension reload test', { | |
| settings: { | |
| experimental: { extensionReloading: true }, | |
| }, | |
| }); | |
| const testServerPath = join(rig.testDir!, 'gemini-extension.json'); | |
| writeFileSync(testServerPath, safeJsonStringify(extension, 2)); | |
| // defensive cleanup from previous tests. | |
| try { | |
| await rig.runCommand(['extensions', 'uninstall', 'test-extension']); | |
| } catch { | |
| /* empty */ | |
| } | |
| const result = await rig.runCommand( | |
| ['--debug', 'extensions', 'install', `${rig.testDir!}`], | |
| { stdin: 'y\n' }, | |
| ); | |
| expect(result).toContain('test-extension'); | |
| // Now create the update, but its not installed yet | |
| const serverB = new TestMcpServer(); | |
| const portB = await serverB.start({ | |
| goodbye: () => ({ content: [{ type: 'text', text: 'world' }] }), | |
| }); | |
| extension.version = '0.0.2'; | |
| extension.mcpServers['test-server'].httpUrl = | |
| `http://localhost:${portB}/mcp`; | |
| writeFileSync(testServerPath, safeJsonStringify(extension, 2)); | |
| // Start the CLI. | |
| const run = await rig.runInteractive({ args: '--debug' }); | |
| await run.expectText('You have 1 extension with an update available'); | |
| // See the outdated extension | |
| await run.sendText('/extensions list'); | |
| await run.type('\r'); | |
| await run.expectText('test-extension (v0.0.1) - active (update available)'); | |
| // Wait for the UI to settle and retry the command until we see the update | |
| await new Promise((resolve) => setTimeout(resolve, 1000)); | |
| // Poll for the updated list | |
| await rig.pollCommand( | |
| async () => { | |
| await run.sendText('/mcp list'); | |
| await run.type('\r'); | |
| }, | |
| () => { | |
| const output = stripAnsi(run.output); | |
| return ( | |
| output.includes( | |
| 'test-server (from test-extension) - Ready (1 tool)', | |
| ) && output.includes('- mcp_test-server_hello') | |
| ); | |
| }, | |
| 30000, // 30s timeout | |
| ); | |
| // Update the extension, expect the list to update, and mcp servers as well. | |
| await run.sendKeys('\u0015/extensions update test-extension'); | |
| await run.expectText('/extensions update test-extension'); | |
| await run.type('\r'); | |
| await new Promise((resolve) => setTimeout(resolve, 500)); | |
| await run.type('\r'); | |
| await run.expectText( | |
| ` * test-server (remote): http://localhost:${portB}/mcp`, | |
| ); | |
| await run.type('\r'); // consent | |
| await run.expectText( | |
| 'Extension "test-extension" successfully updated: 0.0.1 → 0.0.2', | |
| ); | |
| // Poll for the updated extension version | |
| await rig.pollCommand( | |
| async () => { | |
| await run.sendText('/extensions list'); | |
| await run.type('\r'); | |
| }, | |
| () => | |
| stripAnsi(run.output).includes( | |
| 'test-extension (v0.0.2) - active (updated)', | |
| ), | |
| 30000, | |
| ); | |
| // Poll for the updated mcp tool | |
| await rig.pollCommand( | |
| async () => { | |
| await run.sendText('/mcp list'); | |
| await run.type('\r'); | |
| }, | |
| () => { | |
| const output = stripAnsi(run.output); | |
| return ( | |
| output.includes( | |
| 'test-server (from test-extension) - Ready (1 tool)', | |
| ) && output.includes('- mcp_test-server_goodbye') | |
| ); | |
| }, | |
| 30000, | |
| ); | |
| await run.sendText('/quit'); | |
| await run.type('\r'); | |
| // Clean things up. | |
| await serverA.stop(); | |
| await serverB.stop(); | |
| await rig.runCommand(['extensions', 'uninstall', 'test-extension']); | |
| }); | |
| }); | |