mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-03 14:09:42 +02:00
224 lines
7.3 KiB
TypeScript
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);
|
|
});
|