Files
openclaw/src/agents/cli-runner.binding-flush.test.ts
2026-05-31 03:30:37 -04:00

112 lines
3.8 KiB
TypeScript

import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import {
isCliBindingFlushed,
restoreCliRunnerTestDeps,
setCliRunnerTestDeps,
} from "./cli-runner.js";
describe("isCliBindingFlushed", () => {
const workspaceDir = "/tmp/openclaw-workspace";
beforeEach(() => {
vi.useRealTimers();
restoreCliRunnerTestDeps();
});
afterEach(() => {
vi.clearAllTimers();
vi.useRealTimers();
restoreCliRunnerTestDeps();
});
it("returns false when no sessionId is provided", async () => {
const probe = vi.fn(async () => true);
setCliRunnerTestDeps({ claudeCliSessionTranscriptHasContent: probe });
expect(await isCliBindingFlushed(undefined, "claude-cli")).toBe(false);
expect(probe).not.toHaveBeenCalled();
});
it("returns true when the transcript has content on the first probe", async () => {
const probe = vi.fn(async () => true);
setCliRunnerTestDeps({ claudeCliSessionTranscriptHasContent: probe });
expect(await isCliBindingFlushed("sid-fresh", "claude-cli", workspaceDir)).toBe(true);
expect(probe).toHaveBeenCalledTimes(1);
expect(probe).toHaveBeenCalledWith({ sessionId: "sid-fresh", workspaceDir });
});
it("retries up to three times before giving up", async () => {
vi.useFakeTimers();
const probe = vi.fn(async () => false);
setCliRunnerTestDeps({ claudeCliSessionTranscriptHasContent: probe });
const resultPromise = isCliBindingFlushed("sid-cold", "claude-cli", workspaceDir);
await vi.advanceTimersByTimeAsync(0);
await vi.advanceTimersByTimeAsync(50);
await vi.advanceTimersByTimeAsync(150);
await expect(resultPromise).resolves.toBe(false);
expect(probe).toHaveBeenCalledTimes(3);
});
it("succeeds when the transcript becomes visible on a later retry", async () => {
vi.useFakeTimers();
let calls = 0;
const probe = vi.fn(async () => {
calls += 1;
return calls >= 2;
});
setCliRunnerTestDeps({ claudeCliSessionTranscriptHasContent: probe });
const resultPromise = isCliBindingFlushed("sid-late", "claude-cli", workspaceDir);
await vi.advanceTimersByTimeAsync(0);
await vi.advanceTimersByTimeAsync(50);
await expect(resultPromise).resolves.toBe(true);
expect(probe).toHaveBeenCalledTimes(2);
});
it("schedules at most 0 + 50 + 150ms of delay across the bounded retry", async () => {
vi.useFakeTimers();
try {
const probe = vi.fn(async () => false);
setCliRunnerTestDeps({ claudeCliSessionTranscriptHasContent: probe });
const settled = vi.fn();
const errored = vi.fn();
isCliBindingFlushed("sid-bounded", "claude-cli", workspaceDir).then(settled, errored);
await vi.advanceTimersByTimeAsync(0);
await vi.advanceTimersByTimeAsync(50);
await vi.advanceTimersByTimeAsync(150);
expect(settled).toHaveBeenCalledTimes(1);
expect(settled.mock.calls[0]?.[0]).toBe(false);
expect(errored).not.toHaveBeenCalled();
expect(probe).toHaveBeenCalledTimes(3);
} finally {
vi.clearAllTimers();
vi.useRealTimers();
}
});
it("returns true without probing for non-claude-cli providers", async () => {
const probe = vi.fn(async () => false);
setCliRunnerTestDeps({ claudeCliSessionTranscriptHasContent: probe });
expect(await isCliBindingFlushed("sid-codex", "codex-cli")).toBe(true);
expect(await isCliBindingFlushed("sid-anthropic", "anthropic")).toBe(true);
expect(await isCliBindingFlushed("sid-openai", "openai")).toBe(true);
expect(probe).not.toHaveBeenCalled();
});
it("returns true without probing when provider is undefined", async () => {
const probe = vi.fn(async () => false);
setCliRunnerTestDeps({ claudeCliSessionTranscriptHasContent: probe });
expect(await isCliBindingFlushed("sid-x", undefined)).toBe(true);
expect(probe).not.toHaveBeenCalled();
});
});