Fix E2E tests: gate on credentials and parse agentId robustly

This commit is contained in:
Mohamed Boudra
2026-01-23 14:47:37 +07:00
parent 3459faabc4
commit 250a320ff2
5 changed files with 62 additions and 38 deletions

View File

@@ -1133,7 +1133,7 @@ describe("CodexMcpAgentClient (MCP integration)", () => {
model: CODEX_TEST_MODEL,
reasoningEffort: CODEX_TEST_REASONING_EFFORT,
cwd,
modeId: "auto",
modeId: "read-only",
approvalPolicy: "on-request",
} satisfies AgentSessionConfig;
const filePath = path.join(cwd, "permission.txt");

View File

@@ -19,6 +19,17 @@ function tmpCwd(prefix: string): string {
return realpathSync(mkdtempSync(path.join(tmpdir(), prefix)));
}
function hasGitHubCliAuth(): boolean {
try {
execSync("gh auth status -h github.com", { stdio: "pipe" });
return true;
} catch {
return false;
}
}
const testWithGitHubCliAuth = hasGitHubCliAuth() ? test : test.skip;
type McpToolResult = {
structuredContent?: Record<string, unknown>;
content?: Array<{ structuredContent?: Record<string, unknown> } | Record<string, unknown>>;
@@ -137,7 +148,7 @@ describe("daemon checkout ship loop", () => {
await ctx.cleanup();
}, 60000);
test(
testWithGitHubCliAuth(
"runs the full checkout ship loop via checkout RPCs",
async () => {
const repoDir = tmpCwd("checkout-ship-");

View File

@@ -120,11 +120,36 @@ describe("daemon E2E", () => {
createAgentCall.type === "tool_call" &&
createAgentCall.output
) {
// The output contains the agentId
const output = createAgentCall.output as { agentId?: string };
if (output.agentId) {
childAgentId = output.agentId;
}
const output = createAgentCall.output as unknown;
const tryExtract = (value: unknown): string | null => {
if (!value) return null;
if (typeof value === "string") {
try {
return tryExtract(JSON.parse(value));
} catch {
return null;
}
}
if (typeof value !== "object") return null;
const asObj = value as Record<string, unknown>;
const direct = asObj.agentId;
if (typeof direct === "string") return direct;
const structured = asObj.structuredContent;
if (structured && typeof structured === "object") {
const nested = (structured as Record<string, unknown>).agentId;
if (typeof nested === "string") return nested;
}
if (typeof structured === "string") {
try {
return tryExtract(JSON.parse(structured));
} catch {
return null;
}
}
return null;
};
childAgentId = tryExtract(output);
}
// Verify we found the child agent ID

View File

@@ -40,7 +40,7 @@ describe("daemon E2E", () => {
provider: "codex", model: CODEX_TEST_MODEL, reasoningEffort: CODEX_TEST_REASONING_EFFORT,
cwd,
title: "Codex Permission Test",
modeId: "auto",
modeId: "read-only",
});
expect(agent.id).toBeTruthy();
@@ -105,7 +105,7 @@ describe("daemon E2E", () => {
provider: "codex", model: CODEX_TEST_MODEL, reasoningEffort: CODEX_TEST_REASONING_EFFORT,
cwd,
title: "Codex Permission Deny Test",
modeId: "auto",
modeId: "read-only",
});
expect(agent.id).toBeTruthy();

View File

@@ -17,7 +17,12 @@ function tmpCwd(): string {
const CODEX_TEST_MODEL = "gpt-5.1-codex-mini";
const CODEX_TEST_REASONING_EFFORT = "low";
describe("daemon E2E", () => {
const hasClaudeCredentials =
!!process.env.CLAUDE_SESSION_TOKEN || !!process.env.ANTHROPIC_API_KEY;
const describeWithClaude = hasClaudeCredentials ? describe : describe.skip;
describeWithClaude("daemon E2E", () => {
let ctx: DaemonTestContext;
beforeEach(async () => {
@@ -389,43 +394,26 @@ describe("daemon E2E", () => {
const queue = ctx.client.getMessageQueue();
const assistantChunks: string[] = [];
// Debug: dump all events from queue
for (let i = 0; i < queue.length; i++) {
const m = queue[i];
if (m.type === "agent_stream" && m.payload.agentId === agent.id) {
const event = m.payload.event;
if (event.type === "timeline") {
const item = event.item;
} else {
}
} else if (m.type === "agent_state" && m.payload.id === agent.id) {
}
}
// Find the user_message for message 2 to mark the boundary
let foundMsg2UserMessage = false;
// We only care about Turn 2 ("Hello world ..."), but event ordering can be noisy when
// Turn 1 is still streaming. Anchor on the assistant response content itself.
let startedCollecting = false;
for (let i = msg2StartPosition; i < queue.length; i++) {
const m = queue[i];
// Look for our user message to mark the start of message 2 context
if (
m.type === "agent_stream" &&
m.payload.agentId === agent.id &&
m.payload.event.type === "timeline"
) {
const item = m.payload.event.item;
if (item.type === "user_message" && (item.text as string)?.includes("Hello world")) {
foundMsg2UserMessage = true;
}
// Collect assistant messages after we found the user message
if (foundMsg2UserMessage && item.type === "assistant_message" && item.text) {
assistantChunks.push(item.text);
if (item.type === "assistant_message" && item.text) {
const text = String(item.text);
if (!startedCollecting && text.includes("Hello")) {
startedCollecting = true;
}
if (startedCollecting) {
assistantChunks.push(text);
}
}
}
}