Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
421 changes: 421 additions & 0 deletions src/__tests__/buttonHandler.test.ts

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions src/__tests__/serveManager.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,8 @@ describe("serveManager", () => {
});

it("should resolve when fetch returns ok", async () => {
const origPwd = process.env.OPENCODE_SERVER_PASSWORD;
delete process.env.OPENCODE_SERVER_PASSWORD;
vi.mocked(fetch).mockResolvedValue({ ok: true } as Response);

const promise = serveManager.waitForReady(14097);
Expand All @@ -323,6 +325,8 @@ describe("serveManager", () => {
expect(fetch).toHaveBeenCalledWith("http://127.0.0.1:14097/session", {
headers: {},
});
if (origPwd === undefined) delete process.env.OPENCODE_SERVER_PASSWORD;
else process.env.OPENCODE_SERVER_PASSWORD = origPwd;
});

it("should retry if fetch fails or returns not ok", async () => {
Expand Down Expand Up @@ -440,6 +444,7 @@ describe("serveManager", () => {

it("fails fast with a clear error when readiness probe returns 401 and password is unset", async () => {
vi.useRealTimers();
delete process.env.OPENCODE_SERVER_PASSWORD;
vi.mocked(fetch).mockResolvedValue({
ok: false,
status: 401,
Expand Down
51 changes: 51 additions & 0 deletions src/__tests__/sessionManager.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ import {
getSessionInfo,
listSessions,
abortSession,
listQuestions,
replyQuestion,
rejectQuestion,
ensureSessionForThread,
getSessionForThread,
setSessionForThread,
Expand Down Expand Up @@ -190,6 +193,54 @@ describe("SessionManager", () => {
});
});

describe("question helpers", () => {
it("should list pending questions", async () => {
const questions = [{ id: "que_123", sessionID: "ses_123", questions: [] }];
mockFetch.mockResolvedValueOnce({
ok: true,
json: async () => questions,
});

await expect(listQuestions(3000)).resolves.toEqual(questions);

expect(mockFetch).toHaveBeenCalledWith("http://127.0.0.1:3000/question", {
method: "GET",
headers: {},
});
});

it("should reply to a pending question", async () => {
mockFetch.mockResolvedValueOnce({ ok: true });

await expect(
replyQuestion(3000, "que_123", [["Approve plan"]]),
).resolves.toBe(true);

expect(mockFetch).toHaveBeenCalledWith(
"http://127.0.0.1:3000/question/que_123/reply",
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ answers: [["Approve plan"]] }),
},
);
});

it("should reject a pending question", async () => {
mockFetch.mockResolvedValueOnce({ ok: true });

await expect(rejectQuestion(3000, "que_123")).resolves.toBe(true);

expect(mockFetch).toHaveBeenCalledWith(
"http://127.0.0.1:3000/question/que_123/reject",
{
method: "POST",
headers: {},
},
);
});
});

describe("thread-session mapping", () => {
it("should store and retrieve session for thread", () => {
setSessionForThread("thread1", "ses_123", "/path/to/project", 4000);
Expand Down
54 changes: 54 additions & 0 deletions src/__tests__/sseClient.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,60 @@ describe("SSEClient", () => {
});
});

describe("onQuestionAsked", () => {
it("should trigger callback for question.asked events", () => {
const callback = vi.fn();
client.connect("http://127.0.0.1:3000");
client.onQuestionAsked(callback);

const messageHandler =
mockEventSourceInstance.addEventListener.mock.calls.find(
(call: any) => call[0] === "message",
)?.[1];

const request = {
id: "que_123",
sessionID: "session-1",
questions: [
{
header: "Plan Approval",
question: "Approve this plan?",
options: [{ label: "Approve plan" }, { label: "Revise plan" }],
},
],
};

messageHandler({
data: JSON.stringify({
type: "question.asked",
properties: request,
}),
});

expect(callback).toHaveBeenCalledWith(request);
});

it("should not trigger callback for malformed question.asked events", () => {
const callback = vi.fn();
client.connect("http://127.0.0.1:3000");
client.onQuestionAsked(callback);

const messageHandler =
mockEventSourceInstance.addEventListener.mock.calls.find(
(call: any) => call[0] === "message",
)?.[1];

messageHandler({
data: JSON.stringify({
type: "question.asked",
properties: { id: "que_123" },
}),
});

expect(callback).not.toHaveBeenCalled();
});
});

describe("onError", () => {
it("should trigger callback on error", () => {
const callback = vi.fn();
Expand Down
Loading