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); }); });