diff --git a/apps/server/src/routes/worktree/routes/start-tests.ts b/apps/server/src/routes/worktree/routes/start-tests.ts index 72c36bd8..54837056 100644 --- a/apps/server/src/routes/worktree/routes/start-tests.ts +++ b/apps/server/src/routes/worktree/routes/start-tests.ts @@ -13,16 +13,25 @@ import { getErrorMessage, logError } from '../common.js'; export function createStartTestsHandler(settingsService?: SettingsService) { return async (req: Request, res: Response): Promise => { try { - const { worktreePath, projectPath, testFile } = req.body as { - worktreePath: string; - projectPath?: string; - testFile?: string; - }; + const body = req.body; + + // Validate request body + if (!body || typeof body !== 'object') { + res.status(400).json({ + success: false, + error: 'Request body must be an object', + }); + return; + } + + const worktreePath = typeof body.worktreePath === 'string' ? body.worktreePath : undefined; + const projectPath = typeof body.projectPath === 'string' ? body.projectPath : undefined; + const testFile = typeof body.testFile === 'string' ? body.testFile : undefined; if (!worktreePath) { res.status(400).json({ success: false, - error: 'worktreePath is required', + error: 'worktreePath is required and must be a string', }); return; } @@ -42,12 +51,6 @@ export function createStartTestsHandler(settingsService?: SettingsService) { const projectSettings = await settingsService.getProjectSettings(settingsPath); const testCommand = projectSettings?.testCommand; - // Debug logging - console.log('[StartTests] settingsPath:', settingsPath); - console.log('[StartTests] projectSettings:', JSON.stringify(projectSettings, null, 2)); - console.log('[StartTests] testCommand:', testCommand); - console.log('[StartTests] testCommand type:', typeof testCommand); - if (!testCommand) { res.status(400).json({ success: false, diff --git a/apps/server/src/routes/worktree/routes/stop-tests.ts b/apps/server/src/routes/worktree/routes/stop-tests.ts index 0027c3ef..48181f24 100644 --- a/apps/server/src/routes/worktree/routes/stop-tests.ts +++ b/apps/server/src/routes/worktree/routes/stop-tests.ts @@ -12,14 +12,23 @@ import { getErrorMessage, logError } from '../common.js'; export function createStopTestsHandler() { return async (req: Request, res: Response): Promise => { try { - const { sessionId } = req.body as { - sessionId: string; - }; + const body = req.body; + + // Validate request body + if (!body || typeof body !== 'object') { + res.status(400).json({ + success: false, + error: 'Request body must be an object', + }); + return; + } + + const sessionId = typeof body.sessionId === 'string' ? body.sessionId : undefined; if (!sessionId) { res.status(400).json({ success: false, - error: 'sessionId is required', + error: 'sessionId is required and must be a string', }); return; } diff --git a/apps/server/src/routes/worktree/routes/test-logs.ts b/apps/server/src/routes/worktree/routes/test-logs.ts index b34ebf54..724730cc 100644 --- a/apps/server/src/routes/worktree/routes/test-logs.ts +++ b/apps/server/src/routes/worktree/routes/test-logs.ts @@ -14,6 +14,39 @@ import type { Request, Response } from 'express'; import { getTestRunnerService } from '../../../services/test-runner-service.js'; import { getErrorMessage, logError } from '../common.js'; +interface SessionInfo { + sessionId: string; + worktreePath?: string; + command?: string; + testFile?: string; + exitCode?: number | null; +} + +interface OutputResult { + sessionId: string; + status: string; + output: string; + startedAt: string; + finishedAt?: string | null; +} + +function buildLogsResponse(session: SessionInfo, output: OutputResult) { + return { + success: true, + result: { + sessionId: session.sessionId, + worktreePath: session.worktreePath, + command: session.command, + status: output.status, + testFile: session.testFile, + logs: output.output, + startedAt: output.startedAt, + finishedAt: output.finishedAt, + exitCode: session.exitCode ?? null, + }, + }; +} + export function createGetTestLogsHandler() { return async (req: Request, res: Response): Promise => { try { @@ -30,20 +63,18 @@ export function createGetTestLogsHandler() { if (result.success && result.result) { const session = testRunnerService.getSession(sessionId); - res.json({ - success: true, - result: { - sessionId: result.result.sessionId, - worktreePath: session?.worktreePath, - command: session?.command, - status: result.result.status, - testFile: session?.testFile, - logs: result.result.output, - startedAt: result.result.startedAt, - finishedAt: result.result.finishedAt, - exitCode: session?.exitCode ?? null, - }, - }); + res.json( + buildLogsResponse( + { + sessionId: result.result.sessionId, + worktreePath: session?.worktreePath, + command: session?.command, + testFile: session?.testFile, + exitCode: session?.exitCode, + }, + result.result + ) + ); } else { res.status(404).json({ success: false, @@ -61,20 +92,18 @@ export function createGetTestLogsHandler() { const result = testRunnerService.getSessionOutput(activeSession.id); if (result.success && result.result) { - res.json({ - success: true, - result: { - sessionId: activeSession.id, - worktreePath: activeSession.worktreePath, - command: activeSession.command, - status: result.result.status, - testFile: activeSession.testFile, - logs: result.result.output, - startedAt: result.result.startedAt, - finishedAt: result.result.finishedAt, - exitCode: activeSession.exitCode, - }, - }); + res.json( + buildLogsResponse( + { + sessionId: activeSession.id, + worktreePath: activeSession.worktreePath, + command: activeSession.command, + testFile: activeSession.testFile, + exitCode: activeSession.exitCode, + }, + result.result + ) + ); } else { res.status(404).json({ success: false, @@ -94,20 +123,18 @@ export function createGetTestLogsHandler() { const result = testRunnerService.getSessionOutput(mostRecent.sessionId); if (result.success && result.result) { - res.json({ - success: true, - result: { - sessionId: mostRecent.sessionId, - worktreePath: mostRecent.worktreePath, - command: mostRecent.command, - status: result.result.status, - testFile: mostRecent.testFile, - logs: result.result.output, - startedAt: result.result.startedAt, - finishedAt: result.result.finishedAt, - exitCode: mostRecent.exitCode, - }, - }); + res.json( + buildLogsResponse( + { + sessionId: mostRecent.sessionId, + worktreePath: mostRecent.worktreePath, + command: mostRecent.command, + testFile: mostRecent.testFile, + exitCode: mostRecent.exitCode, + }, + result.result + ) + ); return; } } diff --git a/apps/ui/src/components/views/board-view/worktree-panel/worktree-panel.tsx b/apps/ui/src/components/views/board-view/worktree-panel/worktree-panel.tsx index d7befd12..0f42af63 100644 --- a/apps/ui/src/components/views/board-view/worktree-panel/worktree-panel.tsx +++ b/apps/ui/src/components/views/board-view/worktree-panel/worktree-panel.tsx @@ -614,7 +614,6 @@ export function WorktreePanel({ onStopTests={handleStopTests} onViewTestLogs={handleViewTestLogs} hasInitScript={hasInitScript} - hasTestCommand={hasTestCommand} /> )} diff --git a/apps/ui/src/hooks/use-test-runners.ts b/apps/ui/src/hooks/use-test-runners.ts index 7b8e90f1..9b93937e 100644 --- a/apps/ui/src/hooks/use-test-runners.ts +++ b/apps/ui/src/hooks/use-test-runners.ts @@ -174,7 +174,7 @@ export function useTestRunners(worktreePath?: string) { const result = await api.worktree.getTestLogs(worktreePath); if (result.success && result.result) { - const { sessionId, runner, status, testFile, logs, startedAt, finishedAt, exitCode } = + const { sessionId, command, status, testFile, logs, startedAt, finishedAt, exitCode } = result.result; // Only add if we don't already have this session @@ -183,7 +183,7 @@ export function useTestRunners(worktreePath?: string) { startSession({ sessionId, worktreePath, - runner, + command, status, testFile, startedAt,