question.test.ts 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. import { test, expect } from "bun:test"
  2. import { Question } from "../../src/question"
  3. import { Instance } from "../../src/project/instance"
  4. import { tmpdir } from "../fixture/fixture"
  5. test("ask - returns pending promise", async () => {
  6. await using tmp = await tmpdir({ git: true })
  7. await Instance.provide({
  8. directory: tmp.path,
  9. fn: async () => {
  10. const promise = Question.ask({
  11. sessionID: "ses_test",
  12. questions: [
  13. {
  14. question: "What would you like to do?",
  15. header: "Action",
  16. options: [
  17. { label: "Option 1", description: "First option" },
  18. { label: "Option 2", description: "Second option" },
  19. ],
  20. },
  21. ],
  22. })
  23. expect(promise).toBeInstanceOf(Promise)
  24. },
  25. })
  26. })
  27. test("ask - adds to pending list", async () => {
  28. await using tmp = await tmpdir({ git: true })
  29. await Instance.provide({
  30. directory: tmp.path,
  31. fn: async () => {
  32. const questions = [
  33. {
  34. question: "What would you like to do?",
  35. header: "Action",
  36. options: [
  37. { label: "Option 1", description: "First option" },
  38. { label: "Option 2", description: "Second option" },
  39. ],
  40. },
  41. ]
  42. Question.ask({
  43. sessionID: "ses_test",
  44. questions,
  45. })
  46. const pending = await Question.list()
  47. expect(pending.length).toBe(1)
  48. expect(pending[0].questions).toEqual(questions)
  49. },
  50. })
  51. })
  52. // reply tests
  53. test("reply - resolves the pending ask with answers", async () => {
  54. await using tmp = await tmpdir({ git: true })
  55. await Instance.provide({
  56. directory: tmp.path,
  57. fn: async () => {
  58. const questions = [
  59. {
  60. question: "What would you like to do?",
  61. header: "Action",
  62. options: [
  63. { label: "Option 1", description: "First option" },
  64. { label: "Option 2", description: "Second option" },
  65. ],
  66. },
  67. ]
  68. const askPromise = Question.ask({
  69. sessionID: "ses_test",
  70. questions,
  71. })
  72. const pending = await Question.list()
  73. const requestID = pending[0].id
  74. await Question.reply({
  75. requestID,
  76. answers: [["Option 1"]],
  77. })
  78. const answers = await askPromise
  79. expect(answers).toEqual([["Option 1"]])
  80. },
  81. })
  82. })
  83. test("reply - removes from pending list", async () => {
  84. await using tmp = await tmpdir({ git: true })
  85. await Instance.provide({
  86. directory: tmp.path,
  87. fn: async () => {
  88. Question.ask({
  89. sessionID: "ses_test",
  90. questions: [
  91. {
  92. question: "What would you like to do?",
  93. header: "Action",
  94. options: [
  95. { label: "Option 1", description: "First option" },
  96. { label: "Option 2", description: "Second option" },
  97. ],
  98. },
  99. ],
  100. })
  101. const pending = await Question.list()
  102. expect(pending.length).toBe(1)
  103. await Question.reply({
  104. requestID: pending[0].id,
  105. answers: [["Option 1"]],
  106. })
  107. const pendingAfter = await Question.list()
  108. expect(pendingAfter.length).toBe(0)
  109. },
  110. })
  111. })
  112. test("reply - does nothing for unknown requestID", async () => {
  113. await using tmp = await tmpdir({ git: true })
  114. await Instance.provide({
  115. directory: tmp.path,
  116. fn: async () => {
  117. await Question.reply({
  118. requestID: "que_unknown",
  119. answers: [["Option 1"]],
  120. })
  121. // Should not throw
  122. },
  123. })
  124. })
  125. // reject tests
  126. test("reject - throws RejectedError", async () => {
  127. await using tmp = await tmpdir({ git: true })
  128. await Instance.provide({
  129. directory: tmp.path,
  130. fn: async () => {
  131. const askPromise = Question.ask({
  132. sessionID: "ses_test",
  133. questions: [
  134. {
  135. question: "What would you like to do?",
  136. header: "Action",
  137. options: [
  138. { label: "Option 1", description: "First option" },
  139. { label: "Option 2", description: "Second option" },
  140. ],
  141. },
  142. ],
  143. })
  144. const pending = await Question.list()
  145. await Question.reject(pending[0].id)
  146. await expect(askPromise).rejects.toBeInstanceOf(Question.RejectedError)
  147. },
  148. })
  149. })
  150. test("reject - removes from pending list", async () => {
  151. await using tmp = await tmpdir({ git: true })
  152. await Instance.provide({
  153. directory: tmp.path,
  154. fn: async () => {
  155. const askPromise = Question.ask({
  156. sessionID: "ses_test",
  157. questions: [
  158. {
  159. question: "What would you like to do?",
  160. header: "Action",
  161. options: [
  162. { label: "Option 1", description: "First option" },
  163. { label: "Option 2", description: "Second option" },
  164. ],
  165. },
  166. ],
  167. })
  168. const pending = await Question.list()
  169. expect(pending.length).toBe(1)
  170. await Question.reject(pending[0].id)
  171. askPromise.catch(() => {}) // Ignore rejection
  172. const pendingAfter = await Question.list()
  173. expect(pendingAfter.length).toBe(0)
  174. },
  175. })
  176. })
  177. test("reject - does nothing for unknown requestID", async () => {
  178. await using tmp = await tmpdir({ git: true })
  179. await Instance.provide({
  180. directory: tmp.path,
  181. fn: async () => {
  182. await Question.reject("que_unknown")
  183. // Should not throw
  184. },
  185. })
  186. })
  187. // multiple questions tests
  188. test("ask - handles multiple questions", async () => {
  189. await using tmp = await tmpdir({ git: true })
  190. await Instance.provide({
  191. directory: tmp.path,
  192. fn: async () => {
  193. const questions = [
  194. {
  195. question: "What would you like to do?",
  196. header: "Action",
  197. options: [
  198. { label: "Build", description: "Build the project" },
  199. { label: "Test", description: "Run tests" },
  200. ],
  201. },
  202. {
  203. question: "Which environment?",
  204. header: "Env",
  205. options: [
  206. { label: "Dev", description: "Development" },
  207. { label: "Prod", description: "Production" },
  208. ],
  209. },
  210. ]
  211. const askPromise = Question.ask({
  212. sessionID: "ses_test",
  213. questions,
  214. })
  215. const pending = await Question.list()
  216. await Question.reply({
  217. requestID: pending[0].id,
  218. answers: [["Build"], ["Dev"]],
  219. })
  220. const answers = await askPromise
  221. expect(answers).toEqual([["Build"], ["Dev"]])
  222. },
  223. })
  224. })
  225. // list tests
  226. test("list - returns all pending requests", async () => {
  227. await using tmp = await tmpdir({ git: true })
  228. await Instance.provide({
  229. directory: tmp.path,
  230. fn: async () => {
  231. Question.ask({
  232. sessionID: "ses_test1",
  233. questions: [
  234. {
  235. question: "Question 1?",
  236. header: "Q1",
  237. options: [{ label: "A", description: "A" }],
  238. },
  239. ],
  240. })
  241. Question.ask({
  242. sessionID: "ses_test2",
  243. questions: [
  244. {
  245. question: "Question 2?",
  246. header: "Q2",
  247. options: [{ label: "B", description: "B" }],
  248. },
  249. ],
  250. })
  251. const pending = await Question.list()
  252. expect(pending.length).toBe(2)
  253. },
  254. })
  255. })
  256. test("list - returns empty when no pending", async () => {
  257. await using tmp = await tmpdir({ git: true })
  258. await Instance.provide({
  259. directory: tmp.path,
  260. fn: async () => {
  261. const pending = await Question.list()
  262. expect(pending.length).toBe(0)
  263. },
  264. })
  265. })