mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-03-10 14:10:37 -07:00
Added image pasting capabilities for Wayland and X11 on Linux (#17144)
This commit is contained in:
110
integration-tests/clipboard-linux.test.ts
Normal file
110
integration-tests/clipboard-linux.test.ts
Normal file
@@ -0,0 +1,110 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
||||
import { TestRig } from './test-helper.js';
|
||||
import { execSync, spawnSync } from 'node:child_process';
|
||||
import * as os from 'node:os';
|
||||
import * as fs from 'node:fs';
|
||||
import * as path from 'node:path';
|
||||
|
||||
// Minimal 1x1 PNG image base64
|
||||
const DUMMY_PNG_BASE64 =
|
||||
'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg==';
|
||||
|
||||
describe('Linux Clipboard Integration', () => {
|
||||
let rig: TestRig;
|
||||
let dummyImagePath: string;
|
||||
|
||||
beforeEach(() => {
|
||||
rig = new TestRig();
|
||||
// Create a dummy image file for testing
|
||||
dummyImagePath = path.join(
|
||||
os.tmpdir(),
|
||||
`gemini-test-clipboard-${Date.now()}.png`,
|
||||
);
|
||||
fs.writeFileSync(dummyImagePath, Buffer.from(DUMMY_PNG_BASE64, 'base64'));
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await rig.cleanup();
|
||||
try {
|
||||
if (fs.existsSync(dummyImagePath)) {
|
||||
fs.unlinkSync(dummyImagePath);
|
||||
}
|
||||
} catch {
|
||||
// Ignore cleanup errors
|
||||
}
|
||||
});
|
||||
|
||||
// Only run this test on Linux
|
||||
const runIfLinux = os.platform() === 'linux' ? it : it.skip;
|
||||
|
||||
runIfLinux(
|
||||
'should paste image from system clipboard when Ctrl+V is pressed',
|
||||
async () => {
|
||||
// 1. Setup rig
|
||||
await rig.setup('linux-clipboard-paste');
|
||||
|
||||
// 2. Inject image into system clipboard
|
||||
// We attempt both Wayland and X11 tools.
|
||||
let clipboardSet = false;
|
||||
|
||||
// Try wl-copy (Wayland)
|
||||
let sessionType = '';
|
||||
const wlCopy = spawnSync('wl-copy', ['--type', 'image/png'], {
|
||||
input: fs.readFileSync(dummyImagePath),
|
||||
});
|
||||
if (wlCopy.status === 0) {
|
||||
clipboardSet = true;
|
||||
sessionType = 'wayland';
|
||||
} else {
|
||||
// Try xclip (X11)
|
||||
try {
|
||||
execSync(
|
||||
`xclip -selection clipboard -t image/png -i "${dummyImagePath}"`,
|
||||
{ stdio: 'ignore' },
|
||||
);
|
||||
clipboardSet = true;
|
||||
sessionType = 'x11';
|
||||
} catch {
|
||||
// Both failed
|
||||
}
|
||||
}
|
||||
|
||||
if (!clipboardSet) {
|
||||
console.warn(
|
||||
'Skipping test: Could not access system clipboard (wl-copy or xclip required)',
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// 3. Launch CLI and simulate Ctrl+V
|
||||
// We send the control character \u0016 (SYN) which corresponds to Ctrl+V
|
||||
// Note: The CLI must be running and accepting input.
|
||||
// The TestRig usually sends args/stdin and waits for exit or output.
|
||||
// To properly test "interactive" pasting, we need the rig to support sending input *while* running.
|
||||
// Assuming rig.run with 'stdin' sends it immediately.
|
||||
// The CLI treats stdin as typed input if it's interactive.
|
||||
|
||||
// We append a small delay or a newline to ensure processing?
|
||||
// Ctrl+V (\u0016) followed by a newline (\r) to submit?
|
||||
// Or just Ctrl+V and check if the buffer updates (which we can't easily see in non-verbose rig output).
|
||||
// If we send Ctrl+V then Enter, the CLI should submit the prompt containing the image path.
|
||||
|
||||
const result = await rig.run({
|
||||
stdin: '\u0016\r', // Ctrl+V then Enter
|
||||
env: { XDG_SESSION_TYPE: sessionType },
|
||||
});
|
||||
|
||||
// 4. Verify Output
|
||||
// Expect the CLI to have processed the image and echoed back the path (or the prompt containing it)
|
||||
// The output usually contains the user's input echoed back + model response.
|
||||
// The pasted image path should look like @.../clipboard-....png
|
||||
expect(result).toMatch(/@\/.*\.gemini-clipboard\/clipboard-.*\.png/);
|
||||
},
|
||||
);
|
||||
});
|
||||
Reference in New Issue
Block a user