Fix test corrupting production sessions.json
The test 'falls back to most recent session when no to is provided' was using resolveStorePath() which returns the real ~/.warelay/sessions.json. This overwrote production session data with test values, causing session fragmentation issues. Changed to use a temp directory like other tests.
This commit is contained in:
@@ -292,4 +292,79 @@ describe("runCommandReply", () => {
|
||||
expect(meta.queuedMs).toBe(25);
|
||||
expect(meta.queuedAhead).toBe(2);
|
||||
});
|
||||
|
||||
it("handles empty result string without dumping raw JSON", async () => {
|
||||
// Bug fix: Claude CLI returning {"result": ""} should not send raw JSON to WhatsApp
|
||||
// The fix changed from truthy check to explicit typeof check
|
||||
const runner = makeRunner({
|
||||
stdout: '{"result":"","duration_ms":50,"total_cost_usd":0.001}',
|
||||
});
|
||||
const { payload } = await runCommandReply({
|
||||
reply: {
|
||||
mode: "command",
|
||||
command: ["claude", "{{Body}}"],
|
||||
claudeOutputFormat: "json",
|
||||
},
|
||||
templatingCtx: noopTemplateCtx,
|
||||
sendSystemOnce: false,
|
||||
isNewSession: true,
|
||||
isFirstTurnInSession: true,
|
||||
systemSent: false,
|
||||
timeoutMs: 1000,
|
||||
timeoutSeconds: 1,
|
||||
commandRunner: runner,
|
||||
enqueue: enqueueImmediate,
|
||||
});
|
||||
// Should NOT contain raw JSON - empty result should produce fallback message
|
||||
expect(payload?.text).not.toContain('{"result"');
|
||||
expect(payload?.text).toContain("command produced no output");
|
||||
});
|
||||
|
||||
it("handles empty text string in Claude JSON", async () => {
|
||||
const runner = makeRunner({
|
||||
stdout: '{"text":"","duration_ms":50}',
|
||||
});
|
||||
const { payload } = await runCommandReply({
|
||||
reply: {
|
||||
mode: "command",
|
||||
command: ["claude", "{{Body}}"],
|
||||
claudeOutputFormat: "json",
|
||||
},
|
||||
templatingCtx: noopTemplateCtx,
|
||||
sendSystemOnce: false,
|
||||
isNewSession: true,
|
||||
isFirstTurnInSession: true,
|
||||
systemSent: false,
|
||||
timeoutMs: 1000,
|
||||
timeoutSeconds: 1,
|
||||
commandRunner: runner,
|
||||
enqueue: enqueueImmediate,
|
||||
});
|
||||
// Empty text should produce fallback message, not raw JSON
|
||||
expect(payload?.text).not.toContain('{"text"');
|
||||
expect(payload?.text).toContain("command produced no output");
|
||||
});
|
||||
|
||||
it("returns actual text when result is non-empty", async () => {
|
||||
const runner = makeRunner({
|
||||
stdout: '{"result":"hello world","duration_ms":50}',
|
||||
});
|
||||
const { payload } = await runCommandReply({
|
||||
reply: {
|
||||
mode: "command",
|
||||
command: ["claude", "{{Body}}"],
|
||||
claudeOutputFormat: "json",
|
||||
},
|
||||
templatingCtx: noopTemplateCtx,
|
||||
sendSystemOnce: false,
|
||||
isNewSession: true,
|
||||
isFirstTurnInSession: true,
|
||||
systemSent: false,
|
||||
timeoutMs: 1000,
|
||||
timeoutSeconds: 1,
|
||||
commandRunner: runner,
|
||||
enqueue: enqueueImmediate,
|
||||
});
|
||||
expect(payload?.text).toBe("hello world");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -259,8 +259,11 @@ export async function runCommandReply(
|
||||
console.error(
|
||||
`Command auto-reply exited with code ${code ?? "unknown"} (signal: ${signal ?? "none"})`,
|
||||
);
|
||||
// Include any partial output or stderr in error message
|
||||
const partialOut = trimmed ? `\n\nOutput: ${trimmed.slice(0, 500)}${trimmed.length > 500 ? "..." : ""}` : "";
|
||||
const errorText = `⚠️ Command exited with code ${code ?? "unknown"}${signal ? ` (${signal})` : ""}${partialOut}`;
|
||||
return {
|
||||
payload: undefined,
|
||||
payload: { text: errorText },
|
||||
meta: {
|
||||
durationMs: Date.now() - started,
|
||||
queuedMs,
|
||||
@@ -278,8 +281,9 @@ export async function runCommandReply(
|
||||
console.error(
|
||||
`Command auto-reply process killed before completion (exit code ${code ?? "unknown"})`,
|
||||
);
|
||||
const errorText = `⚠️ Command was killed before completion (exit code ${code ?? "unknown"})`;
|
||||
return {
|
||||
payload: undefined,
|
||||
payload: { text: errorText },
|
||||
meta: {
|
||||
durationMs: Date.now() - started,
|
||||
queuedMs,
|
||||
@@ -379,8 +383,11 @@ export async function runCommandReply(
|
||||
};
|
||||
}
|
||||
logError(`Command auto-reply failed after ${elapsed}ms: ${String(err)}`);
|
||||
// Send error message to user so they know the command failed
|
||||
const errMsg = err instanceof Error ? err.message : String(err);
|
||||
const errorText = `⚠️ Command failed: ${errMsg}`;
|
||||
return {
|
||||
payload: undefined,
|
||||
payload: { text: errorText },
|
||||
meta: {
|
||||
durationMs: elapsed,
|
||||
queuedMs,
|
||||
|
||||
Reference in New Issue
Block a user