This commit is contained in:
estill01 2026-06-03 14:36:19 +08:00 committed by GitHub
commit 55d4275894
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 135 additions and 0 deletions

View File

@ -749,6 +749,47 @@ describe('CLI lifecycle', () => {
expect(result.stdout).toContain('Status: healthy');
expect(result.stderr).toContain('Starting server');
}, 20000);
test('sequential CLI invocations reuse the same daemon and page state', async () => {
const stateFile = `/tmp/browse-test-persist-${Date.now()}.json`;
const cliPath = path.resolve(__dirname, '../src/cli.ts');
const cliEnv: Record<string, string> = {};
for (const [k, v] of Object.entries(process.env)) {
if (v !== undefined) cliEnv[k] = v;
}
cliEnv.BROWSE_STATE_FILE = stateFile;
const runCli = (args: string[]) =>
new Promise<{ code: number; stdout: string; stderr: string }>((resolve) => {
const proc = spawn('bun', ['run', cliPath, ...args], {
timeout: 15000,
env: cliEnv,
});
let stdout = '';
let stderr = '';
proc.stdout.on('data', (d) => stdout += d.toString());
proc.stderr.on('data', (d) => stderr += d.toString());
proc.on('close', (code) => resolve({ code: code ?? 1, stdout, stderr }));
});
const gotoResult = await runCli(['goto', `${baseUrl}/basic.html`]);
expect(gotoResult.code).toBe(0);
expect(gotoResult.stdout).toContain('Navigated to');
const pid1 = JSON.parse(fs.readFileSync(stateFile, 'utf-8')).pid;
const textResult = await runCli(['text']);
expect(textResult.code).toBe(0);
expect(textResult.stdout).toContain('Hello World');
const pid2 = JSON.parse(fs.readFileSync(stateFile, 'utf-8')).pid;
try { fs.unlinkSync(stateFile); } catch {}
try { process.kill(pid2, 'SIGTERM'); } catch {}
expect(pid1).toBe(pid2);
expect(textResult.stderr).not.toContain('Starting server');
}, 20000);
});
// ─── Buffer bounds ──────────────────────────────────────────────

View File

@ -0,0 +1,94 @@
import { describe, test, expect } from 'bun:test';
import * as fs from 'fs';
import * as os from 'os';
import * as path from 'path';
import { spawnSync } from 'child_process';
const ROOT = path.resolve(import.meta.dir, '..');
function makeTempDir(prefix: string): string {
return fs.mkdtempSync(path.join(os.tmpdir(), prefix));
}
function copyRepoWithoutGit(dest: string): void {
fs.cpSync(ROOT, dest, {
recursive: true,
force: true,
preserveTimestamps: true,
filter: (src) => {
const rel = path.relative(ROOT, src);
if (!rel) return true;
const top = rel.split(path.sep)[0];
return top !== '.git' && top !== 'node_modules' && top !== '.agents';
},
});
const nodeModulesSrc = path.join(ROOT, 'node_modules');
const nodeModulesDest = path.join(dest, 'node_modules');
fs.symlinkSync(
nodeModulesSrc,
nodeModulesDest,
process.platform === 'win32' ? 'junction' : 'dir'
);
}
function runSetup(cwd: string, homeDir: string): ReturnType<typeof spawnSync> {
return spawnSync('bash', ['./setup', '--host', 'codex'], {
cwd,
env: { ...process.env, HOME: homeDir },
encoding: 'utf-8',
timeout: 120_000,
});
}
describe('setup --host codex smoke', () => {
test('global install creates Codex runtime root and generated skills', () => {
const repoDir = makeTempDir('gstack-codex-global-repo-');
const homeDir = makeTempDir('gstack-codex-global-home-');
try {
copyRepoWithoutGit(repoDir);
const result = runSetup(repoDir, homeDir);
expect(result.status).toBe(0);
expect(result.stdout).toContain('gstack ready (codex).');
const runtimeRoot = path.join(homeDir, '.codex', 'skills', 'gstack');
const reviewSkill = path.join(homeDir, '.codex', 'skills', 'gstack-review', 'SKILL.md');
expect(fs.existsSync(path.join(runtimeRoot, 'SKILL.md'))).toBe(true);
expect(fs.existsSync(path.join(runtimeRoot, 'browse', 'dist'))).toBe(true);
expect(fs.existsSync(path.join(reviewSkill))).toBe(true);
expect(fs.lstatSync(path.join(homeDir, '.codex', 'skills', 'gstack-review')).isSymbolicLink()).toBe(true);
} finally {
fs.rmSync(repoDir, { recursive: true, force: true });
fs.rmSync(homeDir, { recursive: true, force: true });
}
}, 120_000);
test('repo-local install writes generated skills next to .agents checkout only', () => {
const projectDir = makeTempDir('gstack-codex-local-project-');
const homeDir = makeTempDir('gstack-codex-local-home-');
const repoDir = path.join(projectDir, '.agents', 'skills', 'gstack');
try {
fs.mkdirSync(path.dirname(repoDir), { recursive: true });
copyRepoWithoutGit(repoDir);
const result = runSetup(repoDir, homeDir);
expect(result.status).toBe(0);
expect(result.stdout).toContain('gstack ready (codex).');
const localSkill = path.join(projectDir, '.agents', 'skills', 'gstack-review', 'SKILL.md');
const localSidecar = path.join(projectDir, '.agents', 'skills', 'gstack', 'bin');
const globalSkill = path.join(homeDir, '.codex', 'skills', 'gstack-review');
expect(fs.existsSync(localSkill)).toBe(true);
expect(fs.existsSync(localSidecar)).toBe(true);
expect(fs.existsSync(globalSkill)).toBe(false);
} finally {
fs.rmSync(projectDir, { recursive: true, force: true });
fs.rmSync(homeDir, { recursive: true, force: true });
}
}, 120_000);
});