/** * test/desktop/server-config.test.ts — unit tests for buildServerEnv (B1). * * Covers the PORT / BIND_HOST / SHELL_PATH / USE_TMUX mapping, the immutability * guarantee (input.env untouched), and pass-through of unrelated env vars. */ import { execFileSync } from 'node:child_process' import { describe, test, expect } from 'vitest' import { buildServerEnv } from '../../desktop/src/server-config.js' import { loadConfig } from '../../src/config.js' import type { DesktopPrefs } from '../../desktop/src/types.js' const tmuxInstalled = (() => { try { execFileSync('tmux', ['-V'], { stdio: 'ignore' }) return true } catch { return false } })() const BASE_PREFS: DesktopPrefs = { port: null, lanSharing: false, shellPath: null, openAtLogin: false, notifyOnApproval: true, notifyOnStatusChange: true, } describe('buildServerEnv', () => { test('sets PORT to the stringified port', () => { const result = buildServerEnv({ prefs: BASE_PREFS, port: 4321, platform: 'darwin', env: {} }) expect(result.PORT).toBe('4321') }) test('binds 127.0.0.1 when lanSharing is off', () => { const result = buildServerEnv({ prefs: BASE_PREFS, port: 3000, platform: 'darwin', env: {} }) expect(result.BIND_HOST).toBe('127.0.0.1') }) test('binds 0.0.0.0 when lanSharing is on', () => { // Arrange const prefs = { ...BASE_PREFS, lanSharing: true } // Act const result = buildServerEnv({ prefs, port: 3000, platform: 'darwin', env: {} }) // Assert expect(result.BIND_HOST).toBe('0.0.0.0') }) test('uses prefs.shellPath as SHELL_PATH when provided (overriding the platform default)', () => { // Arrange const prefs = { ...BASE_PREFS, shellPath: '/usr/bin/fish' } // Act const result = buildServerEnv({ prefs, port: 3000, platform: 'darwin', env: { SHELL: '/bin/zsh' } }) // Assert expect(result.SHELL_PATH).toBe('/usr/bin/fish') }) test('falls back to the platform default SHELL_PATH when prefs.shellPath is null', () => { const win = buildServerEnv({ prefs: BASE_PREFS, port: 3000, platform: 'win32', env: {} }) expect(win.SHELL_PATH).toBe('powershell.exe') const mac = buildServerEnv({ prefs: BASE_PREFS, port: 3000, platform: 'darwin', env: { SHELL: '/bin/zsh' } }) expect(mac.SHELL_PATH).toBe('/bin/zsh') }) test('forces USE_TMUX off on win32 even when the ambient env enables it', () => { const result = buildServerEnv({ prefs: BASE_PREFS, port: 3000, platform: 'win32', env: { USE_TMUX: '1' } }) expect(result.USE_TMUX).toBe('0') }) test('passes ambient USE_TMUX through on non-Windows platforms', () => { const result = buildServerEnv({ prefs: BASE_PREFS, port: 3000, platform: 'linux', env: { USE_TMUX: '1' } }) expect(result.USE_TMUX).toBe('1') }) test('defaults USE_TMUX to auto-detect on non-Windows when the env is unset', () => { // Not '0'. Without tmux the shell is a direct child of the embedded server, so // quitting the app kills every session — which defeats the point of walking away // from a task and reconnecting later. 'auto' means "use tmux if it is installed". const result = buildServerEnv({ prefs: BASE_PREFS, port: 3000, platform: 'linux', env: {} }) expect(result.USE_TMUX).toBe('auto') }) test('an explicit ambient USE_TMUX=0 still wins — opting out stays possible', () => { const result = buildServerEnv({ prefs: BASE_PREFS, port: 3000, platform: 'darwin', env: { USE_TMUX: '0' } }) expect(result.USE_TMUX).toBe('0') }) // The bug this guards against was the two layers disagreeing: buildServerEnv emitted // a value that loadConfig then resolved to something else than intended. Assert the // end-to-end result, not just the string. test('the default resolves to tmux ON once loadConfig sees it', () => { if (!tmuxInstalled) return // 'auto' correctly resolves to false without the binary const env = buildServerEnv({ prefs: BASE_PREFS, port: 3000, platform: 'darwin', env: {} }) expect(loadConfig({ ...env, BIND_HOST: '127.0.0.1' }).useTmux).toBe(true) }) test('an explicit opt-out resolves to tmux OFF through loadConfig', () => { const env = buildServerEnv({ prefs: BASE_PREFS, port: 3000, platform: 'darwin', env: { USE_TMUX: '0' } }) expect(loadConfig({ ...env, BIND_HOST: '127.0.0.1' }).useTmux).toBe(false) }) test('does not mutate the input env', () => { // Arrange const env = { PATH: '/usr/bin', USE_TMUX: '1' } const snapshot = { ...env } // Act buildServerEnv({ prefs: BASE_PREFS, port: 3000, platform: 'win32', env }) // Assert expect(env).toEqual(snapshot) }) test('preserves unrelated ambient env vars', () => { // Arrange const env = { PATH: '/usr/bin', HOME: '/Users/me', CUSTOM: 'x' } // Act const result = buildServerEnv({ prefs: BASE_PREFS, port: 3000, platform: 'darwin', env }) // Assert expect(result.PATH).toBe('/usr/bin') expect(result.HOME).toBe('/Users/me') expect(result.CUSTOM).toBe('x') }) })