@agent-canvas/cli 0.8.1 → 0.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (199) hide show
  1. package/dist/commands/__tests__/add-arrow.test.d.ts +1 -0
  2. package/dist/commands/__tests__/add-arrow.test.js +186 -0
  3. package/dist/commands/__tests__/add-image.test.d.ts +1 -0
  4. package/dist/commands/__tests__/add-image.test.js +170 -0
  5. package/dist/commands/__tests__/add-line.test.d.ts +1 -0
  6. package/dist/commands/__tests__/add-line.test.js +138 -0
  7. package/dist/commands/__tests__/add-polygon.test.d.ts +1 -0
  8. package/dist/commands/__tests__/add-polygon.test.js +147 -0
  9. package/dist/commands/__tests__/add-shape.test.d.ts +1 -0
  10. package/dist/commands/__tests__/add-shape.test.js +193 -0
  11. package/dist/commands/__tests__/add-text.test.d.ts +1 -0
  12. package/dist/commands/__tests__/add-text.test.js +144 -0
  13. package/dist/commands/__tests__/clear.test.d.ts +1 -0
  14. package/dist/commands/__tests__/clear.test.js +65 -0
  15. package/dist/commands/__tests__/delete-elements.test.d.ts +1 -0
  16. package/dist/commands/__tests__/delete-elements.test.js +103 -0
  17. package/dist/commands/__tests__/export.test.d.ts +1 -0
  18. package/dist/commands/__tests__/export.test.js +187 -0
  19. package/dist/commands/__tests__/group-elements.test.d.ts +1 -0
  20. package/dist/commands/__tests__/group-elements.test.js +93 -0
  21. package/dist/commands/__tests__/list.test.d.ts +1 -0
  22. package/dist/commands/__tests__/list.test.js +134 -0
  23. package/dist/commands/__tests__/load.test.d.ts +1 -0
  24. package/dist/commands/__tests__/load.test.js +158 -0
  25. package/dist/commands/__tests__/move-elements.test.d.ts +1 -0
  26. package/dist/commands/__tests__/move-elements.test.js +117 -0
  27. package/dist/commands/__tests__/new-canvas.test.d.ts +1 -0
  28. package/dist/commands/__tests__/new-canvas.test.js +113 -0
  29. package/dist/commands/__tests__/read.test.d.ts +1 -0
  30. package/dist/commands/__tests__/read.test.js +247 -0
  31. package/dist/commands/__tests__/rename-canvas.test.d.ts +1 -0
  32. package/dist/commands/__tests__/rename-canvas.test.js +86 -0
  33. package/dist/commands/__tests__/resize-elements.test.d.ts +1 -0
  34. package/dist/commands/__tests__/resize-elements.test.js +150 -0
  35. package/dist/commands/__tests__/rotate-elements.test.d.ts +1 -0
  36. package/dist/commands/__tests__/rotate-elements.test.js +114 -0
  37. package/dist/commands/__tests__/save.test.d.ts +1 -0
  38. package/dist/commands/__tests__/save.test.js +105 -0
  39. package/dist/commands/__tests__/ungroup-element.test.d.ts +1 -0
  40. package/dist/commands/__tests__/ungroup-element.test.js +93 -0
  41. package/dist/commands/__tests__/use-canvas.test.d.ts +1 -0
  42. package/dist/commands/__tests__/use-canvas.test.js +86 -0
  43. package/dist/commands/add-arrow.d.ts +40 -0
  44. package/dist/commands/add-arrow.js +52 -0
  45. package/dist/commands/add-image.d.ts +26 -0
  46. package/dist/commands/add-image.js +66 -0
  47. package/dist/commands/add-line.d.ts +27 -0
  48. package/dist/commands/add-line.js +35 -0
  49. package/dist/commands/add-polygon.d.ts +26 -0
  50. package/dist/commands/add-polygon.js +44 -0
  51. package/dist/commands/add-shape.d.ts +32 -0
  52. package/dist/commands/add-shape.js +41 -0
  53. package/dist/commands/add-text.d.ts +28 -0
  54. package/dist/commands/add-text.js +35 -0
  55. package/dist/commands/clear.d.ts +17 -0
  56. package/dist/commands/clear.js +23 -0
  57. package/dist/commands/delete-elements.d.ts +20 -0
  58. package/dist/commands/delete-elements.js +26 -0
  59. package/dist/commands/export.d.ts +26 -0
  60. package/dist/commands/export.js +45 -0
  61. package/dist/commands/group-elements.d.ts +20 -0
  62. package/dist/commands/group-elements.js +28 -0
  63. package/dist/commands/list.d.ts +23 -0
  64. package/dist/commands/list.js +50 -0
  65. package/dist/commands/load.d.ts +20 -0
  66. package/dist/commands/load.js +67 -0
  67. package/dist/commands/move-elements.d.ts +22 -0
  68. package/dist/commands/move-elements.js +26 -0
  69. package/dist/commands/new-canvas.d.ts +21 -0
  70. package/dist/commands/new-canvas.js +29 -0
  71. package/dist/commands/read.d.ts +23 -0
  72. package/dist/commands/read.js +49 -0
  73. package/dist/commands/rename-canvas.d.ts +20 -0
  74. package/dist/commands/rename-canvas.js +27 -0
  75. package/dist/commands/resize-elements.d.ts +24 -0
  76. package/dist/commands/resize-elements.js +41 -0
  77. package/dist/commands/rotate-elements.d.ts +21 -0
  78. package/dist/commands/rotate-elements.js +26 -0
  79. package/dist/commands/save.d.ts +18 -0
  80. package/dist/commands/save.js +27 -0
  81. package/dist/commands/start.d.ts +0 -1
  82. package/dist/commands/start.js +0 -41
  83. package/dist/commands/ungroup-element.d.ts +20 -0
  84. package/dist/commands/ungroup-element.js +28 -0
  85. package/dist/commands/use-canvas.d.ts +20 -0
  86. package/dist/commands/use-canvas.js +27 -0
  87. package/dist/index.js +124 -518
  88. package/dist/lib/__tests__/image-utils.test.d.ts +1 -0
  89. package/dist/lib/__tests__/image-utils.test.js +123 -0
  90. package/dist/lib/__tests__/toon-converter.test.d.ts +1 -0
  91. package/dist/lib/__tests__/toon-converter.test.js +586 -0
  92. package/dist/lib/__tests__/ws-client.test.d.ts +1 -0
  93. package/dist/lib/__tests__/ws-client.test.js +22 -0
  94. package/dist/lib/image-utils.d.ts +3 -0
  95. package/dist/lib/image-utils.js +21 -0
  96. package/dist/lib/protocol.d.ts +24 -0
  97. package/dist/lib/toon-converter.d.ts +104 -0
  98. package/dist/lib/toon-converter.js +221 -0
  99. package/dist/static/assets/{ar-SA-G6X2FPQ2-BghRBqlz.js → ar-SA-G6X2FPQ2-IkUozr1J.js} +1 -1
  100. package/dist/static/assets/{arc-BAce0Ut1.js → arc-DuydAvhB.js} +1 -1
  101. package/dist/static/assets/{az-AZ-76LH7QW2-KWJgGR5j.js → az-AZ-76LH7QW2-DBRYWxAA.js} +1 -1
  102. package/dist/static/assets/{bg-BG-XCXSNQG7-BR1q3b0y.js → bg-BG-XCXSNQG7-DSmqUlNK.js} +1 -1
  103. package/dist/static/assets/{blockDiagram-38ab4fdb-Btt0ZzJn.js → blockDiagram-38ab4fdb-BQnHv2Hd.js} +1 -1
  104. package/dist/static/assets/{bn-BD-2XOGV67Q-NMd2JSfE.js → bn-BD-2XOGV67Q-BaJNdEoY.js} +1 -1
  105. package/dist/static/assets/{c4Diagram-3d4e48cf-Z-Pe7XWi.js → c4Diagram-3d4e48cf-nnxDtLAZ.js} +1 -1
  106. package/dist/static/assets/{ca-ES-6MX7JW3Y-CK3Gu_Vw.js → ca-ES-6MX7JW3Y-DDNyK7J5.js} +1 -1
  107. package/dist/static/assets/channel-aYf9b-j5.js +1 -0
  108. package/dist/static/assets/{classDiagram-70f12bd4-EiSTrz_H.js → classDiagram-70f12bd4-CIBCZxZq.js} +1 -1
  109. package/dist/static/assets/{classDiagram-v2-f2320105-B1McR9kH.js → classDiagram-v2-f2320105-CLFL1Q2z.js} +1 -1
  110. package/dist/static/assets/clone-B3hpthU1.js +1 -0
  111. package/dist/static/assets/{createText-2e5e7dd3-BQBy36k6.js → createText-2e5e7dd3-SIC7Lt02.js} +1 -1
  112. package/dist/static/assets/{cs-CZ-2BRQDIVT-DF6mA41r.js → cs-CZ-2BRQDIVT-BO1WbIzV.js} +1 -1
  113. package/dist/static/assets/{da-DK-5WZEPLOC-BQxspr3A.js → da-DK-5WZEPLOC-CWzELCXm.js} +1 -1
  114. package/dist/static/assets/{de-DE-XR44H4JA-D9E7YcnW.js → de-DE-XR44H4JA-Om4YIZPb.js} +1 -1
  115. package/dist/static/assets/{edges-e0da2a9e-C-C2iHXy.js → edges-e0da2a9e-BbCc3B8k.js} +1 -1
  116. package/dist/static/assets/{el-GR-BZB4AONW-Bgv5eg1R.js → el-GR-BZB4AONW-K-rj9jd1.js} +1 -1
  117. package/dist/static/assets/{erDiagram-9861fffd-R9kTVhHm.js → erDiagram-9861fffd-DxKoJMPh.js} +1 -1
  118. package/dist/static/assets/{es-ES-U4NZUMDT-CjXWWJ7K.js → es-ES-U4NZUMDT-Cx8QrqZa.js} +1 -1
  119. package/dist/static/assets/{eu-ES-A7QVB2H4-BaBBwVk7.js → eu-ES-A7QVB2H4-DgVy2Gmm.js} +1 -1
  120. package/dist/static/assets/{fa-IR-HGAKTJCU-CobpSNqw.js → fa-IR-HGAKTJCU-9ZVEbUKc.js} +1 -1
  121. package/dist/static/assets/{fi-FI-Z5N7JZ37-C9VbkXdE.js → fi-FI-Z5N7JZ37-De9pNeaN.js} +1 -1
  122. package/dist/static/assets/{flowDb-956e92f1-DAytKtep.js → flowDb-956e92f1-CdAH1AaB.js} +1 -1
  123. package/dist/static/assets/{flowDiagram-66a62f08-hr4ccJC-.js → flowDiagram-66a62f08-DkevNttv.js} +1 -1
  124. package/dist/static/assets/flowDiagram-v2-96b9c2cf-J0E-rIBy.js +1 -0
  125. package/dist/static/assets/{flowchart-elk-definition-4a651766-DHdSZsGH.js → flowchart-elk-definition-4a651766-D15lofHZ.js} +1 -1
  126. package/dist/static/assets/{fr-FR-RHASNOE6-BnbTSuOS.js → fr-FR-RHASNOE6-BEr19lHe.js} +1 -1
  127. package/dist/static/assets/{ganttDiagram-c361ad54-DfJ4YdrQ.js → ganttDiagram-c361ad54-BXKB9krA.js} +1 -1
  128. package/dist/static/assets/{gitGraphDiagram-72cf32ee-CZZ1f5B8.js → gitGraphDiagram-72cf32ee-Ck8GuPPZ.js} +1 -1
  129. package/dist/static/assets/{gl-ES-HMX3MZ6V-CxRK4Wl3.js → gl-ES-HMX3MZ6V-Dagk_WKE.js} +1 -1
  130. package/dist/static/assets/{graph-P0vjqQ_q.js → graph-BDnEqDgl.js} +1 -1
  131. package/dist/static/assets/{he-IL-6SHJWFNN-De1ifwpn.js → he-IL-6SHJWFNN-e1Z1F8DN.js} +1 -1
  132. package/dist/static/assets/{hi-IN-IWLTKZ5I-DUjCaS-z.js → hi-IN-IWLTKZ5I-D4qMovdH.js} +1 -1
  133. package/dist/static/assets/{hu-HU-A5ZG7DT2-kRbxQLDu.js → hu-HU-A5ZG7DT2-DSQ4q_DT.js} +1 -1
  134. package/dist/static/assets/{id-ID-SAP4L64H-D3qNFMA5.js → id-ID-SAP4L64H-DTurwmey.js} +1 -1
  135. package/dist/static/assets/{index-3862675e-C6Y3GGXL.js → index-3862675e-C5fBRltS.js} +1 -1
  136. package/dist/static/assets/index-BJAHbcbi.js +316 -0
  137. package/dist/static/assets/{index-C2EUDYsE.js → index-yofiHCKL.js} +4 -4
  138. package/dist/static/assets/{infoDiagram-f8f76790-Bzz1cL3V.js → infoDiagram-f8f76790-C7bFiYkc.js} +1 -1
  139. package/dist/static/assets/{it-IT-JPQ66NNP-BTSOcgM2.js → it-IT-JPQ66NNP-CzHo4OTJ.js} +1 -1
  140. package/dist/static/assets/{ja-JP-DBVTYXUO-R5AkxKlX.js → ja-JP-DBVTYXUO-BBdvaTDd.js} +1 -1
  141. package/dist/static/assets/{journeyDiagram-49397b02-BzaeKV4P.js → journeyDiagram-49397b02-CKdUQSH9.js} +1 -1
  142. package/dist/static/assets/{kaa-6HZHGXH3-TpKFNLxf.js → kaa-6HZHGXH3-DWZSaF1Q.js} +1 -1
  143. package/dist/static/assets/{kab-KAB-ZGHBKWFO-BbPLfeaV.js → kab-KAB-ZGHBKWFO-DYNFBVD2.js} +1 -1
  144. package/dist/static/assets/{kk-KZ-P5N5QNE5-DcOwfzKm.js → kk-KZ-P5N5QNE5-Dm821F79.js} +1 -1
  145. package/dist/static/assets/{km-KH-HSX4SM5Z-DpDjUumQ.js → km-KH-HSX4SM5Z-CVFkT2xE.js} +1 -1
  146. package/dist/static/assets/{ko-KR-MTYHY66A-B6ZELq4q.js → ko-KR-MTYHY66A-PNa3t2z5.js} +1 -1
  147. package/dist/static/assets/{ku-TR-6OUDTVRD-Bw5XN8B3.js → ku-TR-6OUDTVRD-D50yyM1M.js} +1 -1
  148. package/dist/static/assets/{layout-xn_13JdK.js → layout-DfVi8moo.js} +1 -1
  149. package/dist/static/assets/{line-OtB_9B6o.js → line-Bz0tSC1s.js} +1 -1
  150. package/dist/static/assets/{linear-CglnwAad.js → linear-DuXcT5Hr.js} +1 -1
  151. package/dist/static/assets/{lt-LT-XHIRWOB4-B4P1_HMB.js → lt-LT-XHIRWOB4-CO03aPpI.js} +1 -1
  152. package/dist/static/assets/{lv-LV-5QDEKY6T-CeahhdFr.js → lv-LV-5QDEKY6T-C2w0RIc_.js} +1 -1
  153. package/dist/static/assets/{mindmap-definition-fc14e90a-B7krtWf6.js → mindmap-definition-fc14e90a-BCJ9d6wj.js} +1 -1
  154. package/dist/static/assets/{mr-IN-CRQNXWMA-BKet5bjT.js → mr-IN-CRQNXWMA-CPzzTfDr.js} +1 -1
  155. package/dist/static/assets/{my-MM-5M5IBNSE-B0RWOMGB.js → my-MM-5M5IBNSE-Mf5N1ItV.js} +1 -1
  156. package/dist/static/assets/{nb-NO-T6EIAALU-CH0RHqKo.js → nb-NO-T6EIAALU-Ba_9bhrc.js} +1 -1
  157. package/dist/static/assets/{nl-NL-IS3SIHDZ-OR0jupgw.js → nl-NL-IS3SIHDZ-BaAyV71L.js} +1 -1
  158. package/dist/static/assets/{nn-NO-6E72VCQL-C_nwbVBJ.js → nn-NO-6E72VCQL-CJb0Sevu.js} +1 -1
  159. package/dist/static/assets/{oc-FR-POXYY2M6-BkQ5_jwV.js → oc-FR-POXYY2M6-Bi7_UuRq.js} +1 -1
  160. package/dist/static/assets/{pa-IN-N4M65BXN-DVPoCEQf.js → pa-IN-N4M65BXN-DzgeUpdY.js} +1 -1
  161. package/dist/static/assets/{pica-DfKX2BtD.js → pica-xZUsXEnq.js} +1 -1
  162. package/dist/static/assets/{pieDiagram-8a3498a8-JeqvIFCn.js → pieDiagram-8a3498a8-DdPwPU4l.js} +1 -1
  163. package/dist/static/assets/{pl-PL-T2D74RX3-CSuyGES9.js → pl-PL-T2D74RX3-BOLgE3yy.js} +1 -1
  164. package/dist/static/assets/{pt-BR-5N22H2LF-Dl5YX_DK.js → pt-BR-5N22H2LF-BCkU80JQ.js} +1 -1
  165. package/dist/static/assets/{pt-PT-UZXXM6DQ-tdPflqgq.js → pt-PT-UZXXM6DQ-DR-6mHjZ.js} +1 -1
  166. package/dist/static/assets/{quadrantDiagram-120e2f19-BrP8m1hA.js → quadrantDiagram-120e2f19-BcAyroVn.js} +1 -1
  167. package/dist/static/assets/{requirementDiagram-deff3bca-DC6jgwHl.js → requirementDiagram-deff3bca-B21B9lfY.js} +1 -1
  168. package/dist/static/assets/{ro-RO-JPDTUUEW-DjqtjYSi.js → ro-RO-JPDTUUEW-BuQHeLbd.js} +1 -1
  169. package/dist/static/assets/{ru-RU-B4JR7IUQ-C3Co-mTL.js → ru-RU-B4JR7IUQ-DApvw6Zf.js} +1 -1
  170. package/dist/static/assets/{sankeyDiagram-04a897e0-CogkC2Ce.js → sankeyDiagram-04a897e0-BxWYtz_6.js} +1 -1
  171. package/dist/static/assets/{sequenceDiagram-704730f1-DQ7PWM4q.js → sequenceDiagram-704730f1-Dl_4U4se.js} +1 -1
  172. package/dist/static/assets/{si-LK-N5RQ5JYF-Bk0ZwDuh.js → si-LK-N5RQ5JYF-CymcxvPS.js} +1 -1
  173. package/dist/static/assets/{sk-SK-C5VTKIMK-DqcglIkB.js → sk-SK-C5VTKIMK-zH_ZmGbx.js} +1 -1
  174. package/dist/static/assets/{sl-SI-NN7IZMDC-CN9eHX7v.js → sl-SI-NN7IZMDC-CfPfpKu8.js} +1 -1
  175. package/dist/static/assets/{stateDiagram-587899a1-BfmF4tRu.js → stateDiagram-587899a1-BKz8o2mK.js} +1 -1
  176. package/dist/static/assets/{stateDiagram-v2-d93cdb3a-Fsz_mNjL.js → stateDiagram-v2-d93cdb3a-8wswK2sE.js} +1 -1
  177. package/dist/static/assets/{styles-6aaf32cf-iOrM4Idh.js → styles-6aaf32cf-BpIhk0mG.js} +1 -1
  178. package/dist/static/assets/{styles-9a916d00-BvjxcX3a.js → styles-9a916d00-BtBKasJV.js} +1 -1
  179. package/dist/static/assets/{styles-c10674c1-Dhs0qTvS.js → styles-c10674c1-DYQV_sr9.js} +1 -1
  180. package/dist/static/assets/{subset-shared.chunk-zGkIwnyc.js → subset-shared.chunk-CK6qplcn.js} +1 -1
  181. package/dist/static/assets/{subset-worker.chunk-tKNK3Srw.js → subset-worker.chunk-LfdEKIAo.js} +1 -1
  182. package/dist/static/assets/{sv-SE-XGPEYMSR-gIZ5ROCb.js → sv-SE-XGPEYMSR-BskWr0ll.js} +1 -1
  183. package/dist/static/assets/{svgDrawCommon-08f97a94-eaaXRKRL.js → svgDrawCommon-08f97a94-DtrYMmwR.js} +1 -1
  184. package/dist/static/assets/{ta-IN-2NMHFXQM-J93drr6G.js → ta-IN-2NMHFXQM-B9_YJxT9.js} +1 -1
  185. package/dist/static/assets/{th-TH-HPSO5L25-DvMH3MeT.js → th-TH-HPSO5L25-6zAvnYBe.js} +1 -1
  186. package/dist/static/assets/{timeline-definition-85554ec2-2H612cly.js → timeline-definition-85554ec2-DAQ4Ypha.js} +1 -1
  187. package/dist/static/assets/{tr-TR-DEFEU3FU-yaSV094c.js → tr-TR-DEFEU3FU-m_valPkK.js} +1 -1
  188. package/dist/static/assets/{uk-UA-QMV73CPH-D7efi_nG.js → uk-UA-QMV73CPH-DVM2xPaA.js} +1 -1
  189. package/dist/static/assets/{vi-VN-M7AON7JQ-CwCUJKTu.js → vi-VN-M7AON7JQ-DvdI1vFm.js} +1 -1
  190. package/dist/static/assets/{xychartDiagram-e933f94c-D9bLCt0H.js → xychartDiagram-e933f94c-DIvx2hk7.js} +1 -1
  191. package/dist/static/assets/{zh-CN-LNUGB5OW-BSP1R0gi.js → zh-CN-LNUGB5OW-B6EN7h-v.js} +1 -1
  192. package/dist/static/assets/{zh-HK-E62DVLB3-CrnbIjL6.js → zh-HK-E62DVLB3-DDkZVikU.js} +1 -1
  193. package/dist/static/assets/{zh-TW-RAJ6MFWO-qRdAErtD.js → zh-TW-RAJ6MFWO-BIHhDTYR.js} +1 -1
  194. package/dist/static/index.html +1 -1
  195. package/package.json +5 -2
  196. package/dist/static/assets/channel-WIJ4i-mf.js +0 -1
  197. package/dist/static/assets/clone-CIwebUPs.js +0 -1
  198. package/dist/static/assets/flowDiagram-v2-96b9c2cf-Dv1rlQah.js +0 -1
  199. package/dist/static/assets/index-BlIy8DSv.js +0 -311
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,186 @@
1
+ import { describe, it, expect, vi } from 'vitest';
2
+ import { addArrow, parseViaPoints } from '../add-arrow';
3
+ function createMockClient(sendFn) {
4
+ return {
5
+ send: sendFn ?? vi.fn(() => Promise.resolve({ success: true, elementId: 'el-1' })),
6
+ close: vi.fn(),
7
+ };
8
+ }
9
+ function createMockDeps(overrides) {
10
+ return {
11
+ connectToCanvas: vi.fn(() => Promise.resolve(createMockClient())),
12
+ generateId: vi.fn(() => 'test-id'),
13
+ log: vi.fn(),
14
+ error: vi.fn(),
15
+ exit: vi.fn(),
16
+ ...overrides,
17
+ };
18
+ }
19
+ // ==================== parseViaPoints Pure Function Tests ====================
20
+ describe('parseViaPoints', () => {
21
+ it('should parse single point', () => {
22
+ const result = parseViaPoints('100,200');
23
+ expect(result).toEqual([{ x: 100, y: 200 }]);
24
+ });
25
+ it('should parse multiple points', () => {
26
+ const result = parseViaPoints('100,200;300,400');
27
+ expect(result).toEqual([{ x: 100, y: 200 }, { x: 300, y: 400 }]);
28
+ });
29
+ it('should parse three points', () => {
30
+ const result = parseViaPoints('10,20;30,40;50,60');
31
+ expect(result).toEqual([{ x: 10, y: 20 }, { x: 30, y: 40 }, { x: 50, y: 60 }]);
32
+ });
33
+ });
34
+ describe('addArrow', () => {
35
+ // ==================== Parameter Assembly Tests ====================
36
+ describe('parameter assembly', () => {
37
+ it('should send correct params with required options only', async () => {
38
+ const mockSend = vi.fn(() => Promise.resolve({ success: true, elementId: 'el-1' }));
39
+ const mockClient = createMockClient(mockSend);
40
+ const deps = createMockDeps({
41
+ connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
42
+ });
43
+ await addArrow({ x: 100, y: 200, endX: 300, endY: 400 }, deps);
44
+ expect(mockSend).toHaveBeenCalledWith(expect.objectContaining({
45
+ type: 'addArrow',
46
+ id: 'test-id',
47
+ params: expect.objectContaining({
48
+ x: 100,
49
+ y: 200,
50
+ endX: 300,
51
+ endY: 400,
52
+ }),
53
+ }));
54
+ // customData and midpoints should be undefined when not provided
55
+ const callParams = mockSend.mock.calls[0][0].params;
56
+ expect(callParams.customData).toBeUndefined();
57
+ expect(callParams.midpoints).toBeUndefined();
58
+ });
59
+ it('should send correct optional style params', async () => {
60
+ const mockSend = vi.fn(() => Promise.resolve({ success: true, elementId: 'el-1' }));
61
+ const mockClient = createMockClient(mockSend);
62
+ const deps = createMockDeps({
63
+ connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
64
+ });
65
+ await addArrow({
66
+ x: 0,
67
+ y: 0,
68
+ endX: 100,
69
+ endY: 100,
70
+ strokeColor: '#ff0000',
71
+ strokeWidth: 2,
72
+ strokeStyle: 'dashed',
73
+ startArrowhead: 'none',
74
+ endArrowhead: 'triangle',
75
+ arrowType: 'round',
76
+ }, deps);
77
+ const callParams = mockSend.mock.calls[0][0].params;
78
+ expect(callParams.strokeColor).toBe('#ff0000');
79
+ expect(callParams.strokeWidth).toBe(2);
80
+ expect(callParams.strokeStyle).toBe('dashed');
81
+ expect(callParams.startArrowhead).toBe('none');
82
+ expect(callParams.endArrowhead).toBe('triangle');
83
+ expect(callParams.arrowType).toBe('round');
84
+ });
85
+ it('should parse via into midpoints when provided', async () => {
86
+ const mockSend = vi.fn(() => Promise.resolve({ success: true, elementId: 'el-1' }));
87
+ const mockClient = createMockClient(mockSend);
88
+ const deps = createMockDeps({
89
+ connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
90
+ });
91
+ await addArrow({
92
+ x: 0,
93
+ y: 0,
94
+ endX: 200,
95
+ endY: 200,
96
+ via: '100,50;150,150',
97
+ }, deps);
98
+ const callParams = mockSend.mock.calls[0][0].params;
99
+ expect(callParams.midpoints).toEqual([{ x: 100, y: 50 }, { x: 150, y: 150 }]);
100
+ });
101
+ it('should have undefined midpoints when via is not provided', async () => {
102
+ const mockSend = vi.fn(() => Promise.resolve({ success: true, elementId: 'el-1' }));
103
+ const mockClient = createMockClient(mockSend);
104
+ const deps = createMockDeps({
105
+ connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
106
+ });
107
+ await addArrow({ x: 0, y: 0, endX: 100, endY: 100 }, deps);
108
+ const callParams = mockSend.mock.calls[0][0].params;
109
+ expect(callParams.midpoints).toBeUndefined();
110
+ });
111
+ it('should set customData with note when note is provided', async () => {
112
+ const mockSend = vi.fn(() => Promise.resolve({ success: true, elementId: 'el-1' }));
113
+ const mockClient = createMockClient(mockSend);
114
+ const deps = createMockDeps({
115
+ connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
116
+ });
117
+ await addArrow({
118
+ x: 0,
119
+ y: 0,
120
+ endX: 100,
121
+ endY: 100,
122
+ note: 'my arrow note',
123
+ }, deps);
124
+ const callParams = mockSend.mock.calls[0][0].params;
125
+ expect(callParams.customData).toEqual({ note: 'my arrow note' });
126
+ });
127
+ it('should not include customData when note is not provided', async () => {
128
+ const mockSend = vi.fn(() => Promise.resolve({ success: true, elementId: 'el-1' }));
129
+ const mockClient = createMockClient(mockSend);
130
+ const deps = createMockDeps({
131
+ connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
132
+ });
133
+ await addArrow({ x: 0, y: 0, endX: 100, endY: 100 }, deps);
134
+ const callParams = mockSend.mock.calls[0][0].params;
135
+ expect(callParams.customData).toBeUndefined();
136
+ });
137
+ });
138
+ // ==================== Response Handling Tests ====================
139
+ describe('response handling', () => {
140
+ it('should log success message with element id', async () => {
141
+ const mockSend = vi.fn(() => Promise.resolve({
142
+ success: true,
143
+ elementId: 'el-123',
144
+ }));
145
+ const mockClient = createMockClient(mockSend);
146
+ const deps = createMockDeps({
147
+ connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
148
+ });
149
+ await addArrow({ x: 0, y: 0, endX: 100, endY: 100 }, deps);
150
+ expect(deps.log).toHaveBeenCalledWith('Arrow created (id: el-123)');
151
+ });
152
+ it('should error and exit on failure response', async () => {
153
+ const mockSend = vi.fn(() => Promise.resolve({
154
+ success: false,
155
+ error: 'Something went wrong',
156
+ }));
157
+ const mockClient = createMockClient(mockSend);
158
+ const deps = createMockDeps({
159
+ connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
160
+ });
161
+ await addArrow({ x: 0, y: 0, endX: 100, endY: 100 }, deps);
162
+ expect(deps.error).toHaveBeenCalledWith('Failed: Something went wrong');
163
+ expect(deps.exit).toHaveBeenCalledWith(1);
164
+ });
165
+ it('should close client after success', async () => {
166
+ const mockClose = vi.fn();
167
+ const mockSend = vi.fn(() => Promise.resolve({ success: true, elementId: 'el-1' }));
168
+ const mockClient = { send: mockSend, close: mockClose };
169
+ const deps = createMockDeps({
170
+ connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
171
+ });
172
+ await addArrow({ x: 0, y: 0, endX: 100, endY: 100 }, deps);
173
+ expect(mockClose).toHaveBeenCalled();
174
+ });
175
+ it('should close client after failure', async () => {
176
+ const mockClose = vi.fn();
177
+ const mockSend = vi.fn(() => Promise.resolve({ success: false, error: 'error' }));
178
+ const mockClient = { send: mockSend, close: mockClose };
179
+ const deps = createMockDeps({
180
+ connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
181
+ });
182
+ await addArrow({ x: 0, y: 0, endX: 100, endY: 100 }, deps);
183
+ expect(mockClose).toHaveBeenCalled();
184
+ });
185
+ });
186
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,170 @@
1
+ import { describe, it, expect, vi } from 'vitest';
2
+ import { addImage } from '../add-image';
3
+ function createMockClient(sendFn) {
4
+ return {
5
+ send: sendFn ?? vi.fn(() => Promise.resolve({ success: true, elementId: 'el-1', fileId: 'file-1' })),
6
+ close: vi.fn(),
7
+ };
8
+ }
9
+ function createMockDeps(overrides) {
10
+ return {
11
+ readFile: vi.fn(() => Buffer.from('fake-image-data')),
12
+ connectToCanvas: vi.fn(() => Promise.resolve(createMockClient())),
13
+ generateId: vi.fn(() => 'test-id'),
14
+ log: vi.fn(),
15
+ error: vi.fn(),
16
+ exit: vi.fn(),
17
+ ...overrides,
18
+ };
19
+ }
20
+ describe('addImage', () => {
21
+ // ==================== Input Validation Tests ====================
22
+ describe('input validation', () => {
23
+ it('should error on unsupported image format', async () => {
24
+ const deps = createMockDeps();
25
+ await addImage({ file: 'test.txt', x: 0, y: 0 }, deps);
26
+ expect(deps.error).toHaveBeenCalledWith('Unsupported image format. Supported: PNG, JPEG, GIF, SVG, WebP');
27
+ expect(deps.exit).toHaveBeenCalledWith(1);
28
+ expect(deps.connectToCanvas).not.toHaveBeenCalled();
29
+ });
30
+ it('should error when file does not exist', async () => {
31
+ const deps = createMockDeps({
32
+ readFile: vi.fn(() => { throw new Error('ENOENT'); }),
33
+ });
34
+ await addImage({ file: 'missing.png', x: 0, y: 0 }, deps);
35
+ expect(deps.error).toHaveBeenCalledWith('Failed to read file: missing.png');
36
+ expect(deps.exit).toHaveBeenCalledWith(1);
37
+ });
38
+ it('should error when file is too large', async () => {
39
+ const largeBuffer = Buffer.alloc(3 * 1024 * 1024); // 3MB
40
+ const deps = createMockDeps({
41
+ readFile: vi.fn(() => largeBuffer),
42
+ });
43
+ await addImage({ file: 'large.png', x: 0, y: 0 }, deps);
44
+ expect(deps.error).toHaveBeenCalledWith('Image too large: 3.00MB (max: 2MB)');
45
+ expect(deps.exit).toHaveBeenCalledWith(1);
46
+ });
47
+ });
48
+ // ==================== Parameter Assembly Tests ====================
49
+ describe('parameter assembly', () => {
50
+ it('should send correct params with required options only', async () => {
51
+ const mockSend = vi.fn(() => Promise.resolve({ success: true, elementId: 'el-1', fileId: 'file-1' }));
52
+ const mockClient = createMockClient(mockSend);
53
+ const deps = createMockDeps({
54
+ connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
55
+ });
56
+ await addImage({ file: 'test.png', x: 100, y: 200 }, deps);
57
+ expect(mockSend).toHaveBeenCalledWith(expect.objectContaining({
58
+ type: 'addImage',
59
+ params: expect.objectContaining({
60
+ x: 100,
61
+ y: 200,
62
+ mimeType: 'image/png',
63
+ }),
64
+ }));
65
+ // customData should be undefined when no note
66
+ const callParams = mockSend.mock.calls[0][0].params;
67
+ expect(callParams.customData).toBeUndefined();
68
+ });
69
+ it('should send correct params with all options', async () => {
70
+ const mockSend = vi.fn(() => Promise.resolve({ success: true, elementId: 'el-1', fileId: 'file-1' }));
71
+ const mockClient = createMockClient(mockSend);
72
+ const deps = createMockDeps({
73
+ connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
74
+ });
75
+ await addImage({
76
+ file: 'test.jpg',
77
+ x: 100,
78
+ y: 200,
79
+ width: 300,
80
+ height: 400,
81
+ note: 'test note',
82
+ }, deps);
83
+ const callParams = mockSend.mock.calls[0][0].params;
84
+ expect(callParams.x).toBe(100);
85
+ expect(callParams.y).toBe(200);
86
+ expect(callParams.width).toBe(300);
87
+ expect(callParams.height).toBe(400);
88
+ expect(callParams.mimeType).toBe('image/jpeg');
89
+ expect(callParams.customData).toEqual({ note: 'test note' });
90
+ });
91
+ it('should generate correct dataUrl format', async () => {
92
+ const testData = Buffer.from('test-image-content');
93
+ const mockSend = vi.fn(() => Promise.resolve({ success: true, elementId: 'el-1', fileId: 'file-1' }));
94
+ const mockClient = createMockClient(mockSend);
95
+ const deps = createMockDeps({
96
+ readFile: vi.fn(() => testData),
97
+ connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
98
+ });
99
+ await addImage({ file: 'test.png', x: 0, y: 0 }, deps);
100
+ const callParams = mockSend.mock.calls[0][0].params;
101
+ expect(callParams.dataUrl).toBe(`data:image/png;base64,${testData.toString('base64')}`);
102
+ });
103
+ it('should generate fileId from buffer content', async () => {
104
+ const testData = Buffer.from('unique-content');
105
+ const mockSend = vi.fn(() => Promise.resolve({ success: true, elementId: 'el-1', fileId: 'file-1' }));
106
+ const mockClient = createMockClient(mockSend);
107
+ const deps = createMockDeps({
108
+ readFile: vi.fn(() => testData),
109
+ connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
110
+ });
111
+ await addImage({ file: 'test.png', x: 0, y: 0 }, deps);
112
+ const callParams = mockSend.mock.calls[0][0].params;
113
+ // fileId should be 40 char SHA-1 hash
114
+ expect(callParams.fileId).toMatch(/^[0-9a-f]{40}$/);
115
+ });
116
+ });
117
+ // ==================== Response Handling Tests ====================
118
+ describe('response handling', () => {
119
+ it('should log success message with dimensions when provided', async () => {
120
+ const mockSend = vi.fn(() => Promise.resolve({
121
+ success: true,
122
+ elementId: 'el-123',
123
+ fileId: 'file-456',
124
+ x: 100,
125
+ y: 200,
126
+ width: 300,
127
+ height: 400,
128
+ }));
129
+ const mockClient = createMockClient(mockSend);
130
+ const deps = createMockDeps({
131
+ connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
132
+ });
133
+ await addImage({ file: 'test.png', x: 100, y: 200 }, deps);
134
+ expect(deps.log).toHaveBeenCalledWith('Image added (id: el-123, fileId: file-456 x=100 y=200 w=300 h=400)');
135
+ });
136
+ it('should error and exit on failure response', async () => {
137
+ const mockSend = vi.fn(() => Promise.resolve({
138
+ success: false,
139
+ error: 'Something went wrong',
140
+ }));
141
+ const mockClient = createMockClient(mockSend);
142
+ const deps = createMockDeps({
143
+ connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
144
+ });
145
+ await addImage({ file: 'test.png', x: 0, y: 0 }, deps);
146
+ expect(deps.error).toHaveBeenCalledWith('Failed: Something went wrong');
147
+ expect(deps.exit).toHaveBeenCalledWith(1);
148
+ });
149
+ it('should close client after success', async () => {
150
+ const mockClose = vi.fn();
151
+ const mockSend = vi.fn(() => Promise.resolve({ success: true, elementId: 'el-1', fileId: 'file-1' }));
152
+ const mockClient = { send: mockSend, close: mockClose };
153
+ const deps = createMockDeps({
154
+ connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
155
+ });
156
+ await addImage({ file: 'test.png', x: 0, y: 0 }, deps);
157
+ expect(mockClose).toHaveBeenCalled();
158
+ });
159
+ it('should close client after failure', async () => {
160
+ const mockClose = vi.fn();
161
+ const mockSend = vi.fn(() => Promise.resolve({ success: false, error: 'error' }));
162
+ const mockClient = { send: mockSend, close: mockClose };
163
+ const deps = createMockDeps({
164
+ connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
165
+ });
166
+ await addImage({ file: 'test.png', x: 0, y: 0 }, deps);
167
+ expect(mockClose).toHaveBeenCalled();
168
+ });
169
+ });
170
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,138 @@
1
+ import { describe, it, expect, vi } from 'vitest';
2
+ import { addLine } from '../add-line';
3
+ function createMockClient(sendFn) {
4
+ return {
5
+ send: sendFn ?? vi.fn(() => Promise.resolve({ success: true, elementId: 'el-1' })),
6
+ close: vi.fn(),
7
+ };
8
+ }
9
+ function createMockDeps(overrides) {
10
+ return {
11
+ connectToCanvas: vi.fn(() => Promise.resolve(createMockClient())),
12
+ generateId: vi.fn(() => 'test-id'),
13
+ log: vi.fn(),
14
+ error: vi.fn(),
15
+ exit: vi.fn(),
16
+ ...overrides,
17
+ };
18
+ }
19
+ describe('addLine', () => {
20
+ // ==================== Parameter Assembly Tests ====================
21
+ describe('parameter assembly', () => {
22
+ it('should send correct params with required options only', async () => {
23
+ const mockSend = vi.fn(() => Promise.resolve({ success: true, elementId: 'el-1' }));
24
+ const mockClient = createMockClient(mockSend);
25
+ const deps = createMockDeps({
26
+ connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
27
+ });
28
+ await addLine({ x: 100, y: 200, endX: 300, endY: 400 }, deps);
29
+ expect(mockSend).toHaveBeenCalledWith(expect.objectContaining({
30
+ type: 'addLine',
31
+ id: 'test-id',
32
+ params: expect.objectContaining({
33
+ x: 100,
34
+ y: 200,
35
+ endX: 300,
36
+ endY: 400,
37
+ }),
38
+ }));
39
+ // customData should be undefined when no note
40
+ const callParams = mockSend.mock.calls[0][0].params;
41
+ expect(callParams.customData).toBeUndefined();
42
+ });
43
+ it('should send correct optional style params', async () => {
44
+ const mockSend = vi.fn(() => Promise.resolve({ success: true, elementId: 'el-1' }));
45
+ const mockClient = createMockClient(mockSend);
46
+ const deps = createMockDeps({
47
+ connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
48
+ });
49
+ await addLine({
50
+ x: 0,
51
+ y: 0,
52
+ endX: 100,
53
+ endY: 100,
54
+ strokeColor: '#ff0000',
55
+ strokeWidth: 2,
56
+ strokeStyle: 'dashed',
57
+ }, deps);
58
+ const callParams = mockSend.mock.calls[0][0].params;
59
+ expect(callParams.strokeColor).toBe('#ff0000');
60
+ expect(callParams.strokeWidth).toBe(2);
61
+ expect(callParams.strokeStyle).toBe('dashed');
62
+ });
63
+ it('should set customData with note when note is provided', async () => {
64
+ const mockSend = vi.fn(() => Promise.resolve({ success: true, elementId: 'el-1' }));
65
+ const mockClient = createMockClient(mockSend);
66
+ const deps = createMockDeps({
67
+ connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
68
+ });
69
+ await addLine({
70
+ x: 0,
71
+ y: 0,
72
+ endX: 100,
73
+ endY: 100,
74
+ note: 'my line note',
75
+ }, deps);
76
+ const callParams = mockSend.mock.calls[0][0].params;
77
+ expect(callParams.customData).toEqual({ note: 'my line note' });
78
+ });
79
+ it('should not include customData when note is not provided', async () => {
80
+ const mockSend = vi.fn(() => Promise.resolve({ success: true, elementId: 'el-1' }));
81
+ const mockClient = createMockClient(mockSend);
82
+ const deps = createMockDeps({
83
+ connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
84
+ });
85
+ await addLine({ x: 0, y: 0, endX: 100, endY: 100 }, deps);
86
+ const callParams = mockSend.mock.calls[0][0].params;
87
+ expect(callParams.customData).toBeUndefined();
88
+ });
89
+ });
90
+ // ==================== Response Handling Tests ====================
91
+ describe('response handling', () => {
92
+ it('should log success message with element id', async () => {
93
+ const mockSend = vi.fn(() => Promise.resolve({
94
+ success: true,
95
+ elementId: 'el-123',
96
+ }));
97
+ const mockClient = createMockClient(mockSend);
98
+ const deps = createMockDeps({
99
+ connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
100
+ });
101
+ await addLine({ x: 0, y: 0, endX: 100, endY: 100 }, deps);
102
+ expect(deps.log).toHaveBeenCalledWith('Line created (id: el-123)');
103
+ });
104
+ it('should error and exit on failure response', async () => {
105
+ const mockSend = vi.fn(() => Promise.resolve({
106
+ success: false,
107
+ error: 'Something went wrong',
108
+ }));
109
+ const mockClient = createMockClient(mockSend);
110
+ const deps = createMockDeps({
111
+ connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
112
+ });
113
+ await addLine({ x: 0, y: 0, endX: 100, endY: 100 }, deps);
114
+ expect(deps.error).toHaveBeenCalledWith('Failed: Something went wrong');
115
+ expect(deps.exit).toHaveBeenCalledWith(1);
116
+ });
117
+ it('should close client after success', async () => {
118
+ const mockClose = vi.fn();
119
+ const mockSend = vi.fn(() => Promise.resolve({ success: true, elementId: 'el-1' }));
120
+ const mockClient = { send: mockSend, close: mockClose };
121
+ const deps = createMockDeps({
122
+ connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
123
+ });
124
+ await addLine({ x: 0, y: 0, endX: 100, endY: 100 }, deps);
125
+ expect(mockClose).toHaveBeenCalled();
126
+ });
127
+ it('should close client after failure', async () => {
128
+ const mockClose = vi.fn();
129
+ const mockSend = vi.fn(() => Promise.resolve({ success: false, error: 'error' }));
130
+ const mockClient = { send: mockSend, close: mockClose };
131
+ const deps = createMockDeps({
132
+ connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
133
+ });
134
+ await addLine({ x: 0, y: 0, endX: 100, endY: 100 }, deps);
135
+ expect(mockClose).toHaveBeenCalled();
136
+ });
137
+ });
138
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,147 @@
1
+ import { describe, it, expect, vi } from 'vitest';
2
+ import { addPolygon } from '../add-polygon';
3
+ function createMockClient(sendFn) {
4
+ return {
5
+ send: sendFn ?? vi.fn(() => Promise.resolve({ success: true, elementId: 'el-1' })),
6
+ close: vi.fn(),
7
+ };
8
+ }
9
+ function createMockDeps(overrides) {
10
+ return {
11
+ connectToCanvas: vi.fn(() => Promise.resolve(createMockClient())),
12
+ generateId: vi.fn(() => 'test-id'),
13
+ log: vi.fn(),
14
+ error: vi.fn(),
15
+ exit: vi.fn(),
16
+ ...overrides,
17
+ };
18
+ }
19
+ describe('addPolygon', () => {
20
+ // ==================== Input Validation Tests ====================
21
+ describe('input validation', () => {
22
+ it('should error and exit when points JSON is invalid', async () => {
23
+ const deps = createMockDeps();
24
+ await addPolygon({ points: 'not-valid-json' }, deps);
25
+ expect(deps.error).toHaveBeenCalledWith('Invalid points JSON');
26
+ expect(deps.exit).toHaveBeenCalledWith(1);
27
+ // WebSocket should not be called
28
+ expect(deps.connectToCanvas).not.toHaveBeenCalled();
29
+ });
30
+ it('should not connect to WebSocket when JSON parsing fails', async () => {
31
+ const deps = createMockDeps();
32
+ await addPolygon({ points: '{invalid' }, deps);
33
+ expect(deps.connectToCanvas).not.toHaveBeenCalled();
34
+ });
35
+ });
36
+ // ==================== Parameter Assembly Tests ====================
37
+ describe('parameter assembly', () => {
38
+ it('should parse and send points correctly', async () => {
39
+ const mockSend = vi.fn(() => Promise.resolve({ success: true, elementId: 'el-1' }));
40
+ const mockClient = createMockClient(mockSend);
41
+ const deps = createMockDeps({
42
+ connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
43
+ });
44
+ const pointsJson = '[{"x":0,"y":0},{"x":100,"y":0},{"x":50,"y":100}]';
45
+ await addPolygon({ points: pointsJson }, deps);
46
+ expect(mockSend).toHaveBeenCalledWith(expect.objectContaining({
47
+ type: 'addPolygon',
48
+ id: 'test-id',
49
+ params: expect.objectContaining({
50
+ points: [{ x: 0, y: 0 }, { x: 100, y: 0 }, { x: 50, y: 100 }],
51
+ }),
52
+ }));
53
+ });
54
+ it('should send correct style params', async () => {
55
+ const mockSend = vi.fn(() => Promise.resolve({ success: true, elementId: 'el-1' }));
56
+ const mockClient = createMockClient(mockSend);
57
+ const deps = createMockDeps({
58
+ connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
59
+ });
60
+ await addPolygon({
61
+ points: '[{"x":0,"y":0},{"x":100,"y":0}]',
62
+ strokeColor: '#ff0000',
63
+ backgroundColor: '#00ff00',
64
+ strokeWidth: 2,
65
+ strokeStyle: 'dashed',
66
+ fillStyle: 'solid',
67
+ }, deps);
68
+ const callParams = mockSend.mock.calls[0][0].params;
69
+ expect(callParams.strokeColor).toBe('#ff0000');
70
+ expect(callParams.backgroundColor).toBe('#00ff00');
71
+ expect(callParams.strokeWidth).toBe(2);
72
+ expect(callParams.strokeStyle).toBe('dashed');
73
+ expect(callParams.fillStyle).toBe('solid');
74
+ });
75
+ it('should set customData with note when note is provided', async () => {
76
+ const mockSend = vi.fn(() => Promise.resolve({ success: true, elementId: 'el-1' }));
77
+ const mockClient = createMockClient(mockSend);
78
+ const deps = createMockDeps({
79
+ connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
80
+ });
81
+ await addPolygon({
82
+ points: '[{"x":0,"y":0},{"x":100,"y":0}]',
83
+ note: 'my note',
84
+ }, deps);
85
+ const callParams = mockSend.mock.calls[0][0].params;
86
+ expect(callParams.customData).toEqual({ note: 'my note' });
87
+ });
88
+ it('should not include customData when note is not provided', async () => {
89
+ const mockSend = vi.fn(() => Promise.resolve({ success: true, elementId: 'el-1' }));
90
+ const mockClient = createMockClient(mockSend);
91
+ const deps = createMockDeps({
92
+ connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
93
+ });
94
+ await addPolygon({ points: '[{"x":0,"y":0}]' }, deps);
95
+ const callParams = mockSend.mock.calls[0][0].params;
96
+ expect(callParams.customData).toBeUndefined();
97
+ });
98
+ });
99
+ // ==================== Response Handling Tests ====================
100
+ describe('response handling', () => {
101
+ it('should log success message with element id', async () => {
102
+ const mockSend = vi.fn(() => Promise.resolve({
103
+ success: true,
104
+ elementId: 'el-123',
105
+ }));
106
+ const mockClient = createMockClient(mockSend);
107
+ const deps = createMockDeps({
108
+ connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
109
+ });
110
+ await addPolygon({ points: '[{"x":0,"y":0}]' }, deps);
111
+ expect(deps.log).toHaveBeenCalledWith('Polygon created (id: el-123)');
112
+ });
113
+ it('should error and exit on failure response', async () => {
114
+ const mockSend = vi.fn(() => Promise.resolve({
115
+ success: false,
116
+ error: 'Something went wrong',
117
+ }));
118
+ const mockClient = createMockClient(mockSend);
119
+ const deps = createMockDeps({
120
+ connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
121
+ });
122
+ await addPolygon({ points: '[{"x":0,"y":0}]' }, deps);
123
+ expect(deps.error).toHaveBeenCalledWith('Failed: Something went wrong');
124
+ expect(deps.exit).toHaveBeenCalledWith(1);
125
+ });
126
+ it('should close client after success', async () => {
127
+ const mockClose = vi.fn();
128
+ const mockSend = vi.fn(() => Promise.resolve({ success: true, elementId: 'el-1' }));
129
+ const mockClient = { send: mockSend, close: mockClose };
130
+ const deps = createMockDeps({
131
+ connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
132
+ });
133
+ await addPolygon({ points: '[{"x":0,"y":0}]' }, deps);
134
+ expect(mockClose).toHaveBeenCalled();
135
+ });
136
+ it('should close client after failure', async () => {
137
+ const mockClose = vi.fn();
138
+ const mockSend = vi.fn(() => Promise.resolve({ success: false, error: 'error' }));
139
+ const mockClient = { send: mockSend, close: mockClose };
140
+ const deps = createMockDeps({
141
+ connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
142
+ });
143
+ await addPolygon({ points: '[{"x":0,"y":0}]' }, deps);
144
+ expect(mockClose).toHaveBeenCalled();
145
+ });
146
+ });
147
+ });
@@ -0,0 +1 @@
1
+ export {};