Add E2E test for terminal copy selection
Verifies that selecting text in the terminal and releasing the mouse correctly copies the selection to clipboard. The test confirms the mouseup → copySelection flow works without interference from the click → focus handler. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
import { test, expect, type BrowserContext } from '@playwright/test';
|
||||
import { E2E_BACKEND_URL } from '../playwright.config';
|
||||
|
||||
// Helper to delete a specific session by ID via API
|
||||
@@ -182,6 +182,92 @@ test.describe('Tmux Terminal Session', () => {
|
||||
console.log('[Test] Tmux session properly cleaned up');
|
||||
});
|
||||
|
||||
test('copy selection from terminal works', async ({ page, request, context }) => {
|
||||
// Grant clipboard permissions
|
||||
await context.grantPermissions(['clipboard-read', 'clipboard-write']);
|
||||
|
||||
// Track session ID for cleanup
|
||||
let createdSessionId: string | null = null;
|
||||
|
||||
// 1. Navigate to homepage and create a tmux session
|
||||
await page.goto('/');
|
||||
const createButton = page.locator('button[title="New Session"]');
|
||||
await createButton.click();
|
||||
|
||||
const tmuxOption = page.locator('button:has-text("Terminal (tmux)")');
|
||||
await tmuxOption.click();
|
||||
|
||||
// Wait for navigation to session page
|
||||
await page.waitForURL(/\/session\/.+/);
|
||||
const sessionUrl = page.url();
|
||||
createdSessionId = decodeURIComponent(sessionUrl.split('/session/')[1]);
|
||||
console.log('[Test] Created session:', createdSessionId);
|
||||
|
||||
// 2. Wait for terminal to load
|
||||
const terminalOutput = page.locator('pre.text-green-400');
|
||||
await expect(terminalOutput).toBeVisible({ timeout: 10000 });
|
||||
|
||||
// 3. Run a command with unique output
|
||||
const uniqueMarker = `COPY-TEST-${Date.now()}`;
|
||||
const commandInput = page.locator('input[aria-label="Terminal input"]');
|
||||
await expect(commandInput).toBeEnabled({ timeout: 5000 });
|
||||
await commandInput.focus();
|
||||
await page.keyboard.type(`echo "${uniqueMarker}"`);
|
||||
await page.keyboard.press('Enter');
|
||||
console.log('[Test] Sent echo command with marker:', uniqueMarker);
|
||||
|
||||
// Wait for output
|
||||
await expect(async () => {
|
||||
const content = await terminalOutput.textContent();
|
||||
expect(content).toContain(uniqueMarker);
|
||||
}).toPass({ timeout: 5000 });
|
||||
console.log('[Test] Marker appeared in terminal');
|
||||
|
||||
// 4. Clear the clipboard first
|
||||
await page.evaluate(() => navigator.clipboard.writeText(''));
|
||||
|
||||
// 5. Select the marker text by triple-clicking on the line containing it
|
||||
// First, find the position of the marker in the terminal
|
||||
const terminalBox = await terminalOutput.boundingBox();
|
||||
expect(terminalBox).not.toBeNull();
|
||||
|
||||
// Get the terminal content to find the marker position
|
||||
const content = await terminalOutput.textContent();
|
||||
const lines = content?.split('\n') || [];
|
||||
const markerLineIndex = lines.findIndex(line => line.includes(uniqueMarker) && !line.includes('echo'));
|
||||
console.log('[Test] Marker found on line index:', markerLineIndex);
|
||||
|
||||
if (markerLineIndex >= 0 && terminalBox) {
|
||||
// Calculate approximate Y position of the marker line
|
||||
// Assuming ~20px per line (adjust based on actual font size)
|
||||
const lineHeight = 20;
|
||||
const yOffset = markerLineIndex * lineHeight + lineHeight / 2 + 12; // +12 for padding
|
||||
|
||||
// Triple-click to select the entire line
|
||||
await page.mouse.click(terminalBox.x + 50, terminalBox.y + yOffset, { clickCount: 3 });
|
||||
console.log('[Test] Triple-clicked to select line at y offset:', yOffset);
|
||||
|
||||
// Give a moment for the selection to register and copy to happen
|
||||
await page.waitForTimeout(200);
|
||||
|
||||
// 6. Verify clipboard contains the marker
|
||||
const clipboardContent = await page.evaluate(() => navigator.clipboard.readText());
|
||||
console.log('[Test] Clipboard content:', clipboardContent);
|
||||
|
||||
// The clipboard should contain the marker (the entire line might be selected)
|
||||
expect(clipboardContent).toContain(uniqueMarker);
|
||||
console.log('[Test] Copy selection test passed - clipboard contains marker');
|
||||
} else {
|
||||
throw new Error(`Could not find marker line in terminal output`);
|
||||
}
|
||||
|
||||
// 7. Cleanup
|
||||
if (createdSessionId) {
|
||||
await deleteSession(request, createdSessionId);
|
||||
}
|
||||
console.log('[Test] Cleanup complete');
|
||||
});
|
||||
|
||||
test('eject tmux session removes from spiceflow but keeps tmux running', async ({ page, request }) => {
|
||||
// Track session ID for cleanup
|
||||
let createdSessionId: string | null = null;
|
||||
|
||||
Reference in New Issue
Block a user