question-httpapi.test.ts 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. import { afterEach, describe, expect, test } from "bun:test"
  2. import { AppRuntime } from "../../src/effect/app-runtime"
  3. import { Instance } from "../../src/project/instance"
  4. import { Question } from "../../src/question"
  5. import { Server } from "../../src/server/server"
  6. import { SessionID } from "../../src/session/schema"
  7. import { Log } from "../../src/util/log"
  8. import { tmpdir } from "../fixture/fixture"
  9. Log.init({ print: false })
  10. const ask = (input: { sessionID: SessionID; questions: ReadonlyArray<Question.Info> }) =>
  11. AppRuntime.runPromise(Question.Service.use((svc) => svc.ask(input)))
  12. afterEach(async () => {
  13. await Instance.disposeAll()
  14. })
  15. describe("experimental question httpapi", () => {
  16. test("lists pending questions, replies, and serves docs", async () => {
  17. await using tmp = await tmpdir({ git: true })
  18. const app = Server.Default().app
  19. const headers = {
  20. "content-type": "application/json",
  21. "x-kilo-directory": tmp.path,
  22. }
  23. const questions: ReadonlyArray<Question.Info> = [
  24. {
  25. question: "What would you like to do?",
  26. header: "Action",
  27. options: [
  28. { label: "Option 1", description: "First option" },
  29. { label: "Option 2", description: "Second option" },
  30. ],
  31. },
  32. ]
  33. let pending!: ReturnType<typeof ask>
  34. await Instance.provide({
  35. directory: tmp.path,
  36. fn: async () => {
  37. pending = ask({
  38. sessionID: SessionID.make("ses_test"),
  39. questions,
  40. })
  41. },
  42. })
  43. const list = await app.request("/experimental/httpapi/question", {
  44. headers,
  45. })
  46. expect(list.status).toBe(200)
  47. const items = await list.json()
  48. expect(items).toHaveLength(1)
  49. expect(items[0]).toMatchObject({ questions })
  50. const doc = await app.request("/experimental/httpapi/question/doc", {
  51. headers,
  52. })
  53. expect(doc.status).toBe(200)
  54. const spec = await doc.json()
  55. expect(spec.paths["/experimental/httpapi/question"]?.get?.operationId).toBe("question.list")
  56. expect(spec.paths["/experimental/httpapi/question/{requestID}/reply"]?.post?.operationId).toBe("question.reply")
  57. const reply = await app.request(`/experimental/httpapi/question/${items[0].id}/reply`, {
  58. method: "POST",
  59. headers,
  60. body: JSON.stringify({ answers: [["Option 1"]] }),
  61. })
  62. expect(reply.status).toBe(200)
  63. expect(await reply.json()).toBe(true)
  64. expect(await pending).toEqual([["Option 1"]])
  65. })
  66. })