fix: update /help test to expect botCommand dispatch, fix PTY fd leak in claude_code.rs (#451, #452)
The /help test expected the help overlay to appear, but /help now goes through botCommand like other slash commands. Updated the test to match. Also added reader thread join and child.wait() calls to claude_code.rs to prevent PTY master fd leaks from web UI chat sessions. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1642,7 +1642,8 @@ describe("Slash command handling (Story 374)", () => {
|
|||||||
expect(mockedApi.botCommand).not.toHaveBeenCalled();
|
expect(mockedApi.botCommand).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("AC: /help shows help overlay", async () => {
|
it("AC: /help calls botCommand and displays response", async () => {
|
||||||
|
mockedApi.botCommand.mockResolvedValue({ response: "Available commands: status, help, ..." });
|
||||||
render(<Chat projectPath="/tmp/project" onCloseProject={vi.fn()} />);
|
render(<Chat projectPath="/tmp/project" onCloseProject={vi.fn()} />);
|
||||||
await waitFor(() => expect(capturedWsHandlers).not.toBeNull());
|
await waitFor(() => expect(capturedWsHandlers).not.toBeNull());
|
||||||
|
|
||||||
@@ -1658,9 +1659,14 @@ describe("Slash command handling (Story 374)", () => {
|
|||||||
fireEvent.keyDown(input, { key: "Enter", shiftKey: false });
|
fireEvent.keyDown(input, { key: "Enter", shiftKey: false });
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(await screen.findByTestId("help-overlay")).toBeInTheDocument();
|
await waitFor(() => {
|
||||||
|
expect(mockedApi.botCommand).toHaveBeenCalledWith(
|
||||||
|
"help",
|
||||||
|
"",
|
||||||
|
undefined,
|
||||||
|
);
|
||||||
|
});
|
||||||
expect(lastSendChatArgs).toBeNull();
|
expect(lastSendChatArgs).toBeNull();
|
||||||
expect(mockedApi.botCommand).not.toHaveBeenCalled();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("AC: botCommand API error shows error message in chat", async () => {
|
it("AC: botCommand API error shows error message in chat", async () => {
|
||||||
|
|||||||
@@ -256,7 +256,7 @@ fn run_pty_session(
|
|||||||
// Read NDJSON lines from stdout
|
// Read NDJSON lines from stdout
|
||||||
let (line_tx, line_rx) = std::sync::mpsc::channel::<Option<String>>();
|
let (line_tx, line_rx) = std::sync::mpsc::channel::<Option<String>>();
|
||||||
|
|
||||||
std::thread::spawn(move || {
|
let reader_handle = std::thread::spawn(move || {
|
||||||
let buf_reader = BufReader::new(reader);
|
let buf_reader = BufReader::new(reader);
|
||||||
slog!("[pty-debug] Reader thread started");
|
slog!("[pty-debug] Reader thread started");
|
||||||
for line in buf_reader.lines() {
|
for line in buf_reader.lines() {
|
||||||
@@ -284,6 +284,8 @@ fn run_pty_session(
|
|||||||
loop {
|
loop {
|
||||||
if cancelled.load(Ordering::Relaxed) {
|
if cancelled.load(Ordering::Relaxed) {
|
||||||
let _ = child.kill();
|
let _ = child.kill();
|
||||||
|
let _ = child.wait();
|
||||||
|
let _ = reader_handle.join();
|
||||||
return Err("Cancelled".to_string());
|
return Err("Cancelled".to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -365,8 +367,11 @@ fn run_pty_session(
|
|||||||
}
|
}
|
||||||
// If still running after 2s, kill it
|
// If still running after 2s, kill it
|
||||||
let _ = child.kill();
|
let _ = child.kill();
|
||||||
|
let _ = child.wait();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Wait for the reader thread to release the cloned PTY master fd.
|
||||||
|
let _ = reader_handle.join();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user