mirror of
https://github.com/garrytan/gstack.git
synced 2026-05-02 03:35:09 +02:00
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:
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user