Files
Codeman/test/e2e/workflows/quick-start.e2e.ts
T
2026-01-30 22:25:59 +01:00

224 lines
7.3 KiB
TypeScript

/**
* Quick Start E2E Test - THE critical test
* Tests the complete flow: click button -> case created -> session created -> screen created -> terminal visible
*
* Port: 3183 (see CLAUDE.md test port table)
*/
import { describe, it, expect, afterAll } from 'vitest';
import { execSync } from 'node:child_process';
import {
createServerFixture,
destroyServerFixture,
createBrowserFixture,
destroyBrowserFixture,
navigateTo,
waitForVisible,
clickElement,
getText,
isVisible,
CleanupTracker,
captureAndCompare,
type ServerFixture,
type BrowserFixture,
} from '../fixtures/index.js';
import { E2E_PORTS, E2E_TIMEOUTS, generateCaseName } from '../e2e.config.js';
const PORT = E2E_PORTS.QUICK_START;
let serverFixture: ServerFixture | null = null;
let cleanup: CleanupTracker;
/**
* Helper to create a case via API and select it in the dropdown
*/
async function createAndSelectCase(baseUrl: string, page: any, caseName: string): Promise<void> {
// Create case via API
const createRes = await fetch(`${baseUrl}/api/cases`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: caseName }),
});
expect(createRes.ok).toBe(true);
// Refresh page to get updated case list
await page.reload({ waitUntil: 'domcontentloaded' });
await page.waitForTimeout(500);
// Select the case in dropdown
await page.selectOption('#quickStartCase', caseName);
}
describe('Quick Start E2E', () => {
afterAll(async () => {
if (cleanup) {
await cleanup.forceCleanupAll();
}
if (serverFixture) {
await destroyServerFixture(serverFixture);
}
}, E2E_TIMEOUTS.TEST);
it('should create session with real screen via quick-start button', async () => {
let browser: BrowserFixture | null = null;
const caseName = generateCaseName('quickstart');
try {
// Start server
serverFixture = await createServerFixture(PORT);
cleanup = new CleanupTracker(serverFixture.baseUrl);
cleanup.trackCase(caseName);
// Launch browser
browser = await createBrowserFixture();
const { page } = browser;
// Navigate to Claudeman
await navigateTo(page, serverFixture.baseUrl);
// Verify page loaded
const title = await page.title();
expect(title).toBe('Claudeman');
// Create case via API and select it
await createAndSelectCase(serverFixture.baseUrl, page, caseName);
// Click the Claude button to create session
await clickElement(page, '.btn-claude');
// Wait for session tab to appear (this is the critical moment)
await page.waitForSelector('.session-tab', { timeout: E2E_TIMEOUTS.SESSION_CREATE });
// Verify tab is active
expect(await isVisible(page, '.session-tab.active')).toBe(true);
// Get session ID from API
const response = await fetch(`${serverFixture.baseUrl}/api/sessions`);
const data = await response.json();
const session = data?.find((s: any) => s.workingDir?.includes(caseName));
expect(session).toBeDefined();
cleanup.trackSession(session.id);
// CRITICAL: Verify a real screen was created
// Screen names are claudeman-{sessionId.slice(0,8)}
// This is what would have caught the cpulimit bug
const screenList = execSync('screen -ls 2>/dev/null || true', {
encoding: 'utf-8',
timeout: 5000,
});
const sessionIdPrefix = session.id.slice(0, 8);
const screenMatch = screenList.includes(`claudeman-${sessionIdPrefix}`);
expect(screenMatch).toBe(true);
// Track the screen for cleanup
cleanup.trackScreen(`claudeman-${sessionIdPrefix}`);
// Wait for terminal to be visible
await page.waitForSelector('.xterm', { timeout: E2E_TIMEOUTS.TERMINAL_VISIBLE });
expect(await isVisible(page, '.xterm')).toBe(true);
// Take screenshot for visual regression
const screenshotResult = await captureAndCompare(page, 'quick-start-session-created', {
mask: ['.xterm-screen'], // Mask terminal content as it varies
});
expect(screenshotResult.passed).toBe(true);
} finally {
if (browser) {
await destroyBrowserFixture(browser);
}
}
}, E2E_TIMEOUTS.TEST);
it('should show screen exists after session creation', async () => {
let browser: BrowserFixture | null = null;
const caseName = generateCaseName('screen-verify');
try {
if (!serverFixture) {
serverFixture = await createServerFixture(PORT);
}
if (!cleanup) {
cleanup = new CleanupTracker(serverFixture.baseUrl);
}
cleanup.trackCase(caseName);
browser = await createBrowserFixture();
const { page } = browser;
await navigateTo(page, serverFixture.baseUrl);
await createAndSelectCase(serverFixture.baseUrl, page, caseName);
await clickElement(page, '.btn-claude');
// Wait for session
await page.waitForSelector('.session-tab', { timeout: E2E_TIMEOUTS.SESSION_CREATE });
// Get session from API
const response = await fetch(`${serverFixture.baseUrl}/api/sessions`);
const data = await response.json();
expect(data?.length).toBeGreaterThan(0);
const session = data.find((s: any) => s.workingDir?.includes(caseName));
expect(session).toBeDefined();
cleanup.trackSession(session.id);
// Verify screen exists using cleanup tracker method
// Screen name is claudeman-{sessionId.slice(0,8)}
const screenName = `claudeman-${session.id.slice(0, 8)}`;
const screenExists = cleanup.screenExists(screenName);
expect(screenExists).toBe(true);
} finally {
if (browser) {
await destroyBrowserFixture(browser);
}
}
}, E2E_TIMEOUTS.TEST);
it('should display tab counter correctly', async () => {
let browser: BrowserFixture | null = null;
const caseName = generateCaseName('tab-counter');
try {
if (!serverFixture) {
serverFixture = await createServerFixture(PORT);
}
if (!cleanup) {
cleanup = new CleanupTracker(serverFixture.baseUrl);
}
cleanup.trackCase(caseName);
browser = await createBrowserFixture();
const { page } = browser;
await navigateTo(page, serverFixture.baseUrl);
// Check initial tab count (may have restored sessions from previous tests)
const initialCountStr = await getText(page, '#tabCount');
const initialCount = parseInt(initialCountStr, 10) || 0;
// Create case and session
await createAndSelectCase(serverFixture.baseUrl, page, caseName);
await clickElement(page, '.btn-claude');
await page.waitForSelector('.session-tab', { timeout: E2E_TIMEOUTS.SESSION_CREATE });
// Check tab count increased
await new Promise(r => setTimeout(r, 500)); // Wait for UI update
const newCountStr = await getText(page, '#tabCount');
const newCount = parseInt(newCountStr, 10) || 0;
expect(newCount).toBeGreaterThan(initialCount);
// Track for cleanup
const response = await fetch(`${serverFixture.baseUrl}/api/sessions`);
const data = await response.json();
if (data?.length > 0) {
cleanup.trackSession(data[data.length - 1].id);
}
} finally {
if (browser) {
await destroyBrowserFixture(browser);
}
}
}, E2E_TIMEOUTS.TEST);
});