Make CI independent of external CLIs
This commit is contained in:
@@ -1,10 +1,23 @@
|
|||||||
import { afterEach, beforeEach, describe, expect, test } from "vitest";
|
import { afterEach, beforeEach, describe, expect, test } from "vitest";
|
||||||
|
import { execFileSync } from "node:child_process";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
createDaemonTestContext,
|
createDaemonTestContext,
|
||||||
type DaemonTestContext,
|
type DaemonTestContext,
|
||||||
} from "../test-utils/index.js";
|
} from "../test-utils/index.js";
|
||||||
|
|
||||||
|
function isBinaryInstalled(binary: string): boolean {
|
||||||
|
try {
|
||||||
|
const out = execFileSync("which", [binary], { encoding: "utf8" }).trim();
|
||||||
|
return out.length > 0;
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const hasCodex = isBinaryInstalled("codex");
|
||||||
|
const hasOpenCode = isBinaryInstalled("opencode");
|
||||||
|
|
||||||
describe("provider model catalogs (e2e)", () => {
|
describe("provider model catalogs (e2e)", () => {
|
||||||
let ctx: DaemonTestContext;
|
let ctx: DaemonTestContext;
|
||||||
|
|
||||||
@@ -33,7 +46,7 @@ describe("provider model catalogs (e2e)", () => {
|
|||||||
180_000
|
180_000
|
||||||
);
|
);
|
||||||
|
|
||||||
test(
|
test.runIf(hasCodex)(
|
||||||
"Codex catalog exposes gpt-5.1-codex",
|
"Codex catalog exposes gpt-5.1-codex",
|
||||||
async () => {
|
async () => {
|
||||||
const result = await ctx.client.listProviderModels("codex");
|
const result = await ctx.client.listProviderModels("codex");
|
||||||
@@ -45,7 +58,7 @@ describe("provider model catalogs (e2e)", () => {
|
|||||||
180_000
|
180_000
|
||||||
);
|
);
|
||||||
|
|
||||||
test(
|
test.runIf(hasOpenCode)(
|
||||||
"OpenCode catalog returns models from multiple providers",
|
"OpenCode catalog returns models from multiple providers",
|
||||||
async () => {
|
async () => {
|
||||||
const result = await ctx.client.listProviderModels("opencode");
|
const result = await ctx.client.listProviderModels("opencode");
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { describe, test, expect, beforeEach, afterEach } from "vitest";
|
|||||||
import { mkdtempSync, rmSync } from "fs";
|
import { mkdtempSync, rmSync } from "fs";
|
||||||
import { tmpdir } from "os";
|
import { tmpdir } from "os";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
|
import { execFileSync } from "node:child_process";
|
||||||
import {
|
import {
|
||||||
createDaemonTestContext,
|
createDaemonTestContext,
|
||||||
type DaemonTestContext,
|
type DaemonTestContext,
|
||||||
@@ -49,6 +50,18 @@ function pickTwoDistinctModels(models: Array<{ id: string }>): [string, string]
|
|||||||
return [ids[0]!, ids[1]!];
|
return [ids[0]!, ids[1]!];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isBinaryInstalled(binary: string): boolean {
|
||||||
|
try {
|
||||||
|
const out = execFileSync("which", [binary], { encoding: "utf8" }).trim();
|
||||||
|
return out.length > 0;
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const hasCodex = isBinaryInstalled("codex");
|
||||||
|
const hasOpenCode = isBinaryInstalled("opencode");
|
||||||
|
|
||||||
describe("daemon E2E", () => {
|
describe("daemon E2E", () => {
|
||||||
let ctx: DaemonTestContext;
|
let ctx: DaemonTestContext;
|
||||||
let messages: SessionOutboundMessage[] = [];
|
let messages: SessionOutboundMessage[] = [];
|
||||||
@@ -71,7 +84,12 @@ describe("daemon E2E", () => {
|
|||||||
describe.each(["claude", "codex", "opencode"] as const)(
|
describe.each(["claude", "codex", "opencode"] as const)(
|
||||||
"live model switching (%s)",
|
"live model switching (%s)",
|
||||||
(provider) => {
|
(provider) => {
|
||||||
test(
|
const shouldRun =
|
||||||
|
provider === "claude" ||
|
||||||
|
(provider === "codex" && hasCodex) ||
|
||||||
|
(provider === "opencode" && hasOpenCode);
|
||||||
|
|
||||||
|
test.runIf(shouldRun)(
|
||||||
"updates agent model without restarting",
|
"updates agent model without restarting",
|
||||||
async () => {
|
async () => {
|
||||||
const cwd = tmpCwd();
|
const cwd = tmpCwd();
|
||||||
@@ -150,7 +168,7 @@ describe("daemon E2E", () => {
|
|||||||
120000
|
120000
|
||||||
);
|
);
|
||||||
|
|
||||||
test(
|
test.runIf(hasCodex)(
|
||||||
"live thinking switching works for Codex (default -> non-default)",
|
"live thinking switching works for Codex (default -> non-default)",
|
||||||
async () => {
|
async () => {
|
||||||
const cwd = tmpCwd();
|
const cwd = tmpCwd();
|
||||||
@@ -198,7 +216,7 @@ describe("daemon E2E", () => {
|
|||||||
120000
|
120000
|
||||||
);
|
);
|
||||||
|
|
||||||
test(
|
test.runIf(hasOpenCode)(
|
||||||
"live thinking switching works for OpenCode",
|
"live thinking switching works for OpenCode",
|
||||||
async () => {
|
async () => {
|
||||||
const cwd = tmpCwd();
|
const cwd = tmpCwd();
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { describe, test, expect, beforeEach, afterEach } from "vitest";
|
|||||||
import { mkdtempSync, writeFileSync, existsSync, rmSync, mkdirSync, readFileSync, readdirSync } from "fs";
|
import { mkdtempSync, writeFileSync, existsSync, rmSync, mkdirSync, readFileSync, readdirSync } from "fs";
|
||||||
import { tmpdir } from "os";
|
import { tmpdir } from "os";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
|
import { execFileSync } from "node:child_process";
|
||||||
import {
|
import {
|
||||||
createDaemonTestContext,
|
createDaemonTestContext,
|
||||||
type DaemonTestContext,
|
type DaemonTestContext,
|
||||||
@@ -15,6 +16,18 @@ function tmpCwd(): string {
|
|||||||
|
|
||||||
const CODEX_TEST_MODEL = "gpt-5.1-codex-mini";
|
const CODEX_TEST_MODEL = "gpt-5.1-codex-mini";
|
||||||
|
|
||||||
|
function isBinaryInstalled(binary: string): boolean {
|
||||||
|
try {
|
||||||
|
const out = execFileSync("which", [binary], { encoding: "utf8" }).trim();
|
||||||
|
return out.length > 0;
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const hasCodex = isBinaryInstalled("codex");
|
||||||
|
const hasOpenCode = isBinaryInstalled("opencode");
|
||||||
|
|
||||||
describe("daemon E2E", () => {
|
describe("daemon E2E", () => {
|
||||||
let ctx: DaemonTestContext;
|
let ctx: DaemonTestContext;
|
||||||
|
|
||||||
@@ -27,7 +40,7 @@ describe("daemon E2E", () => {
|
|||||||
}, 60000);
|
}, 60000);
|
||||||
|
|
||||||
describe("listProviderModels", () => {
|
describe("listProviderModels", () => {
|
||||||
test(
|
test.runIf(hasCodex)(
|
||||||
"returns model list for Codex provider",
|
"returns model list for Codex provider",
|
||||||
async () => {
|
async () => {
|
||||||
// List models for Codex provider - no agent needed
|
// List models for Codex provider - no agent needed
|
||||||
@@ -75,7 +88,7 @@ describe("daemon E2E", () => {
|
|||||||
60000 // 1 minute timeout
|
60000 // 1 minute timeout
|
||||||
);
|
);
|
||||||
|
|
||||||
test(
|
test.runIf(hasOpenCode)(
|
||||||
"returns model list for OpenCode provider",
|
"returns model list for OpenCode provider",
|
||||||
async () => {
|
async () => {
|
||||||
const result = await ctx.client.listProviderModels("opencode");
|
const result = await ctx.client.listProviderModels("opencode");
|
||||||
|
|||||||
@@ -11,7 +11,9 @@ function tmpCwd(): string {
|
|||||||
return mkdtempSync(path.join(tmpdir(), "daemon-terminal-e2e-"));
|
return mkdtempSync(path.join(tmpdir(), "daemon-terminal-e2e-"));
|
||||||
}
|
}
|
||||||
|
|
||||||
describe("daemon E2E terminal", () => {
|
const shouldRun = !process.env.CI;
|
||||||
|
|
||||||
|
(shouldRun ? describe : describe.skip)("daemon E2E terminal", () => {
|
||||||
let ctx: DaemonTestContext;
|
let ctx: DaemonTestContext;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
|
|||||||
@@ -393,7 +393,8 @@ export class TerminalManager {
|
|||||||
paneId,
|
paneId,
|
||||||
"#{pane_dead_status}",
|
"#{pane_dead_status}",
|
||||||
]);
|
]);
|
||||||
exitCode = parseInt(exitCodeStr, 10);
|
const parsed = parseInt(exitCodeStr, 10);
|
||||||
|
exitCode = Number.isFinite(parsed) ? parsed : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
commands.push({
|
commands.push({
|
||||||
@@ -448,7 +449,8 @@ export class TerminalManager {
|
|||||||
paneId,
|
paneId,
|
||||||
"#{pane_dead_status}",
|
"#{pane_dead_status}",
|
||||||
]);
|
]);
|
||||||
exitCode = parseInt(exitCodeStr, 10);
|
const parsed = parseInt(exitCodeStr, 10);
|
||||||
|
exitCode = Number.isFinite(parsed) ? parsed : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
Reference in New Issue
Block a user