Add integration test for extensions (#9177)

This commit is contained in:
christine betts
2025-09-25 19:43:09 -04:00
committed by GitHub
parent 809b933d81
commit 463e5d5b7e
2 changed files with 103 additions and 0 deletions

View File

@@ -0,0 +1,52 @@
/**
* @license
* Copyright 2025 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import { expect, test } from 'vitest';
import { TestRig } from './test-helper.js';
import { writeFileSync } from 'node:fs';
import { join } from 'node:path';
const extension = `{
"name": "test-extension",
"version": "0.0.1"
}`;
const extensionUpdate = `{
"name": "test-extension",
"version": "0.0.2"
}`;
test('installs a local extension, verifies a command, and updates it', async () => {
const rig = new TestRig();
rig.setup('extension install test');
const testServerPath = join(rig.testDir!, 'gemini-extension.json');
writeFileSync(testServerPath, extension);
try {
await rig.runCommand(['extensions', 'uninstall', 'test-extension']);
} catch {
/* empty */
}
const result = await rig.runCommand(
['extensions', 'install', `--path=${rig.testDir!}`],
{ stdin: 'y\n' },
);
expect(result).toContain('test-extension');
const listResult = await rig.runCommand(['extensions', 'list']);
expect(listResult).toContain('test-extension');
writeFileSync(testServerPath, extensionUpdate);
const updateResult = await rig.runCommand([
'extensions',
'update',
`test-extension`,
]);
expect(updateResult).toContain('0.0.2');
await rig.runCommand(['extensions', 'uninstall', 'test-extension']);
await rig.cleanup();
});

View File

@@ -309,6 +309,57 @@ export class TestRig {
return promise;
}
runCommand(
args: string[],
options: { stdin?: string } = {},
): Promise<string> {
const commandArgs = [this.bundlePath, ...args];
const child = spawn('node', commandArgs, {
cwd: this.testDir!,
stdio: 'pipe',
});
let stdout = '';
let stderr = '';
if (options.stdin) {
child.stdin!.write(options.stdin);
child.stdin!.end();
}
child.stdout!.on('data', (data: Buffer) => {
stdout += data;
if (env.KEEP_OUTPUT === 'true' || env.VERBOSE === 'true') {
process.stdout.write(data);
}
});
child.stderr!.on('data', (data: Buffer) => {
stderr += data;
if (env.KEEP_OUTPUT === 'true' || env.VERBOSE === 'true') {
process.stderr.write(data);
}
});
const promise = new Promise<string>((resolve, reject) => {
child.on('close', (code: number) => {
if (code === 0) {
this._lastRunStdout = stdout;
let result = stdout;
if (stderr) {
result += `\n\nStdErr:\n${stderr}`;
}
resolve(result);
} else {
reject(new Error(`Process exited with code ${code}:\n${stderr}`));
}
});
});
return promise;
}
readFile(fileName: string) {
const filePath = join(this.testDir!, fileName);
const content = readFileSync(filePath, 'utf-8');