frontend-server.test.ts 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. import { expect, test } from "bun:test"
  2. import { Effect, FileSystem, Queue } from "effect"
  3. import { SimulationActions } from "../src/frontend/actions"
  4. import { SimulationRenderer } from "../src/frontend/renderer"
  5. import { SimulationServer } from "../src/frontend/server"
  6. import { availableEndpoint, connect } from "./fixture/websocket"
  7. test("scopes the frontend control server and reports malformed JSON", async () => {
  8. const endpoint = availableEndpoint()
  9. await Effect.runPromise(
  10. Effect.scoped(
  11. Effect.gen(function* () {
  12. const renderer = yield* SimulationRenderer.create({})
  13. yield* SimulationServer.start(SimulationActions.createHarness(renderer), endpoint)
  14. const socket = yield* connect(endpoint)
  15. const messages = yield* Queue.unbounded<unknown>()
  16. socket.addEventListener("message", (event) => {
  17. Queue.offerUnsafe(messages, JSON.parse(String(event.data)))
  18. })
  19. socket.send(
  20. JSON.stringify({
  21. jsonrpc: "2.0",
  22. id: 0,
  23. method: "simulation.handshake",
  24. params: {
  25. client: { name: "test", version: "test" },
  26. expectedRole: "ui",
  27. offeredVersions: [1],
  28. requiredCapabilities: ["ui.state"],
  29. optionalCapabilities: [],
  30. },
  31. }),
  32. )
  33. expect(yield* Queue.take(messages)).toMatchObject({
  34. id: 0,
  35. result: {
  36. protocolVersion: 1,
  37. role: "ui",
  38. server: { name: "opencode", version: expect.any(String) },
  39. capabilities: expect.arrayContaining(["ui.state", "ui.capture"]),
  40. },
  41. })
  42. socket.send(JSON.stringify({ jsonrpc: "2.0", id: 1, method: "ui.state" }))
  43. expect(yield* Queue.take(messages)).toMatchObject({
  44. id: 1,
  45. result: { focused: { editor: false }, elements: [] },
  46. })
  47. socket.send(JSON.stringify({ jsonrpc: "2.0", id: 2, method: "ui.capture" }))
  48. expect(yield* Queue.take(messages)).toMatchObject({
  49. id: 2,
  50. result: {
  51. cols: 100,
  52. rows: 40,
  53. cursor: [0, 0],
  54. lines: expect.any(Array),
  55. },
  56. })
  57. socket.send("{")
  58. expect(yield* Queue.take(messages)).toMatchObject({
  59. id: null,
  60. error: { code: -32000 },
  61. })
  62. }),
  63. ).pipe(Effect.provide(FileSystem.layerNoop({}))),
  64. )
  65. const url = new URL(endpoint)
  66. const rebound = Bun.serve({ hostname: url.hostname, port: Number(url.port), fetch: () => new Response() })
  67. await rebound.stop(true)
  68. })