test(tmux-subagent): expand zombie-pane test coverage

This commit is contained in:
YeonGyu-Kim
2026-04-28 10:45:30 +09:00
parent 49bb5dd81a
commit 5e4ae8815e
+51 -23
View File
@@ -32,32 +32,31 @@ const mockSpawnTmuxSession = mock(async () => ({ success: true, paneId: "%sessio
const mockIsInsideTmux = mock<() => boolean>(() => true) const mockIsInsideTmux = mock<() => boolean>(() => true)
const mockGetCurrentPaneId = mock<() => string | undefined>(() => "%0") const mockGetCurrentPaneId = mock<() => string | undefined>(() => "%0")
mock.module("./pane-state-querier", () => ({ function registerModuleMocks(): void {
queryWindowState: mockQueryWindowState, mock.module("./action-executor", () => ({
})) executeAction: mockExecuteAction,
executeActions: mockExecuteActions,
}))
mock.module("./action-executor", () => ({ mock.module("../../shared/tmux", () => ({
executeAction: mockExecuteAction, isInsideTmux: mockIsInsideTmux,
executeActions: mockExecuteActions, getCurrentPaneId: mockGetCurrentPaneId,
})) POLL_INTERVAL_BACKGROUND_MS: 10,
SESSION_READY_POLL_INTERVAL_MS: 10,
mock.module("../../shared/tmux", () => ({ SESSION_READY_TIMEOUT_MS: 50,
isInsideTmux: mockIsInsideTmux, SESSION_MISSING_GRACE_MS: 1_000,
getCurrentPaneId: mockGetCurrentPaneId, spawnTmuxWindow: mockSpawnTmuxWindow,
POLL_INTERVAL_BACKGROUND_MS: 10, spawnTmuxSession: mockSpawnTmuxSession,
SESSION_READY_POLL_INTERVAL_MS: 10, SESSION_TIMEOUT_MS: 600_000,
SESSION_READY_TIMEOUT_MS: 50, }))
SESSION_MISSING_GRACE_MS: 1_000, }
spawnTmuxWindow: mockSpawnTmuxWindow,
spawnTmuxSession: mockSpawnTmuxSession,
SESSION_TIMEOUT_MS: 600_000,
}))
afterAll(() => { mock.restore() }) afterAll(() => { mock.restore() })
const mockTmuxDeps: TmuxUtilDeps = { const mockTmuxDeps: TmuxUtilDeps = {
isInsideTmux: mockIsInsideTmux, isInsideTmux: mockIsInsideTmux,
getCurrentPaneId: mockGetCurrentPaneId, getCurrentPaneId: mockGetCurrentPaneId,
queryWindowState: mockQueryWindowState,
} }
function createConfig(): TmuxConfig { function createConfig(): TmuxConfig {
@@ -161,6 +160,8 @@ function createManager(
describe("TmuxSessionManager zombie pane handling", () => { describe("TmuxSessionManager zombie pane handling", () => {
beforeEach(() => { beforeEach(() => {
mock.restore()
registerModuleMocks()
mockQueryWindowState.mockClear() mockQueryWindowState.mockClear()
mockExecuteAction.mockClear() mockExecuteAction.mockClear()
mockExecuteActions.mockClear() mockExecuteActions.mockClear()
@@ -224,7 +225,7 @@ describe("TmuxSessionManager zombie pane handling", () => {
expect(mockExecuteAction).toHaveBeenCalledTimes(1) expect(mockExecuteAction).toHaveBeenCalledTimes(1)
}) })
test("#given session with closePending true and closeRetryCount >= 3 #when retryPendingCloses called #then session is force-removed from Map", async () => { test("#given session with closePending true and closeRetryCount >= 3 and missing pane #when retryPendingCloses called #then session is removed from Map", async () => {
// given // given
const { TmuxSessionManager } = await import("./manager") const { TmuxSessionManager } = await import("./manager")
const manager = createManager(TmuxSessionManager) const manager = createManager(TmuxSessionManager)
@@ -239,11 +240,11 @@ describe("TmuxSessionManager zombie pane handling", () => {
// then // then
expect(sessions.has("ses_pending")).toBe(false) expect(sessions.has("ses_pending")).toBe(false)
expect(mockQueryWindowState).not.toHaveBeenCalled() expect(mockQueryWindowState).toHaveBeenCalledTimes(1)
expect(mockExecuteAction).not.toHaveBeenCalled() expect(mockExecuteAction).not.toHaveBeenCalled()
}) })
test("#given session with closePending true and closeRetryCount >= 3 #when closeSessionById called #then session is force-removed without retrying close", async () => { test("#given session with closePending true and closeRetryCount >= 3 and missing pane #when closeSessionById called #then session is removed without retrying close", async () => {
// given // given
const { TmuxSessionManager } = await import("./manager") const { TmuxSessionManager } = await import("./manager")
const manager = createManager(TmuxSessionManager) const manager = createManager(TmuxSessionManager)
@@ -258,7 +259,34 @@ describe("TmuxSessionManager zombie pane handling", () => {
// then // then
expect(sessions.has("ses_pending")).toBe(false) expect(sessions.has("ses_pending")).toBe(false)
expect(mockQueryWindowState).not.toHaveBeenCalled() expect(mockQueryWindowState).toHaveBeenCalledTimes(1)
expect(mockExecuteAction).not.toHaveBeenCalled()
})
test("#given session with closePending true and closeRetryCount >= 3 and pane still exists #when retryPendingCloses called #then session stays tracked for manual intervention", async () => {
// given
mockQueryWindowState.mockImplementation(async () => ({
windowWidth: 220,
windowHeight: 44,
mainPane: { paneId: "%0", width: 110, height: 44, left: 0, top: 0, title: "main", isActive: true },
agentPanes: [
{ paneId: "%1", width: 40, height: 44, left: 110, top: 0, title: "Pending pane", isActive: false },
],
}))
const { TmuxSessionManager } = await import("./manager")
const manager = createManager(TmuxSessionManager)
const sessions = getTrackedSessions(manager)
sessions.set(
"ses_pending",
createTrackedSession({ closePending: true, closeRetryCount: 3 }),
)
// when
await getRetryPendingCloses(manager)()
// then
expect(sessions.has("ses_pending")).toBe(true)
expect(mockQueryWindowState).toHaveBeenCalledTimes(1)
expect(mockExecuteAction).not.toHaveBeenCalled() expect(mockExecuteAction).not.toHaveBeenCalled()
}) })