test(tmux): inject session-created handler seams
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
@@ -1,11 +1,6 @@
|
|||||||
import { describe, test, expect, mock, afterEach } from "bun:test"
|
/// <reference path="../../../bun-test.d.ts" />
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
import { describe, test, expect, mock, afterEach } from "bun:test"
|
||||||
// Module-level mocks — must be registered BEFORE importing the handler so the
|
|
||||||
// handler picks up the mocked exports instead of the real implementations.
|
|
||||||
// queryWindowState and executeActions hit real tmux/spawn subprocesses; we
|
|
||||||
// replace them with spies so the spawn path can actually be exercised in tests.
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
const mockQueryWindowState = mock(async (_paneId: string) => ({
|
const mockQueryWindowState = mock(async (_paneId: string) => ({
|
||||||
windowWidth: 244,
|
windowWidth: 244,
|
||||||
@@ -20,9 +15,6 @@ const mockExecuteActions = mock(async (_actions: unknown[], _ctx: unknown) => ({
|
|||||||
results: [],
|
results: [],
|
||||||
}))
|
}))
|
||||||
|
|
||||||
mock.module("./pane-state-querier", () => ({ queryWindowState: mockQueryWindowState }))
|
|
||||||
mock.module("./action-executor", () => ({ executeActions: mockExecuteActions }))
|
|
||||||
|
|
||||||
import type { SessionCreatedHandlerDeps } from "./session-created-handler"
|
import type { SessionCreatedHandlerDeps } from "./session-created-handler"
|
||||||
import { handleSessionCreated } from "./session-created-handler"
|
import { handleSessionCreated } from "./session-created-handler"
|
||||||
import type { SessionCreatedEvent } from "./session-created-event"
|
import type { SessionCreatedEvent } from "./session-created-event"
|
||||||
@@ -50,12 +42,6 @@ function makeDeps(overrides: Partial<SessionCreatedHandlerDeps> = {}): {
|
|||||||
mockExecuteActions: ReturnType<typeof mock>
|
mockExecuteActions: ReturnType<typeof mock>
|
||||||
mockWaitForSessionReady: ReturnType<typeof mock>
|
mockWaitForSessionReady: ReturnType<typeof mock>
|
||||||
} {
|
} {
|
||||||
const mockExecuteActions = mock(async () => ({
|
|
||||||
success: true,
|
|
||||||
spawnedPaneId: "%99",
|
|
||||||
results: [],
|
|
||||||
}))
|
|
||||||
|
|
||||||
const mockWaitForSessionReady = mock(async (_sessionId: string) => true)
|
const mockWaitForSessionReady = mock(async (_sessionId: string) => true)
|
||||||
|
|
||||||
const deps: SessionCreatedHandlerDeps = {
|
const deps: SessionCreatedHandlerDeps = {
|
||||||
@@ -72,6 +58,8 @@ function makeDeps(overrides: Partial<SessionCreatedHandlerDeps> = {}): {
|
|||||||
getSessionMappings: () => [],
|
getSessionMappings: () => [],
|
||||||
waitForSessionReady: mockWaitForSessionReady,
|
waitForSessionReady: mockWaitForSessionReady,
|
||||||
startPolling: mock(() => {}),
|
startPolling: mock(() => {}),
|
||||||
|
queryWindowState: mockQueryWindowState,
|
||||||
|
executeActions: mockExecuteActions,
|
||||||
...overrides,
|
...overrides,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,7 +120,7 @@ describe("handleSessionCreated – #3505 session readiness race", () => {
|
|||||||
callLog.push("waitForSessionReady:end")
|
callLog.push("waitForSessionReady:end")
|
||||||
return ready
|
return ready
|
||||||
})
|
})
|
||||||
mockExecuteActions.mockImplementation(async (_actions, _ctx) => {
|
mockExecuteActions.mockImplementation(async (_actions: unknown[], _ctx: unknown) => {
|
||||||
callLog.push("executeActions")
|
callLog.push("executeActions")
|
||||||
return { success: true, spawnedPaneId: "%99", results: [] }
|
return { success: true, spawnedPaneId: "%99", results: [] }
|
||||||
})
|
})
|
||||||
@@ -195,6 +183,7 @@ describe("handleSessionCreated – #3505 session readiness race", () => {
|
|||||||
sessionId: "ses_existing",
|
sessionId: "ses_existing",
|
||||||
paneId: "%5",
|
paneId: "%5",
|
||||||
description: "TestAgent",
|
description: "TestAgent",
|
||||||
|
attachActivated: false,
|
||||||
createdAt: new Date(),
|
createdAt: new Date(),
|
||||||
lastSeenAt: new Date(),
|
lastSeenAt: new Date(),
|
||||||
closePending: false,
|
closePending: false,
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ export interface SessionCreatedHandlerDeps {
|
|||||||
getSessionMappings: () => SessionMapping[]
|
getSessionMappings: () => SessionMapping[]
|
||||||
waitForSessionReady: (sessionId: string) => Promise<boolean>
|
waitForSessionReady: (sessionId: string) => Promise<boolean>
|
||||||
startPolling: () => void
|
startPolling: () => void
|
||||||
|
queryWindowState?: typeof queryWindowState
|
||||||
|
executeActions?: typeof executeActions
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function handleSessionCreated(
|
export async function handleSessionCreated(
|
||||||
@@ -63,7 +65,10 @@ export async function handleSessionCreated(
|
|||||||
deps.pendingSessions.add(sessionId)
|
deps.pendingSessions.add(sessionId)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const state = await queryWindowState(deps.sourcePaneId)
|
const queryWindowStateImpl = deps.queryWindowState ?? queryWindowState
|
||||||
|
const executeActionsImpl = deps.executeActions ?? executeActions
|
||||||
|
|
||||||
|
const state = await queryWindowStateImpl(deps.sourcePaneId)
|
||||||
if (!state) {
|
if (!state) {
|
||||||
log("[tmux-session-manager] failed to query window state")
|
log("[tmux-session-manager] failed to query window state")
|
||||||
return
|
return
|
||||||
@@ -115,7 +120,7 @@ export async function handleSessionCreated(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await executeActions(decision.actions, {
|
const result = await executeActionsImpl(decision.actions, {
|
||||||
config: deps.tmuxConfig,
|
config: deps.tmuxConfig,
|
||||||
directory: deps.directory,
|
directory: deps.directory,
|
||||||
serverUrl: deps.serverUrl,
|
serverUrl: deps.serverUrl,
|
||||||
|
|||||||
Reference in New Issue
Block a user