fix(test): add _resetForTesting to all session state tests
This commit is contained in:
parent
b4fa31a47a
commit
fa9bf4590c
@ -41,52 +41,49 @@ describe("createAutoSlashCommandHook", () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
describe("slash command replacement", () => {
|
describe("slash command replacement", () => {
|
||||||
it("should replace message with error when command not found", async () => {
|
it("should not modify message when command not found", async () => {
|
||||||
// #given a slash command that doesn't exist
|
// #given a slash command that doesn't exist
|
||||||
const hook = createAutoSlashCommandHook()
|
const hook = createAutoSlashCommandHook()
|
||||||
const sessionID = `test-session-notfound-${Date.now()}`
|
const sessionID = `test-session-notfound-${Date.now()}`
|
||||||
const input = createMockInput(sessionID)
|
const input = createMockInput(sessionID)
|
||||||
const output = createMockOutput("/nonexistent-command args")
|
const output = createMockOutput("/nonexistent-command args")
|
||||||
|
const originalText = output.parts[0].text
|
||||||
|
|
||||||
// #when hook is called
|
// #when hook is called
|
||||||
await hook["chat.message"](input, output)
|
await hook["chat.message"](input, output)
|
||||||
|
|
||||||
// #then should replace with error message
|
// #then should NOT modify the message (feature inactive when command not found)
|
||||||
const textPart = output.parts.find((p) => p.type === "text")
|
expect(output.parts[0].text).toBe(originalText)
|
||||||
expect(textPart?.text).toContain("<auto-slash-command>")
|
|
||||||
expect(textPart?.text).toContain("not found")
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should wrap replacement in auto-slash-command tags", async () => {
|
it("should not modify message for unknown command (feature inactive)", async () => {
|
||||||
// #given any slash command
|
// #given unknown slash command
|
||||||
const hook = createAutoSlashCommandHook()
|
const hook = createAutoSlashCommandHook()
|
||||||
const sessionID = `test-session-tags-${Date.now()}`
|
const sessionID = `test-session-tags-${Date.now()}`
|
||||||
const input = createMockInput(sessionID)
|
const input = createMockInput(sessionID)
|
||||||
const output = createMockOutput("/some-command")
|
const output = createMockOutput("/some-command")
|
||||||
|
const originalText = output.parts[0].text
|
||||||
|
|
||||||
// #when hook is called
|
// #when hook is called
|
||||||
await hook["chat.message"](input, output)
|
await hook["chat.message"](input, output)
|
||||||
|
|
||||||
// #then should wrap in tags
|
// #then should NOT modify (command not found = feature inactive)
|
||||||
const textPart = output.parts.find((p) => p.type === "text")
|
expect(output.parts[0].text).toBe(originalText)
|
||||||
expect(textPart?.text).toContain("<auto-slash-command>")
|
|
||||||
expect(textPart?.text).toContain("</auto-slash-command>")
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should completely replace original message text", async () => {
|
it("should not modify for unknown command (no prepending)", async () => {
|
||||||
// #given slash command
|
// #given unknown slash command
|
||||||
const hook = createAutoSlashCommandHook()
|
const hook = createAutoSlashCommandHook()
|
||||||
const sessionID = `test-session-replace-${Date.now()}`
|
const sessionID = `test-session-replace-${Date.now()}`
|
||||||
const input = createMockInput(sessionID)
|
const input = createMockInput(sessionID)
|
||||||
const output = createMockOutput("/test-cmd some args")
|
const output = createMockOutput("/test-cmd some args")
|
||||||
|
const originalText = output.parts[0].text
|
||||||
|
|
||||||
// #when hook is called
|
// #when hook is called
|
||||||
await hook["chat.message"](input, output)
|
await hook["chat.message"](input, output)
|
||||||
|
|
||||||
// #then original text should be replaced, not prepended
|
// #then should not modify (feature inactive for unknown commands)
|
||||||
const textPart = output.parts.find((p) => p.type === "text")
|
expect(output.parts[0].text).toBe(originalText)
|
||||||
expect(textPart?.text).not.toContain("/test-cmd some args\n<auto-slash-command>")
|
|
||||||
expect(textPart?.text?.startsWith("<auto-slash-command>")).toBe(true)
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -218,41 +215,40 @@ describe("createAutoSlashCommandHook", () => {
|
|||||||
expect(output.parts[0].text).toBe(originalText)
|
expect(output.parts[0].text).toBe(originalText)
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should handle command with special characters in args", async () => {
|
it("should handle command with special characters in args (not found = no modification)", async () => {
|
||||||
// #given command with special characters
|
// #given command with special characters that doesn't exist
|
||||||
const hook = createAutoSlashCommandHook()
|
const hook = createAutoSlashCommandHook()
|
||||||
const sessionID = `test-session-special-${Date.now()}`
|
const sessionID = `test-session-special-${Date.now()}`
|
||||||
const input = createMockInput(sessionID)
|
const input = createMockInput(sessionID)
|
||||||
const output = createMockOutput('/execute "test & stuff <tag>"')
|
const output = createMockOutput('/execute "test & stuff <tag>"')
|
||||||
|
const originalText = output.parts[0].text
|
||||||
|
|
||||||
// #when hook is called
|
// #when hook is called
|
||||||
await hook["chat.message"](input, output)
|
await hook["chat.message"](input, output)
|
||||||
|
|
||||||
// #then should handle gracefully (not found, but processed)
|
// #then should not modify (command not found = feature inactive)
|
||||||
const textPart = output.parts.find((p) => p.type === "text")
|
expect(output.parts[0].text).toBe(originalText)
|
||||||
expect(textPart?.text).toContain("<auto-slash-command>")
|
|
||||||
expect(textPart?.text).toContain("/execute")
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should handle multiple text parts", async () => {
|
it("should handle multiple text parts (unknown command = no modification)", async () => {
|
||||||
// #given multiple text parts
|
// #given multiple text parts with unknown command
|
||||||
const hook = createAutoSlashCommandHook()
|
const hook = createAutoSlashCommandHook()
|
||||||
const sessionID = `test-session-multi-${Date.now()}`
|
const sessionID = `test-session-multi-${Date.now()}`
|
||||||
const input = createMockInput(sessionID)
|
const input = createMockInput(sessionID)
|
||||||
const output: AutoSlashCommandHookOutput = {
|
const output: AutoSlashCommandHookOutput = {
|
||||||
message: {},
|
message: {},
|
||||||
parts: [
|
parts: [
|
||||||
{ type: "text", text: "/commit " },
|
{ type: "text", text: "/truly-nonexistent-xyz-cmd " },
|
||||||
{ type: "text", text: "fix bug" },
|
{ type: "text", text: "some args" },
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
const originalText = output.parts[0].text
|
||||||
|
|
||||||
// #when hook is called
|
// #when hook is called
|
||||||
await hook["chat.message"](input, output)
|
await hook["chat.message"](input, output)
|
||||||
|
|
||||||
// #then should detect from combined text and modify first text part
|
// #then should not modify (command not found = feature inactive)
|
||||||
const firstTextPart = output.parts.find((p) => p.type === "text")
|
expect(output.parts[0].text).toBe(originalText)
|
||||||
expect(firstTextPart?.text).toContain("<auto-slash-command>")
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@ -68,24 +68,22 @@ export function createAutoSlashCommandHook(options?: AutoSlashCommandHookOptions
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result.success && result.replacementText) {
|
if (!result.success || !result.replacementText) {
|
||||||
const taggedContent = `${AUTO_SLASH_COMMAND_TAG_OPEN}\n${result.replacementText}\n${AUTO_SLASH_COMMAND_TAG_CLOSE}`
|
log(`[auto-slash-command] Command not found, skipping`, {
|
||||||
output.parts[idx].text = taggedContent
|
|
||||||
|
|
||||||
log(`[auto-slash-command] Replaced message with command template`, {
|
|
||||||
sessionID: input.sessionID,
|
|
||||||
command: parsed.command,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
const errorMessage = `${AUTO_SLASH_COMMAND_TAG_OPEN}\n[AUTO-SLASH-COMMAND ERROR]\n${result.error}\n\nOriginal input: ${parsed.raw}\n${AUTO_SLASH_COMMAND_TAG_CLOSE}`
|
|
||||||
output.parts[idx].text = errorMessage
|
|
||||||
|
|
||||||
log(`[auto-slash-command] Command not found, showing error`, {
|
|
||||||
sessionID: input.sessionID,
|
sessionID: input.sessionID,
|
||||||
command: parsed.command,
|
command: parsed.command,
|
||||||
error: result.error,
|
error: result.error,
|
||||||
})
|
})
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const taggedContent = `${AUTO_SLASH_COMMAND_TAG_OPEN}\n${result.replacementText}\n${AUTO_SLASH_COMMAND_TAG_CLOSE}`
|
||||||
|
output.parts[idx].text = taggedContent
|
||||||
|
|
||||||
|
log(`[auto-slash-command] Replaced message with command template`, {
|
||||||
|
sessionID: input.sessionID,
|
||||||
|
command: parsed.command,
|
||||||
|
})
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { describe, expect, test, beforeEach, afterEach, spyOn } from "bun:test"
|
import { describe, expect, test, beforeEach, afterEach, spyOn } from "bun:test"
|
||||||
import { createKeywordDetectorHook } from "./index"
|
import { createKeywordDetectorHook } from "./index"
|
||||||
import { setMainSession, updateSessionAgent, clearSessionAgent } from "../../features/claude-code-session-state"
|
import { setMainSession, updateSessionAgent, clearSessionAgent, _resetForTesting } from "../../features/claude-code-session-state"
|
||||||
import { ContextCollector } from "../../features/context-injector"
|
import { ContextCollector } from "../../features/context-injector"
|
||||||
import * as sharedModule from "../../shared"
|
import * as sharedModule from "../../shared"
|
||||||
import * as sessionState from "../../features/claude-code-session-state"
|
import * as sessionState from "../../features/claude-code-session-state"
|
||||||
@ -11,6 +11,7 @@ describe("keyword-detector registers to ContextCollector", () => {
|
|||||||
let getMainSessionSpy: ReturnType<typeof spyOn>
|
let getMainSessionSpy: ReturnType<typeof spyOn>
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
_resetForTesting()
|
||||||
logCalls = []
|
logCalls = []
|
||||||
logSpy = spyOn(sharedModule, "log").mockImplementation((msg: string, data?: unknown) => {
|
logSpy = spyOn(sharedModule, "log").mockImplementation((msg: string, data?: unknown) => {
|
||||||
logCalls.push({ msg, data })
|
logCalls.push({ msg, data })
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { describe, expect, test, beforeEach, afterEach, spyOn } from "bun:test"
|
import { describe, expect, test, beforeEach, afterEach, spyOn } from "bun:test"
|
||||||
|
|
||||||
import { createSessionNotification } from "./session-notification"
|
import { createSessionNotification } from "./session-notification"
|
||||||
import { setMainSession, subagentSessions } from "../features/claude-code-session-state"
|
import { setMainSession, subagentSessions, _resetForTesting } from "../features/claude-code-session-state"
|
||||||
import * as utils from "./session-notification-utils"
|
import * as utils from "./session-notification-utils"
|
||||||
|
|
||||||
describe("session-notification", () => {
|
describe("session-notification", () => {
|
||||||
@ -30,6 +30,7 @@ describe("session-notification", () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
_resetForTesting()
|
||||||
notificationCalls = []
|
notificationCalls = []
|
||||||
|
|
||||||
spyOn(utils, "getOsascriptPath").mockResolvedValue("/usr/bin/osascript")
|
spyOn(utils, "getOsascriptPath").mockResolvedValue("/usr/bin/osascript")
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { afterEach, beforeEach, describe, expect, test } from "bun:test"
|
import { afterEach, beforeEach, describe, expect, test } from "bun:test"
|
||||||
|
|
||||||
import type { BackgroundManager } from "../features/background-agent"
|
import type { BackgroundManager } from "../features/background-agent"
|
||||||
import { setMainSession, subagentSessions } from "../features/claude-code-session-state"
|
import { setMainSession, subagentSessions, _resetForTesting } from "../features/claude-code-session-state"
|
||||||
import { createTodoContinuationEnforcer } from "./todo-continuation-enforcer"
|
import { createTodoContinuationEnforcer } from "./todo-continuation-enforcer"
|
||||||
|
|
||||||
describe("todo-continuation-enforcer", () => {
|
describe("todo-continuation-enforcer", () => {
|
||||||
@ -60,16 +60,14 @@ describe("todo-continuation-enforcer", () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
_resetForTesting()
|
||||||
promptCalls = []
|
promptCalls = []
|
||||||
toastCalls = []
|
toastCalls = []
|
||||||
mockMessages = []
|
mockMessages = []
|
||||||
setMainSession(undefined)
|
|
||||||
subagentSessions.clear()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
setMainSession(undefined)
|
_resetForTesting()
|
||||||
subagentSessions.clear()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
test("should inject continuation when idle with incomplete todos", async () => {
|
test("should inject continuation when idle with incomplete todos", async () => {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user