Files
kilocode/packages/kilo-vscode/tests/unit/session-select-connection.test.ts
T
2026-08-17 15:29:51 +02:00

76 lines
3.4 KiB
TypeScript

/**
* Source contract test for selectSession's connection handling.
*
* Static analysis — reads session.tsx and verifies that selectSession updates
* the current session id BEFORE (and independently of) the backend connection
* check, and only defers the message fetch when offline.
*
* Regression guard: previously selectSession bailed out entirely when
* `server.isConnected()` was false. In Agent Manager the side diff is resolved
* from the worktree selection independently of currentSessionID, so a switch
* during a transient disconnect moved the diff but left the chat frozen on the
* previous session ("switching only changes the sidebar diff"). The chat must
* always follow the selection; only the network fetch may wait for reconnect.
*/
import { describe, it, expect } from "bun:test"
import fs from "node:fs"
import path from "node:path"
const ROOT = path.resolve(import.meta.dir, "../..")
const SESSION_FILE = path.join(ROOT, "webview-ui/src/context/session.tsx")
const source = fs.readFileSync(SESSION_FILE, "utf-8")
describe("selectSession keeps the chat in sync with the selection while offline", () => {
const start = source.indexOf("function selectSession(")
const cloudGuard = source.indexOf('id.startsWith("cloud:")', start)
const setCurrent = source.indexOf("setCurrentSessionID(id)", start)
const offlineDefer = source.indexOf("if (!server.isConnected()) {", start)
it("selectSession exists", () => {
expect(start).toBeGreaterThan(-1)
})
it("returns early for cloud preview ids before touching the current session", () => {
expect(cloudGuard).toBeGreaterThan(start)
expect(cloudGuard).toBeLessThan(setCurrent)
})
it("sets currentSessionID before checking the connection (chat follows selection offline)", () => {
expect(setCurrent).toBeGreaterThan(-1)
expect(offlineDefer).toBeGreaterThan(-1)
// The whole point of the fix: the local selection update must precede the
// connection guard, so a disconnected switch no longer freezes the chat.
expect(setCurrent).toBeLessThan(offlineDefer)
})
it("defers the fetch for any session while offline, including cached ones", () => {
const body = source.slice(start, source.indexOf("\n function loadFocusedMessages("))
// Queue a replay unconditionally. The earlier `deferredFetch = ready ? undefined : id`
// form skipped cached sessions, so a reconnect never re-sent the focus load that
// re-focuses the backend (focusSession/contextSessionID/SSE tracking/reconcile).
expect(body).toContain("deferredFetch = { id, focus }")
expect(body).not.toMatch(/deferredFetch\s*=\s*ready\s*\?/)
})
})
describe("a deferred fetch is replayed on reconnect", () => {
it("watches the connection and replays the deferred session load", () => {
expect(source).toContain("on(server.isConnected")
const effect = source.slice(source.indexOf("on(server.isConnected"))
expect(effect).toContain("deferredFetch")
// Replays with the focus/replace choice so cached sessions still re-focus the backend.
expect(effect).toMatch(
/loadFocusedMessages\(\s*pending\.id,\s*loaded\(\)\.has\(pending\.id\),\s*pending\.focus\s*\)/,
)
})
it("the focused load helper sends focus for cached sessions and replace otherwise", () => {
const helper = source.slice(source.indexOf("function loadFocusedMessages("))
expect(helper).toMatch(/mode: "focus"/)
expect(helper).toMatch(/mode: "replace"/)
expect(helper).toContain("focus: false")
})
})