test: add config tests and update CLI lifecycle test

14 new tests for config resolution, ensureStateDir, readVersionHash,
resolveServerScript, and version mismatch detection. Remove obsolete
CONDUCTOR_PORT/BROWSE_PORT filtering from commands.test.ts.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Garry Tan
2026-03-13 19:45:58 -05:00
parent 63c6910fb9
commit b9125fd394
2 changed files with 126 additions and 4 deletions
+1 -4
View File
@@ -457,14 +457,11 @@ describe('CLI lifecycle', () => {
}));
const cliPath = path.resolve(__dirname, '../src/cli.ts');
// Build env without CONDUCTOR_PORT/BROWSE_PORT so BROWSE_PORT_START takes effect
const cliEnv: Record<string, string> = {};
for (const [k, v] of Object.entries(process.env)) {
if (k !== 'CONDUCTOR_PORT' && k !== 'BROWSE_PORT' && v !== undefined) cliEnv[k] = v;
if (v !== undefined) cliEnv[k] = v;
}
cliEnv.BROWSE_STATE_FILE = stateFile;
// Use a random high port to avoid conflicts with running servers
cliEnv.BROWSE_PORT_START = String(9600 + Math.floor(Math.random() * 100));
const result = await new Promise<{ code: number; stdout: string; stderr: string }>((resolve) => {
const proc = spawn('bun', ['run', cliPath, 'status'], {
timeout: 15000,
+125
View File
@@ -0,0 +1,125 @@
import { describe, test, expect } from 'bun:test';
import { resolveConfig, ensureStateDir, readVersionHash, getGitRoot } from '../src/config';
import * as fs from 'fs';
import * as path from 'path';
import * as os from 'os';
describe('config', () => {
describe('getGitRoot', () => {
test('returns a path when in a git repo', () => {
const root = getGitRoot();
expect(root).not.toBeNull();
expect(fs.existsSync(path.join(root!, '.git'))).toBe(true);
});
});
describe('resolveConfig', () => {
test('uses git root by default', () => {
const config = resolveConfig({});
const gitRoot = getGitRoot();
expect(gitRoot).not.toBeNull();
expect(config.projectDir).toBe(gitRoot);
expect(config.stateDir).toBe(path.join(gitRoot!, '.gstack'));
expect(config.stateFile).toBe(path.join(gitRoot!, '.gstack', 'browse.json'));
});
test('derives paths from BROWSE_STATE_FILE when set', () => {
const stateFile = '/tmp/test-config/.gstack/browse.json';
const config = resolveConfig({ BROWSE_STATE_FILE: stateFile });
expect(config.stateFile).toBe(stateFile);
expect(config.stateDir).toBe('/tmp/test-config/.gstack');
expect(config.projectDir).toBe('/tmp/test-config');
});
test('log paths are in stateDir', () => {
const config = resolveConfig({});
expect(config.consoleLog).toBe(path.join(config.stateDir, 'browse-console.log'));
expect(config.networkLog).toBe(path.join(config.stateDir, 'browse-network.log'));
expect(config.dialogLog).toBe(path.join(config.stateDir, 'browse-dialog.log'));
});
});
describe('ensureStateDir', () => {
test('creates directory if it does not exist', () => {
const tmpDir = path.join(os.tmpdir(), `browse-config-test-${Date.now()}`);
const config = resolveConfig({ BROWSE_STATE_FILE: path.join(tmpDir, '.gstack', 'browse.json') });
expect(fs.existsSync(config.stateDir)).toBe(false);
ensureStateDir(config);
expect(fs.existsSync(config.stateDir)).toBe(true);
// Cleanup
fs.rmSync(tmpDir, { recursive: true, force: true });
});
test('is a no-op if directory already exists', () => {
const tmpDir = path.join(os.tmpdir(), `browse-config-test-${Date.now()}`);
const stateDir = path.join(tmpDir, '.gstack');
fs.mkdirSync(stateDir, { recursive: true });
const config = resolveConfig({ BROWSE_STATE_FILE: path.join(stateDir, 'browse.json') });
ensureStateDir(config); // should not throw
expect(fs.existsSync(config.stateDir)).toBe(true);
// Cleanup
fs.rmSync(tmpDir, { recursive: true, force: true });
});
});
describe('readVersionHash', () => {
test('returns null when .version file does not exist', () => {
const result = readVersionHash('/nonexistent/path/browse');
expect(result).toBeNull();
});
test('reads version from .version file adjacent to execPath', () => {
const tmpDir = path.join(os.tmpdir(), `browse-version-test-${Date.now()}`);
fs.mkdirSync(tmpDir, { recursive: true });
const versionFile = path.join(tmpDir, '.version');
fs.writeFileSync(versionFile, 'abc123def\n');
const result = readVersionHash(path.join(tmpDir, 'browse'));
expect(result).toBe('abc123def');
// Cleanup
fs.rmSync(tmpDir, { recursive: true, force: true });
});
});
});
describe('resolveServerScript', () => {
// Import the function from cli.ts
const { resolveServerScript } = require('../src/cli');
test('uses BROWSE_SERVER_SCRIPT env when set', () => {
const result = resolveServerScript({ BROWSE_SERVER_SCRIPT: '/custom/server.ts' }, '', '');
expect(result).toBe('/custom/server.ts');
});
test('finds server.ts adjacent to cli.ts in dev mode', () => {
const srcDir = path.resolve(__dirname, '../src');
const result = resolveServerScript({}, srcDir, '');
expect(result).toBe(path.join(srcDir, 'server.ts'));
});
test('throws when server.ts cannot be found', () => {
expect(() => resolveServerScript({}, '/nonexistent/$bunfs', '/nonexistent/browse'))
.toThrow('Cannot find server.ts');
});
});
describe('version mismatch detection', () => {
test('detects when versions differ', () => {
const stateVersion = 'abc123';
const currentVersion = 'def456';
expect(stateVersion !== currentVersion).toBe(true);
});
test('no mismatch when versions match', () => {
const stateVersion = 'abc123';
const currentVersion = 'abc123';
expect(stateVersion !== currentVersion).toBe(false);
});
test('no mismatch when either version is null', () => {
const currentVersion: string | null = null;
const stateVersion: string | undefined = 'abc123';
// Version mismatch only triggers when both are present
const shouldRestart = currentVersion !== null && stateVersion !== undefined && currentVersion !== stateVersion;
expect(shouldRestart).toBe(false);
});
});