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';
|
import { E2E_BACKEND_URL } from '../playwright.config';
|
||||||
|
|
||||||
// Helper to delete a specific session by ID via API
|
// 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');
|
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 }) => {
|
test('eject tmux session removes from spiceflow but keeps tmux running', async ({ page, request }) => {
|
||||||
// Track session ID for cleanup
|
// Track session ID for cleanup
|
||||||
let createdSessionId: string | null = null;
|
let createdSessionId: string | null = null;
|
||||||
|
|||||||
Reference in New Issue
Block a user