@agent-canvas/cli 0.8.0 → 0.9.0

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-DrFZc17I.js → ar-SA-G6X2FPQ2-DBOnFzSe.js} +1 -1
  100. package/dist/static/assets/{arc-BE4RRWho.js → arc-bbUtBUEI.js} +1 -1
  101. package/dist/static/assets/{az-AZ-76LH7QW2-DgHo0c8x.js → az-AZ-76LH7QW2-Cc10aZ9u.js} +1 -1
  102. package/dist/static/assets/{bg-BG-XCXSNQG7-D6Qfq7sN.js → bg-BG-XCXSNQG7-Ccf7m1dz.js} +1 -1
  103. package/dist/static/assets/{blockDiagram-38ab4fdb-j4QCKNBJ.js → blockDiagram-38ab4fdb-fpHXuuqC.js} +1 -1
  104. package/dist/static/assets/{bn-BD-2XOGV67Q-DtD_GeTA.js → bn-BD-2XOGV67Q-DUsn1OkS.js} +1 -1
  105. package/dist/static/assets/{c4Diagram-3d4e48cf-BmQ9mE4L.js → c4Diagram-3d4e48cf-R8YUsP4D.js} +1 -1
  106. package/dist/static/assets/{ca-ES-6MX7JW3Y-pqblEVH2.js → ca-ES-6MX7JW3Y-hu4EsJg6.js} +1 -1
  107. package/dist/static/assets/channel-DOejQ6Zr.js +1 -0
  108. package/dist/static/assets/{classDiagram-70f12bd4-CUF5vm_X.js → classDiagram-70f12bd4-Bd-nCoOe.js} +1 -1
  109. package/dist/static/assets/{classDiagram-v2-f2320105-Cpj_A_lB.js → classDiagram-v2-f2320105-BSqlF2Ya.js} +1 -1
  110. package/dist/static/assets/clone-BACvnIVb.js +1 -0
  111. package/dist/static/assets/{createText-2e5e7dd3-pnM7Sebc.js → createText-2e5e7dd3-DDxcRLmM.js} +1 -1
  112. package/dist/static/assets/{cs-CZ-2BRQDIVT-CybzkHZt.js → cs-CZ-2BRQDIVT-CvZtKTE7.js} +1 -1
  113. package/dist/static/assets/{da-DK-5WZEPLOC-pqELhXiQ.js → da-DK-5WZEPLOC-Bo6-ltfA.js} +1 -1
  114. package/dist/static/assets/{de-DE-XR44H4JA-ZL76WiIL.js → de-DE-XR44H4JA-Rki2qM_x.js} +1 -1
  115. package/dist/static/assets/{edges-e0da2a9e-B9extNmC.js → edges-e0da2a9e-DWJxCouB.js} +1 -1
  116. package/dist/static/assets/{el-GR-BZB4AONW-rKEdKItN.js → el-GR-BZB4AONW-BRy2rrt9.js} +1 -1
  117. package/dist/static/assets/{erDiagram-9861fffd-Bf-1lr9-.js → erDiagram-9861fffd-DXldiM4J.js} +1 -1
  118. package/dist/static/assets/{es-ES-U4NZUMDT-BB6riLIk.js → es-ES-U4NZUMDT-hCKbxwHs.js} +1 -1
  119. package/dist/static/assets/{eu-ES-A7QVB2H4-ChqJNrpA.js → eu-ES-A7QVB2H4-CmZGwoa5.js} +1 -1
  120. package/dist/static/assets/{fa-IR-HGAKTJCU--KEd62Xu.js → fa-IR-HGAKTJCU-C6DRPcaF.js} +1 -1
  121. package/dist/static/assets/{fi-FI-Z5N7JZ37-CdB0adCJ.js → fi-FI-Z5N7JZ37-DBaspnIB.js} +1 -1
  122. package/dist/static/assets/{flowDb-956e92f1-Dbca38tY.js → flowDb-956e92f1-C48Cmgvd.js} +1 -1
  123. package/dist/static/assets/{flowDiagram-66a62f08-DpQc0ZQB.js → flowDiagram-66a62f08-DV7f8TtG.js} +1 -1
  124. package/dist/static/assets/flowDiagram-v2-96b9c2cf-MnAxlKb6.js +1 -0
  125. package/dist/static/assets/{flowchart-elk-definition-4a651766-CAxl2EAj.js → flowchart-elk-definition-4a651766-C2muEpzy.js} +1 -1
  126. package/dist/static/assets/{fr-FR-RHASNOE6-LEJbMD3b.js → fr-FR-RHASNOE6-D1dEEEfS.js} +1 -1
  127. package/dist/static/assets/{ganttDiagram-c361ad54-BsKueDb1.js → ganttDiagram-c361ad54-CrooqCzc.js} +1 -1
  128. package/dist/static/assets/{gitGraphDiagram-72cf32ee-BySoTKcT.js → gitGraphDiagram-72cf32ee-x7BVIo_3.js} +1 -1
  129. package/dist/static/assets/{gl-ES-HMX3MZ6V-Bi3P3M7W.js → gl-ES-HMX3MZ6V-Czkw2ahx.js} +1 -1
  130. package/dist/static/assets/{graph-B_0qOa-k.js → graph-Bv0C_szp.js} +1 -1
  131. package/dist/static/assets/{he-IL-6SHJWFNN-DE7_aRwg.js → he-IL-6SHJWFNN-BLwbN3CV.js} +1 -1
  132. package/dist/static/assets/{hi-IN-IWLTKZ5I-CjARmJ8i.js → hi-IN-IWLTKZ5I-BJh3HrXc.js} +1 -1
  133. package/dist/static/assets/{hu-HU-A5ZG7DT2-d79urL5L.js → hu-HU-A5ZG7DT2-D00s-8EN.js} +1 -1
  134. package/dist/static/assets/{id-ID-SAP4L64H-bxo8Q0Jv.js → id-ID-SAP4L64H-BmyuzwXV.js} +1 -1
  135. package/dist/static/assets/{index-3862675e-BLm8h60G.js → index-3862675e-mZlepZqF.js} +1 -1
  136. package/dist/static/assets/{index-BkW4NM9R.js → index-Bnmyv9TE.js} +4 -4
  137. package/dist/static/assets/index-jjzEa4oB.js +316 -0
  138. package/dist/static/assets/{infoDiagram-f8f76790-CZ4J5sjk.js → infoDiagram-f8f76790-w7FUTsVV.js} +1 -1
  139. package/dist/static/assets/{it-IT-JPQ66NNP-D41R3uEK.js → it-IT-JPQ66NNP-CeVq0l8v.js} +1 -1
  140. package/dist/static/assets/{ja-JP-DBVTYXUO-zK8NUJnS.js → ja-JP-DBVTYXUO-BUNKxxGA.js} +1 -1
  141. package/dist/static/assets/{journeyDiagram-49397b02-DtFcZaIk.js → journeyDiagram-49397b02-DYjDqkQG.js} +1 -1
  142. package/dist/static/assets/{kaa-6HZHGXH3-CbGIc6V6.js → kaa-6HZHGXH3-BIKwULqb.js} +1 -1
  143. package/dist/static/assets/{kab-KAB-ZGHBKWFO-BweHPuX1.js → kab-KAB-ZGHBKWFO-BDpRo7IX.js} +1 -1
  144. package/dist/static/assets/{kk-KZ-P5N5QNE5-DSokMm7h.js → kk-KZ-P5N5QNE5-bI2LN3W0.js} +1 -1
  145. package/dist/static/assets/{km-KH-HSX4SM5Z-LYiEs3ge.js → km-KH-HSX4SM5Z-gtwrLJn5.js} +1 -1
  146. package/dist/static/assets/{ko-KR-MTYHY66A-BzgMEtcU.js → ko-KR-MTYHY66A-BVcwVELq.js} +1 -1
  147. package/dist/static/assets/{ku-TR-6OUDTVRD-D1FtjbSs.js → ku-TR-6OUDTVRD-COvDJH7d.js} +1 -1
  148. package/dist/static/assets/{layout-CQWIZrii.js → layout-HBWJ9_zM.js} +1 -1
  149. package/dist/static/assets/{line-BryEd-Ku.js → line-DxrK6d-_.js} +1 -1
  150. package/dist/static/assets/{linear-SXhM57Mz.js → linear-TwnxNDQ0.js} +1 -1
  151. package/dist/static/assets/{lt-LT-XHIRWOB4-BPrhIUrC.js → lt-LT-XHIRWOB4-BxYB7tM6.js} +1 -1
  152. package/dist/static/assets/{lv-LV-5QDEKY6T-CXJse_rs.js → lv-LV-5QDEKY6T-CGURbwyW.js} +1 -1
  153. package/dist/static/assets/{mindmap-definition-fc14e90a-C8giDsiX.js → mindmap-definition-fc14e90a-CWJfWF5a.js} +1 -1
  154. package/dist/static/assets/{mr-IN-CRQNXWMA-Clab-bAO.js → mr-IN-CRQNXWMA-65brZPyQ.js} +1 -1
  155. package/dist/static/assets/{my-MM-5M5IBNSE-Dp08JzEw.js → my-MM-5M5IBNSE-DaCAmQNv.js} +1 -1
  156. package/dist/static/assets/{nb-NO-T6EIAALU-CiaXJA-W.js → nb-NO-T6EIAALU-BiSJhu0W.js} +1 -1
  157. package/dist/static/assets/{nl-NL-IS3SIHDZ-D-9KUTnx.js → nl-NL-IS3SIHDZ-D3rj4Vme.js} +1 -1
  158. package/dist/static/assets/{nn-NO-6E72VCQL-Bg5gsQ4h.js → nn-NO-6E72VCQL-rxxP7Cwf.js} +1 -1
  159. package/dist/static/assets/{oc-FR-POXYY2M6-G4iqllhL.js → oc-FR-POXYY2M6-6emd2NQX.js} +1 -1
  160. package/dist/static/assets/{pa-IN-N4M65BXN-l6Lk41uX.js → pa-IN-N4M65BXN-CXwT_z_m.js} +1 -1
  161. package/dist/static/assets/{pica-CtkejCRD.js → pica-CtyIOuSv.js} +1 -1
  162. package/dist/static/assets/{pieDiagram-8a3498a8-CG6gQ14H.js → pieDiagram-8a3498a8-Ccff4vHz.js} +1 -1
  163. package/dist/static/assets/{pl-PL-T2D74RX3-BZPbB8S3.js → pl-PL-T2D74RX3-DMx_ZmIC.js} +1 -1
  164. package/dist/static/assets/{pt-BR-5N22H2LF-CIC4vRyd.js → pt-BR-5N22H2LF-D9nz7afr.js} +1 -1
  165. package/dist/static/assets/{pt-PT-UZXXM6DQ-rkGTBEI0.js → pt-PT-UZXXM6DQ-DeFH3geX.js} +1 -1
  166. package/dist/static/assets/{quadrantDiagram-120e2f19-BL9eFu4M.js → quadrantDiagram-120e2f19-RF2ZGF1U.js} +1 -1
  167. package/dist/static/assets/{requirementDiagram-deff3bca-crxdUpVK.js → requirementDiagram-deff3bca-CvnD9QLg.js} +1 -1
  168. package/dist/static/assets/{ro-RO-JPDTUUEW-GDhpTKBO.js → ro-RO-JPDTUUEW-Cy22QAjW.js} +1 -1
  169. package/dist/static/assets/{ru-RU-B4JR7IUQ-BzHvMwjC.js → ru-RU-B4JR7IUQ-Cw2rH2nW.js} +1 -1
  170. package/dist/static/assets/{sankeyDiagram-04a897e0-bM05WQw3.js → sankeyDiagram-04a897e0-CWfRjMv0.js} +1 -1
  171. package/dist/static/assets/{sequenceDiagram-704730f1-DjknV0Qp.js → sequenceDiagram-704730f1-pAE8N_Ym.js} +1 -1
  172. package/dist/static/assets/{si-LK-N5RQ5JYF-D3P3TNDH.js → si-LK-N5RQ5JYF-DmXIZ3i0.js} +1 -1
  173. package/dist/static/assets/{sk-SK-C5VTKIMK-CM8yTXlZ.js → sk-SK-C5VTKIMK-CboHDpHd.js} +1 -1
  174. package/dist/static/assets/{sl-SI-NN7IZMDC-CxoGm3aM.js → sl-SI-NN7IZMDC-8XnCHmN4.js} +1 -1
  175. package/dist/static/assets/{stateDiagram-587899a1-CmWqIdF5.js → stateDiagram-587899a1-B4nuLay6.js} +1 -1
  176. package/dist/static/assets/{stateDiagram-v2-d93cdb3a-CgzNTiHW.js → stateDiagram-v2-d93cdb3a-9cMNxr_8.js} +1 -1
  177. package/dist/static/assets/{styles-6aaf32cf-CI4s6NIA.js → styles-6aaf32cf-CynMMkPq.js} +1 -1
  178. package/dist/static/assets/{styles-9a916d00-ZcdN6rtW.js → styles-9a916d00-BTmAnC2j.js} +1 -1
  179. package/dist/static/assets/{styles-c10674c1-ZFkD6ta7.js → styles-c10674c1-DQ_pTuGr.js} +1 -1
  180. package/dist/static/assets/{subset-shared.chunk-B4F4dEPr.js → subset-shared.chunk-DPGuz0R6.js} +1 -1
  181. package/dist/static/assets/{subset-worker.chunk-CmgaOgn3.js → subset-worker.chunk-CMiOYLER.js} +1 -1
  182. package/dist/static/assets/{sv-SE-XGPEYMSR-CnVZlafq.js → sv-SE-XGPEYMSR-ATPKfqXs.js} +1 -1
  183. package/dist/static/assets/{svgDrawCommon-08f97a94-DbN3OiBf.js → svgDrawCommon-08f97a94-qY4BnSWc.js} +1 -1
  184. package/dist/static/assets/{ta-IN-2NMHFXQM-Bl-eCjzL.js → ta-IN-2NMHFXQM-Ct5-Fher.js} +1 -1
  185. package/dist/static/assets/{th-TH-HPSO5L25-CNIGPjSR.js → th-TH-HPSO5L25-5a6bUzcv.js} +1 -1
  186. package/dist/static/assets/{timeline-definition-85554ec2-Cmr82Iq1.js → timeline-definition-85554ec2-Bgexbl3C.js} +1 -1
  187. package/dist/static/assets/{tr-TR-DEFEU3FU-Cx7HbGIA.js → tr-TR-DEFEU3FU-WsK7dnwA.js} +1 -1
  188. package/dist/static/assets/{uk-UA-QMV73CPH-BxcA50Ze.js → uk-UA-QMV73CPH-B_P61mnc.js} +1 -1
  189. package/dist/static/assets/{vi-VN-M7AON7JQ-BvGuRh0c.js → vi-VN-M7AON7JQ-qdiQcney.js} +1 -1
  190. package/dist/static/assets/{xychartDiagram-e933f94c-BcWLDEHu.js → xychartDiagram-e933f94c-vkQjFADD.js} +1 -1
  191. package/dist/static/assets/{zh-CN-LNUGB5OW-SQH8i3l5.js → zh-CN-LNUGB5OW-DQ3BQjPe.js} +1 -1
  192. package/dist/static/assets/{zh-HK-E62DVLB3-COWoLNur.js → zh-HK-E62DVLB3-Ynj07W9J.js} +1 -1
  193. package/dist/static/assets/{zh-TW-RAJ6MFWO-Cm5B69ig.js → zh-TW-RAJ6MFWO-DNkcasuo.js} +1 -1
  194. package/dist/static/index.html +1 -1
  195. package/package.json +5 -2
  196. package/dist/static/assets/channel-DjiT9qJ0.js +0 -1
  197. package/dist/static/assets/clone-nkJpLn4s.js +0 -1
  198. package/dist/static/assets/flowDiagram-v2-96b9c2cf-Dlfh8z7R.js +0 -1
  199. package/dist/static/assets/index-B6CTdFKu.js +0 -311
@@ -0,0 +1,187 @@
1
+ import { describe, it, expect, vi } from 'vitest';
2
+ import { exportImage } from '../export';
3
+ const SAMPLE_DATA_URL = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==';
4
+ function createMockClient(sendFn) {
5
+ return {
6
+ send: sendFn ?? vi.fn(() => Promise.resolve({ success: true, dataUrl: SAMPLE_DATA_URL })),
7
+ close: vi.fn(),
8
+ };
9
+ }
10
+ function createMockDeps(overrides) {
11
+ return {
12
+ connectToCanvas: vi.fn(() => Promise.resolve(createMockClient())),
13
+ generateId: vi.fn(() => 'test-id'),
14
+ writeFile: vi.fn(),
15
+ now: vi.fn(() => 1234567890),
16
+ log: vi.fn(),
17
+ error: vi.fn(),
18
+ exit: vi.fn(),
19
+ ...overrides,
20
+ };
21
+ }
22
+ describe('exportImage', () => {
23
+ // ==================== Input Validation Tests ====================
24
+ describe('input validation', () => {
25
+ it('should error and exit when scale is not 1, 2, or 3', async () => {
26
+ const deps = createMockDeps();
27
+ await exportImage({ scale: 4 }, deps);
28
+ expect(deps.error).toHaveBeenCalledWith('Scale must be 1, 2, or 3');
29
+ expect(deps.exit).toHaveBeenCalledWith(1);
30
+ expect(deps.connectToCanvas).not.toHaveBeenCalled();
31
+ });
32
+ it('should accept scale 1', async () => {
33
+ const mockSend = vi.fn(() => Promise.resolve({ success: true, dataUrl: SAMPLE_DATA_URL }));
34
+ const mockClient = createMockClient(mockSend);
35
+ const deps = createMockDeps({
36
+ connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
37
+ });
38
+ await exportImage({ scale: 1 }, deps);
39
+ expect(deps.error).not.toHaveBeenCalled();
40
+ expect(mockSend).toHaveBeenCalled();
41
+ });
42
+ it('should accept scale 2', async () => {
43
+ const mockSend = vi.fn(() => Promise.resolve({ success: true, dataUrl: SAMPLE_DATA_URL }));
44
+ const mockClient = createMockClient(mockSend);
45
+ const deps = createMockDeps({
46
+ connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
47
+ });
48
+ await exportImage({ scale: 2 }, deps);
49
+ expect(deps.error).not.toHaveBeenCalled();
50
+ expect(mockSend).toHaveBeenCalled();
51
+ });
52
+ it('should accept scale 3', async () => {
53
+ const mockSend = vi.fn(() => Promise.resolve({ success: true, dataUrl: SAMPLE_DATA_URL }));
54
+ const mockClient = createMockClient(mockSend);
55
+ const deps = createMockDeps({
56
+ connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
57
+ });
58
+ await exportImage({ scale: 3 }, deps);
59
+ expect(deps.error).not.toHaveBeenCalled();
60
+ expect(mockSend).toHaveBeenCalled();
61
+ });
62
+ });
63
+ // ==================== Parameter/Logic Tests ====================
64
+ describe('parameter handling', () => {
65
+ it('should send correct params with defaults', async () => {
66
+ const mockSend = vi.fn(() => Promise.resolve({ success: true, dataUrl: SAMPLE_DATA_URL }));
67
+ const mockClient = createMockClient(mockSend);
68
+ const deps = createMockDeps({
69
+ connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
70
+ });
71
+ await exportImage({}, deps);
72
+ expect(mockSend).toHaveBeenCalledWith(expect.objectContaining({
73
+ type: 'exportImage',
74
+ id: 'test-id',
75
+ params: {
76
+ background: true,
77
+ dark: false,
78
+ embedScene: false,
79
+ scale: 1,
80
+ },
81
+ }));
82
+ });
83
+ it('should send correct params with all options', async () => {
84
+ const mockSend = vi.fn(() => Promise.resolve({ success: true, dataUrl: SAMPLE_DATA_URL }));
85
+ const mockClient = createMockClient(mockSend);
86
+ const deps = createMockDeps({
87
+ connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
88
+ });
89
+ await exportImage({
90
+ background: false,
91
+ dark: true,
92
+ embedScene: true,
93
+ scale: 2,
94
+ }, deps);
95
+ expect(mockSend).toHaveBeenCalledWith(expect.objectContaining({
96
+ params: {
97
+ background: false,
98
+ dark: true,
99
+ embedScene: true,
100
+ scale: 2,
101
+ },
102
+ }));
103
+ });
104
+ it('should correctly parse dataUrl to buffer', async () => {
105
+ const mockWriteFile = vi.fn();
106
+ const mockSend = vi.fn(() => Promise.resolve({ success: true, dataUrl: SAMPLE_DATA_URL }));
107
+ const mockClient = createMockClient(mockSend);
108
+ const deps = createMockDeps({
109
+ connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
110
+ writeFile: mockWriteFile,
111
+ });
112
+ await exportImage({ output: 'test.png' }, deps);
113
+ const expectedBuffer = Buffer.from('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==', 'base64');
114
+ expect(mockWriteFile).toHaveBeenCalledWith('test.png', expectedBuffer);
115
+ });
116
+ it('should generate default filename when output not specified', async () => {
117
+ const mockWriteFile = vi.fn();
118
+ const mockSend = vi.fn(() => Promise.resolve({ success: true, dataUrl: SAMPLE_DATA_URL }));
119
+ const mockClient = createMockClient(mockSend);
120
+ const deps = createMockDeps({
121
+ connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
122
+ writeFile: mockWriteFile,
123
+ now: vi.fn(() => 1234567890),
124
+ });
125
+ await exportImage({}, deps);
126
+ expect(mockWriteFile).toHaveBeenCalledWith('canvas-1234567890.png', expect.any(Buffer));
127
+ expect(deps.log).toHaveBeenCalledWith('Exported to canvas-1234567890.png');
128
+ });
129
+ it('should use provided output path', async () => {
130
+ const mockWriteFile = vi.fn();
131
+ const mockSend = vi.fn(() => Promise.resolve({ success: true, dataUrl: SAMPLE_DATA_URL }));
132
+ const mockClient = createMockClient(mockSend);
133
+ const deps = createMockDeps({
134
+ connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
135
+ writeFile: mockWriteFile,
136
+ });
137
+ await exportImage({ output: 'my-diagram.png' }, deps);
138
+ expect(mockWriteFile).toHaveBeenCalledWith('my-diagram.png', expect.any(Buffer));
139
+ expect(deps.log).toHaveBeenCalledWith('Exported to my-diagram.png');
140
+ });
141
+ });
142
+ // ==================== Response Handling Tests ====================
143
+ describe('response handling', () => {
144
+ it('should log success message on success', async () => {
145
+ const mockSend = vi.fn(() => Promise.resolve({ success: true, dataUrl: SAMPLE_DATA_URL }));
146
+ const mockClient = createMockClient(mockSend);
147
+ const deps = createMockDeps({
148
+ connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
149
+ });
150
+ await exportImage({ output: 'output.png' }, deps);
151
+ expect(deps.log).toHaveBeenCalledWith('Exported to output.png');
152
+ });
153
+ it('should error and exit on failure response', async () => {
154
+ const mockSend = vi.fn(() => Promise.resolve({
155
+ success: false,
156
+ error: 'Export failed',
157
+ }));
158
+ const mockClient = createMockClient(mockSend);
159
+ const deps = createMockDeps({
160
+ connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
161
+ });
162
+ await exportImage({}, deps);
163
+ expect(deps.error).toHaveBeenCalledWith('Failed: Export failed');
164
+ expect(deps.exit).toHaveBeenCalledWith(1);
165
+ });
166
+ it('should close client after success', async () => {
167
+ const mockClose = vi.fn();
168
+ const mockSend = vi.fn(() => Promise.resolve({ success: true, dataUrl: SAMPLE_DATA_URL }));
169
+ const mockClient = { send: mockSend, close: mockClose };
170
+ const deps = createMockDeps({
171
+ connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
172
+ });
173
+ await exportImage({}, deps);
174
+ expect(mockClose).toHaveBeenCalled();
175
+ });
176
+ it('should close client after failure', async () => {
177
+ const mockClose = vi.fn();
178
+ const mockSend = vi.fn(() => Promise.resolve({ success: false, error: 'error' }));
179
+ const mockClient = { send: mockSend, close: mockClose };
180
+ const deps = createMockDeps({
181
+ connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
182
+ });
183
+ await exportImage({}, deps);
184
+ expect(mockClose).toHaveBeenCalled();
185
+ });
186
+ });
187
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,93 @@
1
+ import { describe, it, expect, vi } from 'vitest';
2
+ import { groupElements } from '../group-elements';
3
+ function createMockClient(sendFn) {
4
+ return {
5
+ send: sendFn ?? vi.fn(() => Promise.resolve({ success: true, groupId: 'group-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('groupElements', () => {
20
+ // ==================== Parameter Assembly Tests ====================
21
+ describe('parameter assembly', () => {
22
+ it('should send correct params with elementIds', async () => {
23
+ const mockSend = vi.fn(() => Promise.resolve({ success: true, groupId: 'group-1' }));
24
+ const mockClient = createMockClient(mockSend);
25
+ const deps = createMockDeps({
26
+ connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
27
+ });
28
+ await groupElements({ elementIds: ['el-1', 'el-2', 'el-3'] }, deps);
29
+ expect(mockSend).toHaveBeenCalledWith(expect.objectContaining({
30
+ type: 'groupElements',
31
+ id: 'test-id',
32
+ params: {
33
+ elementIds: ['el-1', 'el-2', 'el-3'],
34
+ },
35
+ }));
36
+ });
37
+ it('should handle single element', async () => {
38
+ const mockSend = vi.fn(() => Promise.resolve({ success: true, groupId: 'group-2' }));
39
+ const mockClient = createMockClient(mockSend);
40
+ const deps = createMockDeps({
41
+ connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
42
+ });
43
+ await groupElements({ elementIds: ['el-single'] }, deps);
44
+ const callParams = mockSend.mock.calls[0][0].params;
45
+ expect(callParams.elementIds).toEqual(['el-single']);
46
+ });
47
+ });
48
+ // ==================== Response Handling Tests ====================
49
+ describe('response handling', () => {
50
+ it('should log success message with group ID', async () => {
51
+ const mockSend = vi.fn(() => Promise.resolve({ success: true, groupId: 'grp-abc123' }));
52
+ const mockClient = createMockClient(mockSend);
53
+ const deps = createMockDeps({
54
+ connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
55
+ });
56
+ await groupElements({ elementIds: ['el-1', 'el-2'] }, deps);
57
+ expect(deps.log).toHaveBeenCalledWith('Group created (id: grp-abc123)');
58
+ });
59
+ it('should error and exit on failure response', async () => {
60
+ const mockSend = vi.fn(() => Promise.resolve({
61
+ success: false,
62
+ error: 'Cannot group less than 2 elements',
63
+ }));
64
+ const mockClient = createMockClient(mockSend);
65
+ const deps = createMockDeps({
66
+ connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
67
+ });
68
+ await groupElements({ elementIds: ['el-1'] }, deps);
69
+ expect(deps.error).toHaveBeenCalledWith('Failed: Cannot group less than 2 elements');
70
+ expect(deps.exit).toHaveBeenCalledWith(1);
71
+ });
72
+ it('should close client after success', async () => {
73
+ const mockClose = vi.fn();
74
+ const mockSend = vi.fn(() => Promise.resolve({ success: true, groupId: 'group-1' }));
75
+ const mockClient = { send: mockSend, close: mockClose };
76
+ const deps = createMockDeps({
77
+ connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
78
+ });
79
+ await groupElements({ elementIds: ['el-1', 'el-2'] }, deps);
80
+ expect(mockClose).toHaveBeenCalled();
81
+ });
82
+ it('should close client after failure', async () => {
83
+ const mockClose = vi.fn();
84
+ const mockSend = vi.fn(() => Promise.resolve({ success: false, error: 'error' }));
85
+ const mockClient = { send: mockSend, close: mockClose };
86
+ const deps = createMockDeps({
87
+ connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
88
+ });
89
+ await groupElements({ elementIds: ['el-1', 'el-2'] }, deps);
90
+ expect(mockClose).toHaveBeenCalled();
91
+ });
92
+ });
93
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,134 @@
1
+ import { describe, it, expect, vi } from 'vitest';
2
+ import { list, formatCanvasList } from '../list';
3
+ function createMockClient(sendFn) {
4
+ return {
5
+ send: sendFn ?? vi.fn(() => Promise.resolve({ success: true, canvases: [] })),
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('list', () => {
20
+ // ==================== Format Function Tests ====================
21
+ describe('formatCanvasList', () => {
22
+ it('should output header', () => {
23
+ const lines = formatCanvasList({ canvases: [] });
24
+ expect(lines[0]).toBe('Canvases: ([U]=User [A]=Agent)');
25
+ });
26
+ it('should mark canvas with [U] for user active', () => {
27
+ const lines = formatCanvasList({
28
+ activeCanvasId: 'canvas-1',
29
+ canvases: [
30
+ { id: 'canvas-1', name: 'Test Canvas', createdAt: 1000, updatedAt: 2000 },
31
+ ],
32
+ });
33
+ expect(lines[1]).toContain('[U] ');
34
+ expect(lines[1]).toContain('Test Canvas');
35
+ });
36
+ it('should mark canvas with [A] for agent active', () => {
37
+ const lines = formatCanvasList({
38
+ agentActiveCanvasId: 'canvas-1',
39
+ canvases: [
40
+ { id: 'canvas-1', name: 'Test Canvas', createdAt: 1000, updatedAt: 2000 },
41
+ ],
42
+ });
43
+ expect(lines[1]).toContain('[A] ');
44
+ expect(lines[1]).toContain('Test Canvas');
45
+ });
46
+ it('should mark canvas with [UA] for both user and agent active', () => {
47
+ const lines = formatCanvasList({
48
+ activeCanvasId: 'canvas-1',
49
+ agentActiveCanvasId: 'canvas-1',
50
+ canvases: [
51
+ { id: 'canvas-1', name: 'Test Canvas', createdAt: 1000, updatedAt: 2000 },
52
+ ],
53
+ });
54
+ expect(lines[1]).toContain('[UA]');
55
+ expect(lines[1]).toContain('Test Canvas');
56
+ });
57
+ it('should not mark canvas when not active', () => {
58
+ const lines = formatCanvasList({
59
+ activeCanvasId: 'other-id',
60
+ agentActiveCanvasId: 'another-id',
61
+ canvases: [
62
+ { id: 'canvas-1', name: 'Test Canvas', createdAt: 1000, updatedAt: 2000 },
63
+ ],
64
+ });
65
+ expect(lines[1]).toMatch(/^ /);
66
+ expect(lines[1]).toContain('Test Canvas');
67
+ });
68
+ it('should include canvas name and formatted date', () => {
69
+ const timestamp = new Date('2024-01-15T10:30:00Z').getTime();
70
+ const lines = formatCanvasList({
71
+ canvases: [
72
+ { id: 'canvas-1', name: 'My Canvas', createdAt: 1000, updatedAt: timestamp },
73
+ ],
74
+ });
75
+ expect(lines[1]).toContain('My Canvas');
76
+ expect(lines[1]).toContain('(updated:');
77
+ });
78
+ });
79
+ // ==================== Response Handling Tests ====================
80
+ describe('response handling', () => {
81
+ it('should log each formatted line on success', async () => {
82
+ const mockSend = vi.fn(() => Promise.resolve({
83
+ success: true,
84
+ activeCanvasId: 'canvas-1',
85
+ canvases: [
86
+ { id: 'canvas-1', name: 'Canvas 1', createdAt: 1000, updatedAt: 2000 },
87
+ { id: 'canvas-2', name: 'Canvas 2', createdAt: 1000, updatedAt: 3000 },
88
+ ],
89
+ }));
90
+ const mockClient = createMockClient(mockSend);
91
+ const deps = createMockDeps({
92
+ connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
93
+ });
94
+ await list(deps);
95
+ // First call is header
96
+ expect(deps.log).toHaveBeenCalledWith('Canvases: ([U]=User [A]=Agent)');
97
+ // Should have called log 3 times (header + 2 canvases)
98
+ expect(deps.log).toHaveBeenCalledTimes(3);
99
+ });
100
+ it('should error and exit on failure response', async () => {
101
+ const mockSend = vi.fn(() => Promise.resolve({
102
+ success: false,
103
+ error: 'Connection failed',
104
+ }));
105
+ const mockClient = createMockClient(mockSend);
106
+ const deps = createMockDeps({
107
+ connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
108
+ });
109
+ await list(deps);
110
+ expect(deps.error).toHaveBeenCalledWith('Failed: Connection failed');
111
+ expect(deps.exit).toHaveBeenCalledWith(1);
112
+ });
113
+ it('should close client after success', async () => {
114
+ const mockClose = vi.fn();
115
+ const mockSend = vi.fn(() => Promise.resolve({ success: true, canvases: [] }));
116
+ const mockClient = { send: mockSend, close: mockClose };
117
+ const deps = createMockDeps({
118
+ connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
119
+ });
120
+ await list(deps);
121
+ expect(mockClose).toHaveBeenCalled();
122
+ });
123
+ it('should close client after failure', async () => {
124
+ const mockClose = vi.fn();
125
+ const mockSend = vi.fn(() => Promise.resolve({ success: false, error: 'error' }));
126
+ const mockClient = { send: mockSend, close: mockClose };
127
+ const deps = createMockDeps({
128
+ connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
129
+ });
130
+ await list(deps);
131
+ expect(mockClose).toHaveBeenCalled();
132
+ });
133
+ });
134
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,158 @@
1
+ import { describe, it, expect, vi } from 'vitest';
2
+ import { load } from '../load';
3
+ function createMockClient(sendFn) {
4
+ return {
5
+ send: sendFn ?? vi.fn(() => Promise.resolve({ success: true, elementCount: 5 })),
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
+ readFile: vi.fn(() => JSON.stringify({ elements: [{ id: 'el-1' }] })),
14
+ existsSync: vi.fn(() => true),
15
+ resolvePath: vi.fn((p) => `/absolute/path/${p}`),
16
+ log: vi.fn(),
17
+ error: vi.fn(),
18
+ exit: vi.fn(),
19
+ ...overrides,
20
+ };
21
+ }
22
+ describe('load', () => {
23
+ // ==================== Input Validation Tests ====================
24
+ describe('input validation', () => {
25
+ it('should error and exit when filepath is not provided', async () => {
26
+ const deps = createMockDeps();
27
+ await load(undefined, deps);
28
+ expect(deps.error).toHaveBeenCalledWith('Usage: agent-canvas load <filepath>');
29
+ expect(deps.exit).toHaveBeenCalledWith(1);
30
+ expect(deps.connectToCanvas).not.toHaveBeenCalled();
31
+ });
32
+ it('should error and exit when file does not exist', async () => {
33
+ const deps = createMockDeps({
34
+ existsSync: vi.fn(() => false),
35
+ resolvePath: vi.fn(() => '/path/to/missing.excalidraw'),
36
+ });
37
+ await load('missing.excalidraw', deps);
38
+ expect(deps.error).toHaveBeenCalledWith('File not found: /path/to/missing.excalidraw');
39
+ expect(deps.exit).toHaveBeenCalledWith(1);
40
+ expect(deps.connectToCanvas).not.toHaveBeenCalled();
41
+ });
42
+ it('should error and exit when file cannot be read', async () => {
43
+ const deps = createMockDeps({
44
+ readFile: vi.fn(() => { throw new Error('Permission denied'); }),
45
+ });
46
+ await load('test.excalidraw', deps);
47
+ expect(deps.error).toHaveBeenCalledWith('Failed to read file: Permission denied');
48
+ expect(deps.exit).toHaveBeenCalledWith(1);
49
+ expect(deps.connectToCanvas).not.toHaveBeenCalled();
50
+ });
51
+ it('should error and exit when file contains invalid JSON', async () => {
52
+ const deps = createMockDeps({
53
+ readFile: vi.fn(() => '{ invalid json }'),
54
+ });
55
+ await load('test.excalidraw', deps);
56
+ expect(deps.error).toHaveBeenCalledWith(expect.stringMatching(/^Failed to parse file:/));
57
+ expect(deps.exit).toHaveBeenCalledWith(1);
58
+ expect(deps.connectToCanvas).not.toHaveBeenCalled();
59
+ });
60
+ });
61
+ // ==================== Parameter Assembly Tests ====================
62
+ describe('parameter assembly', () => {
63
+ it('should resolve filepath to absolute path', async () => {
64
+ const mockResolvePath = vi.fn(() => '/absolute/path/test.excalidraw');
65
+ const deps = createMockDeps({ resolvePath: mockResolvePath });
66
+ await load('test.excalidraw', deps);
67
+ expect(mockResolvePath).toHaveBeenCalledWith('test.excalidraw');
68
+ expect(deps.existsSync).toHaveBeenCalledWith('/absolute/path/test.excalidraw');
69
+ expect(deps.readFile).toHaveBeenCalledWith('/absolute/path/test.excalidraw', 'utf-8');
70
+ });
71
+ it('should send loadScene message with parsed elements', async () => {
72
+ const mockSend = vi.fn(() => Promise.resolve({ success: true, elementCount: 2 }));
73
+ const mockClient = createMockClient(mockSend);
74
+ const sceneData = {
75
+ elements: [{ id: 'el-1' }, { id: 'el-2' }],
76
+ appState: { viewBackgroundColor: '#ffffff' },
77
+ files: { 'file-1': { mimeType: 'image/png' } },
78
+ };
79
+ const deps = createMockDeps({
80
+ connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
81
+ readFile: vi.fn(() => JSON.stringify(sceneData)),
82
+ });
83
+ await load('scene.excalidraw', deps);
84
+ expect(mockSend).toHaveBeenCalledWith({
85
+ type: 'loadScene',
86
+ id: 'test-id',
87
+ params: {
88
+ elements: sceneData.elements,
89
+ appState: sceneData.appState,
90
+ files: sceneData.files,
91
+ },
92
+ });
93
+ });
94
+ it('should default to empty array when elements is missing', async () => {
95
+ const mockSend = vi.fn(() => Promise.resolve({ success: true, elementCount: 0 }));
96
+ const mockClient = createMockClient(mockSend);
97
+ const deps = createMockDeps({
98
+ connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
99
+ readFile: vi.fn(() => JSON.stringify({ appState: {} })),
100
+ });
101
+ await load('empty.excalidraw', deps);
102
+ expect(mockSend).toHaveBeenCalledWith({
103
+ type: 'loadScene',
104
+ id: 'test-id',
105
+ params: {
106
+ elements: [],
107
+ appState: {},
108
+ files: undefined,
109
+ },
110
+ });
111
+ });
112
+ });
113
+ // ==================== Response Handling Tests ====================
114
+ describe('response handling', () => {
115
+ it('should log success message with element count', async () => {
116
+ const mockSend = vi.fn(() => Promise.resolve({ success: true, elementCount: 10 }));
117
+ const mockClient = createMockClient(mockSend);
118
+ const deps = createMockDeps({
119
+ connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
120
+ });
121
+ await load('scene.excalidraw', deps);
122
+ expect(deps.log).toHaveBeenCalledWith('Loaded 10 elements from scene.excalidraw');
123
+ });
124
+ it('should error and exit on failure response', async () => {
125
+ const mockSend = vi.fn(() => Promise.resolve({
126
+ success: false,
127
+ error: 'Invalid scene format',
128
+ }));
129
+ const mockClient = createMockClient(mockSend);
130
+ const deps = createMockDeps({
131
+ connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
132
+ });
133
+ await load('bad.excalidraw', deps);
134
+ expect(deps.error).toHaveBeenCalledWith('Failed to load file: Invalid scene format');
135
+ expect(deps.exit).toHaveBeenCalledWith(1);
136
+ });
137
+ it('should close client after success', async () => {
138
+ const mockClose = vi.fn();
139
+ const mockSend = vi.fn(() => Promise.resolve({ success: true, elementCount: 5 }));
140
+ const mockClient = { send: mockSend, close: mockClose };
141
+ const deps = createMockDeps({
142
+ connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
143
+ });
144
+ await load('scene.excalidraw', deps);
145
+ expect(mockClose).toHaveBeenCalled();
146
+ });
147
+ it('should close client after failure', async () => {
148
+ const mockClose = vi.fn();
149
+ const mockSend = vi.fn(() => Promise.resolve({ success: false, error: 'error' }));
150
+ const mockClient = { send: mockSend, close: mockClose };
151
+ const deps = createMockDeps({
152
+ connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
153
+ });
154
+ await load('scene.excalidraw', deps);
155
+ expect(mockClose).toHaveBeenCalled();
156
+ });
157
+ });
158
+ });
@@ -0,0 +1 @@
1
+ export {};