cloudaxe-opencode/packages/opencode/test/lsp/client.test.ts

107 lines
3.2 KiB
TypeScript

import { describe, expect, test, beforeEach } from "bun:test"
import path from "path"
import { Effect } from "effect"
import { Bus } from "../../src/bus"
import { LSPClient } from "../../src/lsp"
import { LSPServer } from "../../src/lsp"
import { Log } from "../../src/util"
import { provideInstance } from "../fixture/fixture"
// Minimal fake LSP server that speaks JSON-RPC over stdio
function spawnFakeServer() {
const { spawn } = require("child_process")
const serverPath = path.join(__dirname, "../fixture/lsp/fake-lsp-server.js")
return {
process: spawn(process.execPath, [serverPath], {
stdio: "pipe",
}),
}
}
async function createClient() {
const handle = spawnFakeServer() as any
const cwd = process.cwd()
const client = await Effect.runPromise(
LSPClient.create({
serverID: "fake",
server: handle as unknown as LSPServer.Handle,
root: cwd,
}).pipe(provideInstance(cwd)),
)
return { client, cwd }
}
describe("LSPClient interop", () => {
beforeEach(async () => {
await Log.init({ print: true })
})
test("handles workspace/workspaceFolders request", async () => {
const { client } = await createClient()
await client.connection.sendNotification("test/trigger", {
method: "workspace/workspaceFolders",
})
await new Promise((r) => setTimeout(r, 100))
expect(client.connection).toBeDefined()
await Effect.runPromise(client.shutdown())
})
test("handles client/registerCapability request", async () => {
const { client } = await createClient()
await client.connection.sendNotification("test/trigger", {
method: "client/registerCapability",
})
await new Promise((r) => setTimeout(r, 100))
expect(client.connection).toBeDefined()
await Effect.runPromise(client.shutdown())
})
test("handles client/unregisterCapability request", async () => {
const { client } = await createClient()
await client.connection.sendNotification("test/trigger", {
method: "client/unregisterCapability",
})
await new Promise((r) => setTimeout(r, 100))
expect(client.connection).toBeDefined()
await Effect.runPromise(client.shutdown())
})
test("waitForDiagnostics() resolves when a matching diagnostic event is published", async () => {
const { client, cwd } = await createClient()
const file = path.join(cwd, "fixture.ts")
const waiting = Effect.runPromise(client.waitForDiagnostics({ path: file }).pipe(provideInstance(cwd)))
await Effect.runPromise(Effect.sleep(20))
await Effect.runPromise(Effect.promise(() => Bus.publish(LSPClient.Event.Diagnostics, { path: file, serverID: "fake" })).pipe(provideInstance(cwd)))
await waiting
await Effect.runPromise(client.shutdown())
})
test("waitForDiagnostics() times out without throwing when no event arrives", async () => {
const { client, cwd } = await createClient()
const started = Date.now()
await Effect.runPromise(client.waitForDiagnostics({ path: path.join(cwd, "never.ts") }).pipe(provideInstance(cwd)))
const elapsed = Date.now() - started
expect(elapsed).toBeGreaterThanOrEqual(2900)
expect(elapsed).toBeLessThan(5000)
await Effect.runPromise(client.shutdown())
})
})