test: align codex plugin version checks and stabilize init port tests

This commit is contained in:
Prateek 2026-03-07 21:02:07 +05:30
parent ea879773ec
commit db79ad9423
6 changed files with 43 additions and 52 deletions

View File

@ -2,7 +2,6 @@ import { describe, it, expect, vi, afterEach } from "vitest";
import { mkdtempSync, writeFileSync, readFileSync, rmSync, existsSync } from "node:fs";
import { join } from "node:path";
import { tmpdir } from "node:os";
import { createServer } from "node:net";
import { Command } from "commander";
import { parse as yamlParse } from "yaml";
@ -62,61 +61,42 @@ describe("init command", () => {
tmpDir = mkdtempSync(join(tmpdir(), "ao-init-test-"));
const outputPath = join(tmpDir, "agent-orchestrator.yaml");
// Occupy port 3000
const blocker = createServer();
await new Promise<void>((resolve) => {
blocker.listen(3000, "127.0.0.1", () => resolve());
});
// Mock free-port discovery to avoid relying on host port availability
const webDirModule = await import("../../src/lib/web-dir.js");
vi.spyOn(webDirModule, "findFreePort").mockResolvedValue(3001);
try {
const program = new Command();
program.exitOverride();
registerInit(program);
const program = new Command();
program.exitOverride();
registerInit(program);
vi.spyOn(console, "log").mockImplementation(() => {});
vi.spyOn(console, "log").mockImplementation(() => {});
await program.parseAsync(["node", "test", "init", "--auto", "--output", outputPath]);
await program.parseAsync(["node", "test", "init", "--auto", "--output", outputPath]);
const content = readFileSync(outputPath, "utf-8");
// Should NOT be 3000 since we're occupying it
expect(content).not.toContain("port: 3000");
// Should pick 3001 (or higher if 3001 is also taken)
const portMatch = content.match(/port: (\d+)/);
expect(portMatch).toBeTruthy();
const port = parseInt(portMatch![1], 10);
expect(port).toBeGreaterThan(3000);
expect(port).toBeLessThan(3100);
} finally {
await new Promise<void>((resolve) => blocker.close(() => resolve()));
}
const content = readFileSync(outputPath, "utf-8");
expect(content).toContain("port: 3001");
});
it("auto mode tells user when default port is busy and which port it picked", async () => {
tmpDir = mkdtempSync(join(tmpdir(), "ao-init-test-"));
const outputPath = join(tmpDir, "agent-orchestrator.yaml");
// Occupy port 3000
const blocker = createServer();
await new Promise<void>((resolve) => {
blocker.listen(3000, "127.0.0.1", () => resolve());
});
// Mock free-port discovery to avoid relying on host port availability
const webDirModule = await import("../../src/lib/web-dir.js");
vi.spyOn(webDirModule, "findFreePort").mockResolvedValue(3001);
try {
const logSpy = vi.spyOn(console, "log").mockImplementation(() => {});
const logSpy = vi.spyOn(console, "log").mockImplementation(() => {});
const program = new Command();
program.exitOverride();
registerInit(program);
const program = new Command();
program.exitOverride();
registerInit(program);
await program.parseAsync(["node", "test", "init", "--auto", "--output", outputPath]);
await program.parseAsync(["node", "test", "init", "--auto", "--output", outputPath]);
const logCalls = logSpy.mock.calls.map((args) => args.join(" "));
const busyMessage = logCalls.find((msg) => msg.includes("Port 3000 is busy"));
expect(busyMessage).toBeDefined();
expect(busyMessage).toContain("instead");
} finally {
await new Promise<void>((resolve) => blocker.close(() => resolve()));
}
const logCalls = logSpy.mock.calls.map((args) => args.join(" "));
const busyMessage = logCalls.find((msg) => msg.includes("Port 3000 is busy"));
expect(busyMessage).toBeDefined();
expect(busyMessage).toContain("instead");
});
it("auto mode writes name and sessionPrefix to project config", async () => {

View File

@ -212,7 +212,7 @@ describe("CodexAppServerClient", () => {
const params = initReq!["params"] as Record<string, unknown>;
const clientInfo = params["clientInfo"] as Record<string, unknown>;
expect(clientInfo["name"]).toBe("ao-agent-codex");
expect(clientInfo["version"]).toBe("0.1.0");
expect(clientInfo["version"]).toBe("0.1.1");
await closeClient(client, proc);
});

View File

@ -379,7 +379,7 @@ export class CodexAppServerClient extends EventEmitter {
clientInfo: {
name: "ao-agent-codex",
title: "Agent Orchestrator — Codex Plugin",
version: "0.1.0",
version: "0.1.1",
},
});

View File

@ -187,7 +187,7 @@ describe("plugin manifest & exports", () => {
name: "codex",
slot: "agent",
description: "Agent plugin: OpenAI Codex CLI",
version: "0.1.0",
version: "0.1.1",
});
});
@ -1330,7 +1330,7 @@ describe("setupWorkspaceHooks", () => {
// Second call for AGENTS.md — file doesn't exist
mockReadFile.mockImplementation((path: string) => {
if (typeof path === "string" && path.endsWith(".ao-version")) {
return Promise.resolve("0.1.0");
return Promise.resolve("0.1.1");
}
// AGENTS.md read attempt
return Promise.reject(new Error("ENOENT"));
@ -1370,7 +1370,7 @@ describe("setupWorkspaceHooks", () => {
typeof call[0] === "string" && call[0].includes(".ao-version.tmp."),
);
expect(versionWriteCall).toBeDefined();
expect(versionWriteCall![1]).toBe("0.1.0");
expect(versionWriteCall![1]).toBe("0.1.1");
const versionRenameCall = mockRename.mock.calls.find(
(call: string[]) => typeof call[1] === "string" && call[1].endsWith(".ao-version"),
@ -1383,7 +1383,7 @@ describe("setupWorkspaceHooks", () => {
// AGENTS.md exists without ao section
mockReadFile.mockImplementation((path: string) => {
if (typeof path === "string" && path.endsWith(".ao-version")) {
return Promise.resolve("0.1.0");
return Promise.resolve("0.1.1");
}
if (typeof path === "string" && path.endsWith("AGENTS.md")) {
return Promise.resolve("# Existing Content\n\nSome stuff here.\n");
@ -1408,7 +1408,7 @@ describe("setupWorkspaceHooks", () => {
// Version marker matches, AGENTS.md doesn't exist
mockReadFile.mockImplementation((path: string) => {
if (typeof path === "string" && path.endsWith(".ao-version")) {
return Promise.resolve("0.1.0");
return Promise.resolve("0.1.1");
}
return Promise.reject(new Error("ENOENT"));
});
@ -1455,7 +1455,7 @@ describe("setupWorkspaceHooks", () => {
it("does not duplicate ao section in AGENTS.md if already present", async () => {
mockReadFile.mockImplementation((path: string) => {
if (typeof path === "string" && path.endsWith(".ao-version")) {
return Promise.resolve("0.1.0");
return Promise.resolve("0.1.1");
}
if (typeof path === "string" && path.endsWith("AGENTS.md")) {
return Promise.resolve("# Existing\n\n## Agent Orchestrator (ao) Session\n\nAlready here.\n");

View File

@ -35,7 +35,7 @@ export const manifest = {
name: "codex",
slot: "agent" as const,
description: "Agent plugin: OpenAI Codex CLI",
version: "0.1.0",
version: "0.1.1",
};
// =============================================================================
@ -240,7 +240,7 @@ async function setupCodexWorkspace(workspacePath: string): Promise<void> {
// Only write wrappers if they don't exist or are outdated (check marker)
const markerPath = join(AO_BIN_DIR, ".ao-version");
const currentVersion = "0.1.0";
const currentVersion = "0.1.1";
let needsUpdate = true;
try {
const existing = await readFile(markerPath, "utf-8");

View File

@ -0,0 +1,11 @@
import { describe, expect, it } from "vitest";
import { readFileSync } from "node:fs";
describe("package manifest version", () => {
it("is bumped to 0.1.1", () => {
const packageJsonUrl = new URL("../package.json", import.meta.url);
const packageJson = JSON.parse(readFileSync(packageJsonUrl, "utf8")) as { version?: string };
expect(packageJson.version).toBe("0.1.1");
});
});