diff --git a/test/quick-start.test.ts b/test/quick-start.test.ts index 107654e1..3ff346f5 100644 --- a/test/quick-start.test.ts +++ b/test/quick-start.test.ts @@ -4,7 +4,7 @@ import { existsSync, rmSync, mkdirSync, mkdtempSync } from 'node:fs'; import { join } from 'node:path'; import { tmpdir } from 'node:os'; -const TEST_PORT = 3099; +const TEST_PORT = 3299; const ORIGINAL_HOME = process.env.HOME; const TEST_HOME = mkdtempSync(join(tmpdir(), 'codeman-quick-start-')); const CASES_DIR = join(TEST_HOME, 'codeman-cases'); @@ -33,7 +33,7 @@ describe('Quick Start API', () => { server = await createTestServer(TEST_PORT); await server.start(); baseUrl = `http://localhost:${TEST_PORT}`; - }); + }, 30000); afterEach(() => { // Clean up cases created during this test diff --git a/test/respawn-test-plan.md b/test/respawn-test-plan.md index aada16eb..31afc51a 100644 --- a/test/respawn-test-plan.md +++ b/test/respawn-test-plan.md @@ -183,7 +183,7 @@ Integration tests that spawn web servers use unique ports to avoid conflicts. | Port | Test File | Notes | |-------|------------------------------|----------------------------------| -| 3099 | quick-start.test.ts | Basic startup tests | +| 3299 | quick-start.test.ts | Basic startup tests | | 3102 | session.test.ts | Session lifecycle tests | | 3105 | scheduled-runs.test.ts | Scheduled task tests | | 3107 | sse-events.test.ts | Server-Sent Events tests | diff --git a/test/setup.ts b/test/setup.ts index a7bed796..0ef7e35b 100644 --- a/test/setup.ts +++ b/test/setup.ts @@ -35,6 +35,12 @@ process.env.HOME = testHome; process.env.USERPROFILE = testHome; process.env.VITEST = 'true'; +for (const key of Object.keys(process.env)) { + if (key.startsWith('CODEMAN_')) delete process.env[key]; +} + +// Explicitly document the most consequential inherited settings below. The +// loop above intentionally also catches future container/deployment variables. delete process.env.CODEMAN_PASSWORD; delete process.env.CODEMAN_USERNAME; // Gesture availability changes renderIndexHtml output (injects the @@ -84,6 +90,9 @@ delete process.env.CLAUDE_CONFIG_DIR; delete process.env.CODEMAN_INSTANCE; delete process.env.CODEMAN_DATA_DIR; delete process.env.CODEMAN_TMUX_SOCKET; +// Docker Compose binds cases outside HOME. Leaving this set makes route tests +// write into the deployment's real case root instead of their temp HOME. +delete process.env.CODEMAN_CASES_PATH; afterEach(() => { vi.clearAllMocks(); diff --git a/test/test-env-isolation.test.ts b/test/test-env-isolation.test.ts index c1097dd8..9ea5e0c7 100644 --- a/test/test-env-isolation.test.ts +++ b/test/test-env-isolation.test.ts @@ -35,6 +35,7 @@ const STRIPPED_ENV_VARS: Array<[name: string, why: string]> = [ ['CODEMAN_DATA_DIR', 'ABSOLUTE override: bypasses the temp HOME and points the suite at a real data dir'], ['CODEMAN_TMUX_SOCKET', 'renames the socket resolveTmuxSocketName() returns'], ['CLAUDE_CONFIG_DIR', 'relocates the Claude tree, so transcript fixtures under the temp HOME read as missing'], + ['CODEMAN_CASES_PATH', 'bypasses the temporary HOME and points case routes at a deployment bind mount'], ]; const SETUP_SOURCE = readFileSync(fileURLToPath(new URL('./setup.ts', import.meta.url)), 'utf-8'); @@ -49,6 +50,10 @@ const SETUP_SOURCE = readFileSync(fileURLToPath(new URL('./setup.ts', import.met const SETUP_STRIP_SECTION = SETUP_SOURCE.split(/^afterEach\(/m)[0]; describe('test environment isolation', () => { + it('removes every inherited CODEMAN_* environment variable', () => { + expect(Object.keys(process.env).filter((key) => key.startsWith('CODEMAN_'))).toEqual([]); + }); + it.each(STRIPPED_ENV_VARS)('%s is unset while the suite runs', (name) => { expect(process.env[name], `${name} leaked into the test environment`).toBeUndefined(); });