@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.
- package/dist/commands/__tests__/add-arrow.test.d.ts +1 -0
- package/dist/commands/__tests__/add-arrow.test.js +186 -0
- package/dist/commands/__tests__/add-image.test.d.ts +1 -0
- package/dist/commands/__tests__/add-image.test.js +170 -0
- package/dist/commands/__tests__/add-line.test.d.ts +1 -0
- package/dist/commands/__tests__/add-line.test.js +138 -0
- package/dist/commands/__tests__/add-polygon.test.d.ts +1 -0
- package/dist/commands/__tests__/add-polygon.test.js +147 -0
- package/dist/commands/__tests__/add-shape.test.d.ts +1 -0
- package/dist/commands/__tests__/add-shape.test.js +193 -0
- package/dist/commands/__tests__/add-text.test.d.ts +1 -0
- package/dist/commands/__tests__/add-text.test.js +144 -0
- package/dist/commands/__tests__/clear.test.d.ts +1 -0
- package/dist/commands/__tests__/clear.test.js +65 -0
- package/dist/commands/__tests__/delete-elements.test.d.ts +1 -0
- package/dist/commands/__tests__/delete-elements.test.js +103 -0
- package/dist/commands/__tests__/export.test.d.ts +1 -0
- package/dist/commands/__tests__/export.test.js +187 -0
- package/dist/commands/__tests__/group-elements.test.d.ts +1 -0
- package/dist/commands/__tests__/group-elements.test.js +93 -0
- package/dist/commands/__tests__/list.test.d.ts +1 -0
- package/dist/commands/__tests__/list.test.js +134 -0
- package/dist/commands/__tests__/load.test.d.ts +1 -0
- package/dist/commands/__tests__/load.test.js +158 -0
- package/dist/commands/__tests__/move-elements.test.d.ts +1 -0
- package/dist/commands/__tests__/move-elements.test.js +117 -0
- package/dist/commands/__tests__/new-canvas.test.d.ts +1 -0
- package/dist/commands/__tests__/new-canvas.test.js +113 -0
- package/dist/commands/__tests__/read.test.d.ts +1 -0
- package/dist/commands/__tests__/read.test.js +247 -0
- package/dist/commands/__tests__/rename-canvas.test.d.ts +1 -0
- package/dist/commands/__tests__/rename-canvas.test.js +86 -0
- package/dist/commands/__tests__/resize-elements.test.d.ts +1 -0
- package/dist/commands/__tests__/resize-elements.test.js +150 -0
- package/dist/commands/__tests__/rotate-elements.test.d.ts +1 -0
- package/dist/commands/__tests__/rotate-elements.test.js +114 -0
- package/dist/commands/__tests__/save.test.d.ts +1 -0
- package/dist/commands/__tests__/save.test.js +105 -0
- package/dist/commands/__tests__/ungroup-element.test.d.ts +1 -0
- package/dist/commands/__tests__/ungroup-element.test.js +93 -0
- package/dist/commands/__tests__/use-canvas.test.d.ts +1 -0
- package/dist/commands/__tests__/use-canvas.test.js +86 -0
- package/dist/commands/add-arrow.d.ts +40 -0
- package/dist/commands/add-arrow.js +52 -0
- package/dist/commands/add-image.d.ts +26 -0
- package/dist/commands/add-image.js +66 -0
- package/dist/commands/add-line.d.ts +27 -0
- package/dist/commands/add-line.js +35 -0
- package/dist/commands/add-polygon.d.ts +26 -0
- package/dist/commands/add-polygon.js +44 -0
- package/dist/commands/add-shape.d.ts +32 -0
- package/dist/commands/add-shape.js +41 -0
- package/dist/commands/add-text.d.ts +28 -0
- package/dist/commands/add-text.js +35 -0
- package/dist/commands/clear.d.ts +17 -0
- package/dist/commands/clear.js +23 -0
- package/dist/commands/delete-elements.d.ts +20 -0
- package/dist/commands/delete-elements.js +26 -0
- package/dist/commands/export.d.ts +26 -0
- package/dist/commands/export.js +45 -0
- package/dist/commands/group-elements.d.ts +20 -0
- package/dist/commands/group-elements.js +28 -0
- package/dist/commands/list.d.ts +23 -0
- package/dist/commands/list.js +50 -0
- package/dist/commands/load.d.ts +20 -0
- package/dist/commands/load.js +67 -0
- package/dist/commands/move-elements.d.ts +22 -0
- package/dist/commands/move-elements.js +26 -0
- package/dist/commands/new-canvas.d.ts +21 -0
- package/dist/commands/new-canvas.js +29 -0
- package/dist/commands/read.d.ts +23 -0
- package/dist/commands/read.js +49 -0
- package/dist/commands/rename-canvas.d.ts +20 -0
- package/dist/commands/rename-canvas.js +27 -0
- package/dist/commands/resize-elements.d.ts +24 -0
- package/dist/commands/resize-elements.js +41 -0
- package/dist/commands/rotate-elements.d.ts +21 -0
- package/dist/commands/rotate-elements.js +26 -0
- package/dist/commands/save.d.ts +18 -0
- package/dist/commands/save.js +27 -0
- package/dist/commands/start.d.ts +0 -1
- package/dist/commands/start.js +0 -41
- package/dist/commands/ungroup-element.d.ts +20 -0
- package/dist/commands/ungroup-element.js +28 -0
- package/dist/commands/use-canvas.d.ts +20 -0
- package/dist/commands/use-canvas.js +27 -0
- package/dist/index.js +124 -518
- package/dist/lib/__tests__/image-utils.test.d.ts +1 -0
- package/dist/lib/__tests__/image-utils.test.js +123 -0
- package/dist/lib/__tests__/toon-converter.test.d.ts +1 -0
- package/dist/lib/__tests__/toon-converter.test.js +586 -0
- package/dist/lib/__tests__/ws-client.test.d.ts +1 -0
- package/dist/lib/__tests__/ws-client.test.js +22 -0
- package/dist/lib/image-utils.d.ts +3 -0
- package/dist/lib/image-utils.js +21 -0
- package/dist/lib/protocol.d.ts +24 -0
- package/dist/lib/toon-converter.d.ts +104 -0
- package/dist/lib/toon-converter.js +221 -0
- package/dist/static/assets/{ar-SA-G6X2FPQ2-DrFZc17I.js → ar-SA-G6X2FPQ2-DBOnFzSe.js} +1 -1
- package/dist/static/assets/{arc-BE4RRWho.js → arc-bbUtBUEI.js} +1 -1
- package/dist/static/assets/{az-AZ-76LH7QW2-DgHo0c8x.js → az-AZ-76LH7QW2-Cc10aZ9u.js} +1 -1
- package/dist/static/assets/{bg-BG-XCXSNQG7-D6Qfq7sN.js → bg-BG-XCXSNQG7-Ccf7m1dz.js} +1 -1
- package/dist/static/assets/{blockDiagram-38ab4fdb-j4QCKNBJ.js → blockDiagram-38ab4fdb-fpHXuuqC.js} +1 -1
- package/dist/static/assets/{bn-BD-2XOGV67Q-DtD_GeTA.js → bn-BD-2XOGV67Q-DUsn1OkS.js} +1 -1
- package/dist/static/assets/{c4Diagram-3d4e48cf-BmQ9mE4L.js → c4Diagram-3d4e48cf-R8YUsP4D.js} +1 -1
- package/dist/static/assets/{ca-ES-6MX7JW3Y-pqblEVH2.js → ca-ES-6MX7JW3Y-hu4EsJg6.js} +1 -1
- package/dist/static/assets/channel-DOejQ6Zr.js +1 -0
- package/dist/static/assets/{classDiagram-70f12bd4-CUF5vm_X.js → classDiagram-70f12bd4-Bd-nCoOe.js} +1 -1
- package/dist/static/assets/{classDiagram-v2-f2320105-Cpj_A_lB.js → classDiagram-v2-f2320105-BSqlF2Ya.js} +1 -1
- package/dist/static/assets/clone-BACvnIVb.js +1 -0
- package/dist/static/assets/{createText-2e5e7dd3-pnM7Sebc.js → createText-2e5e7dd3-DDxcRLmM.js} +1 -1
- package/dist/static/assets/{cs-CZ-2BRQDIVT-CybzkHZt.js → cs-CZ-2BRQDIVT-CvZtKTE7.js} +1 -1
- package/dist/static/assets/{da-DK-5WZEPLOC-pqELhXiQ.js → da-DK-5WZEPLOC-Bo6-ltfA.js} +1 -1
- package/dist/static/assets/{de-DE-XR44H4JA-ZL76WiIL.js → de-DE-XR44H4JA-Rki2qM_x.js} +1 -1
- package/dist/static/assets/{edges-e0da2a9e-B9extNmC.js → edges-e0da2a9e-DWJxCouB.js} +1 -1
- package/dist/static/assets/{el-GR-BZB4AONW-rKEdKItN.js → el-GR-BZB4AONW-BRy2rrt9.js} +1 -1
- package/dist/static/assets/{erDiagram-9861fffd-Bf-1lr9-.js → erDiagram-9861fffd-DXldiM4J.js} +1 -1
- package/dist/static/assets/{es-ES-U4NZUMDT-BB6riLIk.js → es-ES-U4NZUMDT-hCKbxwHs.js} +1 -1
- package/dist/static/assets/{eu-ES-A7QVB2H4-ChqJNrpA.js → eu-ES-A7QVB2H4-CmZGwoa5.js} +1 -1
- package/dist/static/assets/{fa-IR-HGAKTJCU--KEd62Xu.js → fa-IR-HGAKTJCU-C6DRPcaF.js} +1 -1
- package/dist/static/assets/{fi-FI-Z5N7JZ37-CdB0adCJ.js → fi-FI-Z5N7JZ37-DBaspnIB.js} +1 -1
- package/dist/static/assets/{flowDb-956e92f1-Dbca38tY.js → flowDb-956e92f1-C48Cmgvd.js} +1 -1
- package/dist/static/assets/{flowDiagram-66a62f08-DpQc0ZQB.js → flowDiagram-66a62f08-DV7f8TtG.js} +1 -1
- package/dist/static/assets/flowDiagram-v2-96b9c2cf-MnAxlKb6.js +1 -0
- package/dist/static/assets/{flowchart-elk-definition-4a651766-CAxl2EAj.js → flowchart-elk-definition-4a651766-C2muEpzy.js} +1 -1
- package/dist/static/assets/{fr-FR-RHASNOE6-LEJbMD3b.js → fr-FR-RHASNOE6-D1dEEEfS.js} +1 -1
- package/dist/static/assets/{ganttDiagram-c361ad54-BsKueDb1.js → ganttDiagram-c361ad54-CrooqCzc.js} +1 -1
- package/dist/static/assets/{gitGraphDiagram-72cf32ee-BySoTKcT.js → gitGraphDiagram-72cf32ee-x7BVIo_3.js} +1 -1
- package/dist/static/assets/{gl-ES-HMX3MZ6V-Bi3P3M7W.js → gl-ES-HMX3MZ6V-Czkw2ahx.js} +1 -1
- package/dist/static/assets/{graph-B_0qOa-k.js → graph-Bv0C_szp.js} +1 -1
- package/dist/static/assets/{he-IL-6SHJWFNN-DE7_aRwg.js → he-IL-6SHJWFNN-BLwbN3CV.js} +1 -1
- package/dist/static/assets/{hi-IN-IWLTKZ5I-CjARmJ8i.js → hi-IN-IWLTKZ5I-BJh3HrXc.js} +1 -1
- package/dist/static/assets/{hu-HU-A5ZG7DT2-d79urL5L.js → hu-HU-A5ZG7DT2-D00s-8EN.js} +1 -1
- package/dist/static/assets/{id-ID-SAP4L64H-bxo8Q0Jv.js → id-ID-SAP4L64H-BmyuzwXV.js} +1 -1
- package/dist/static/assets/{index-3862675e-BLm8h60G.js → index-3862675e-mZlepZqF.js} +1 -1
- package/dist/static/assets/{index-BkW4NM9R.js → index-Bnmyv9TE.js} +4 -4
- package/dist/static/assets/index-jjzEa4oB.js +316 -0
- package/dist/static/assets/{infoDiagram-f8f76790-CZ4J5sjk.js → infoDiagram-f8f76790-w7FUTsVV.js} +1 -1
- package/dist/static/assets/{it-IT-JPQ66NNP-D41R3uEK.js → it-IT-JPQ66NNP-CeVq0l8v.js} +1 -1
- package/dist/static/assets/{ja-JP-DBVTYXUO-zK8NUJnS.js → ja-JP-DBVTYXUO-BUNKxxGA.js} +1 -1
- package/dist/static/assets/{journeyDiagram-49397b02-DtFcZaIk.js → journeyDiagram-49397b02-DYjDqkQG.js} +1 -1
- package/dist/static/assets/{kaa-6HZHGXH3-CbGIc6V6.js → kaa-6HZHGXH3-BIKwULqb.js} +1 -1
- package/dist/static/assets/{kab-KAB-ZGHBKWFO-BweHPuX1.js → kab-KAB-ZGHBKWFO-BDpRo7IX.js} +1 -1
- package/dist/static/assets/{kk-KZ-P5N5QNE5-DSokMm7h.js → kk-KZ-P5N5QNE5-bI2LN3W0.js} +1 -1
- package/dist/static/assets/{km-KH-HSX4SM5Z-LYiEs3ge.js → km-KH-HSX4SM5Z-gtwrLJn5.js} +1 -1
- package/dist/static/assets/{ko-KR-MTYHY66A-BzgMEtcU.js → ko-KR-MTYHY66A-BVcwVELq.js} +1 -1
- package/dist/static/assets/{ku-TR-6OUDTVRD-D1FtjbSs.js → ku-TR-6OUDTVRD-COvDJH7d.js} +1 -1
- package/dist/static/assets/{layout-CQWIZrii.js → layout-HBWJ9_zM.js} +1 -1
- package/dist/static/assets/{line-BryEd-Ku.js → line-DxrK6d-_.js} +1 -1
- package/dist/static/assets/{linear-SXhM57Mz.js → linear-TwnxNDQ0.js} +1 -1
- package/dist/static/assets/{lt-LT-XHIRWOB4-BPrhIUrC.js → lt-LT-XHIRWOB4-BxYB7tM6.js} +1 -1
- package/dist/static/assets/{lv-LV-5QDEKY6T-CXJse_rs.js → lv-LV-5QDEKY6T-CGURbwyW.js} +1 -1
- package/dist/static/assets/{mindmap-definition-fc14e90a-C8giDsiX.js → mindmap-definition-fc14e90a-CWJfWF5a.js} +1 -1
- package/dist/static/assets/{mr-IN-CRQNXWMA-Clab-bAO.js → mr-IN-CRQNXWMA-65brZPyQ.js} +1 -1
- package/dist/static/assets/{my-MM-5M5IBNSE-Dp08JzEw.js → my-MM-5M5IBNSE-DaCAmQNv.js} +1 -1
- package/dist/static/assets/{nb-NO-T6EIAALU-CiaXJA-W.js → nb-NO-T6EIAALU-BiSJhu0W.js} +1 -1
- package/dist/static/assets/{nl-NL-IS3SIHDZ-D-9KUTnx.js → nl-NL-IS3SIHDZ-D3rj4Vme.js} +1 -1
- package/dist/static/assets/{nn-NO-6E72VCQL-Bg5gsQ4h.js → nn-NO-6E72VCQL-rxxP7Cwf.js} +1 -1
- package/dist/static/assets/{oc-FR-POXYY2M6-G4iqllhL.js → oc-FR-POXYY2M6-6emd2NQX.js} +1 -1
- package/dist/static/assets/{pa-IN-N4M65BXN-l6Lk41uX.js → pa-IN-N4M65BXN-CXwT_z_m.js} +1 -1
- package/dist/static/assets/{pica-CtkejCRD.js → pica-CtyIOuSv.js} +1 -1
- package/dist/static/assets/{pieDiagram-8a3498a8-CG6gQ14H.js → pieDiagram-8a3498a8-Ccff4vHz.js} +1 -1
- package/dist/static/assets/{pl-PL-T2D74RX3-BZPbB8S3.js → pl-PL-T2D74RX3-DMx_ZmIC.js} +1 -1
- package/dist/static/assets/{pt-BR-5N22H2LF-CIC4vRyd.js → pt-BR-5N22H2LF-D9nz7afr.js} +1 -1
- package/dist/static/assets/{pt-PT-UZXXM6DQ-rkGTBEI0.js → pt-PT-UZXXM6DQ-DeFH3geX.js} +1 -1
- package/dist/static/assets/{quadrantDiagram-120e2f19-BL9eFu4M.js → quadrantDiagram-120e2f19-RF2ZGF1U.js} +1 -1
- package/dist/static/assets/{requirementDiagram-deff3bca-crxdUpVK.js → requirementDiagram-deff3bca-CvnD9QLg.js} +1 -1
- package/dist/static/assets/{ro-RO-JPDTUUEW-GDhpTKBO.js → ro-RO-JPDTUUEW-Cy22QAjW.js} +1 -1
- package/dist/static/assets/{ru-RU-B4JR7IUQ-BzHvMwjC.js → ru-RU-B4JR7IUQ-Cw2rH2nW.js} +1 -1
- package/dist/static/assets/{sankeyDiagram-04a897e0-bM05WQw3.js → sankeyDiagram-04a897e0-CWfRjMv0.js} +1 -1
- package/dist/static/assets/{sequenceDiagram-704730f1-DjknV0Qp.js → sequenceDiagram-704730f1-pAE8N_Ym.js} +1 -1
- package/dist/static/assets/{si-LK-N5RQ5JYF-D3P3TNDH.js → si-LK-N5RQ5JYF-DmXIZ3i0.js} +1 -1
- package/dist/static/assets/{sk-SK-C5VTKIMK-CM8yTXlZ.js → sk-SK-C5VTKIMK-CboHDpHd.js} +1 -1
- package/dist/static/assets/{sl-SI-NN7IZMDC-CxoGm3aM.js → sl-SI-NN7IZMDC-8XnCHmN4.js} +1 -1
- package/dist/static/assets/{stateDiagram-587899a1-CmWqIdF5.js → stateDiagram-587899a1-B4nuLay6.js} +1 -1
- package/dist/static/assets/{stateDiagram-v2-d93cdb3a-CgzNTiHW.js → stateDiagram-v2-d93cdb3a-9cMNxr_8.js} +1 -1
- package/dist/static/assets/{styles-6aaf32cf-CI4s6NIA.js → styles-6aaf32cf-CynMMkPq.js} +1 -1
- package/dist/static/assets/{styles-9a916d00-ZcdN6rtW.js → styles-9a916d00-BTmAnC2j.js} +1 -1
- package/dist/static/assets/{styles-c10674c1-ZFkD6ta7.js → styles-c10674c1-DQ_pTuGr.js} +1 -1
- package/dist/static/assets/{subset-shared.chunk-B4F4dEPr.js → subset-shared.chunk-DPGuz0R6.js} +1 -1
- package/dist/static/assets/{subset-worker.chunk-CmgaOgn3.js → subset-worker.chunk-CMiOYLER.js} +1 -1
- package/dist/static/assets/{sv-SE-XGPEYMSR-CnVZlafq.js → sv-SE-XGPEYMSR-ATPKfqXs.js} +1 -1
- package/dist/static/assets/{svgDrawCommon-08f97a94-DbN3OiBf.js → svgDrawCommon-08f97a94-qY4BnSWc.js} +1 -1
- package/dist/static/assets/{ta-IN-2NMHFXQM-Bl-eCjzL.js → ta-IN-2NMHFXQM-Ct5-Fher.js} +1 -1
- package/dist/static/assets/{th-TH-HPSO5L25-CNIGPjSR.js → th-TH-HPSO5L25-5a6bUzcv.js} +1 -1
- package/dist/static/assets/{timeline-definition-85554ec2-Cmr82Iq1.js → timeline-definition-85554ec2-Bgexbl3C.js} +1 -1
- package/dist/static/assets/{tr-TR-DEFEU3FU-Cx7HbGIA.js → tr-TR-DEFEU3FU-WsK7dnwA.js} +1 -1
- package/dist/static/assets/{uk-UA-QMV73CPH-BxcA50Ze.js → uk-UA-QMV73CPH-B_P61mnc.js} +1 -1
- package/dist/static/assets/{vi-VN-M7AON7JQ-BvGuRh0c.js → vi-VN-M7AON7JQ-qdiQcney.js} +1 -1
- package/dist/static/assets/{xychartDiagram-e933f94c-BcWLDEHu.js → xychartDiagram-e933f94c-vkQjFADD.js} +1 -1
- package/dist/static/assets/{zh-CN-LNUGB5OW-SQH8i3l5.js → zh-CN-LNUGB5OW-DQ3BQjPe.js} +1 -1
- package/dist/static/assets/{zh-HK-E62DVLB3-COWoLNur.js → zh-HK-E62DVLB3-Ynj07W9J.js} +1 -1
- package/dist/static/assets/{zh-TW-RAJ6MFWO-Cm5B69ig.js → zh-TW-RAJ6MFWO-DNkcasuo.js} +1 -1
- package/dist/static/index.html +1 -1
- package/package.json +5 -2
- package/dist/static/assets/channel-DjiT9qJ0.js +0 -1
- package/dist/static/assets/clone-nkJpLn4s.js +0 -1
- package/dist/static/assets/flowDiagram-v2-96b9c2cf-Dlfh8z7R.js +0 -1
- package/dist/static/assets/index-B6CTdFKu.js +0 -311
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
2
|
+
import { resizeElements } from '../resize-elements';
|
|
3
|
+
function createMockClient(sendFn) {
|
|
4
|
+
return {
|
|
5
|
+
send: sendFn ?? vi.fn(() => Promise.resolve({ success: true, resizedCount: 2 })),
|
|
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('resizeElements', () => {
|
|
20
|
+
// ==================== Input Validation Tests ====================
|
|
21
|
+
describe('input validation', () => {
|
|
22
|
+
it('should error when all direction params are unspecified (default to 0)', async () => {
|
|
23
|
+
const deps = createMockDeps();
|
|
24
|
+
await resizeElements({ elementIds: ['el-1', 'el-2'] }, deps);
|
|
25
|
+
expect(deps.error).toHaveBeenCalledWith('At least one of --top, --bottom, --left, --right must be specified');
|
|
26
|
+
expect(deps.exit).toHaveBeenCalledWith(1);
|
|
27
|
+
expect(deps.connectToCanvas).not.toHaveBeenCalled();
|
|
28
|
+
});
|
|
29
|
+
it('should error when all direction params are explicitly 0', async () => {
|
|
30
|
+
const deps = createMockDeps();
|
|
31
|
+
await resizeElements({
|
|
32
|
+
elementIds: ['el-1'],
|
|
33
|
+
top: 0,
|
|
34
|
+
bottom: 0,
|
|
35
|
+
left: 0,
|
|
36
|
+
right: 0,
|
|
37
|
+
}, deps);
|
|
38
|
+
expect(deps.error).toHaveBeenCalledWith('At least one of --top, --bottom, --left, --right must be specified');
|
|
39
|
+
expect(deps.exit).toHaveBeenCalledWith(1);
|
|
40
|
+
expect(deps.connectToCanvas).not.toHaveBeenCalled();
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
// ==================== Parameter Assembly Tests ====================
|
|
44
|
+
describe('parameter assembly', () => {
|
|
45
|
+
it('should send correct params with elementIds and single direction', async () => {
|
|
46
|
+
const mockSend = vi.fn(() => Promise.resolve({ success: true, resizedCount: 1 }));
|
|
47
|
+
const mockClient = createMockClient(mockSend);
|
|
48
|
+
const deps = createMockDeps({
|
|
49
|
+
connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
|
|
50
|
+
});
|
|
51
|
+
await resizeElements({
|
|
52
|
+
elementIds: ['el-1', 'el-2'],
|
|
53
|
+
top: 50,
|
|
54
|
+
}, deps);
|
|
55
|
+
expect(mockSend).toHaveBeenCalledWith(expect.objectContaining({
|
|
56
|
+
type: 'resizeElements',
|
|
57
|
+
id: 'test-id',
|
|
58
|
+
params: {
|
|
59
|
+
elementIds: ['el-1', 'el-2'],
|
|
60
|
+
top: 50,
|
|
61
|
+
bottom: 0,
|
|
62
|
+
left: 0,
|
|
63
|
+
right: 0,
|
|
64
|
+
},
|
|
65
|
+
}));
|
|
66
|
+
});
|
|
67
|
+
it('should send correct params with all directions', async () => {
|
|
68
|
+
const mockSend = vi.fn(() => Promise.resolve({ success: true, resizedCount: 2 }));
|
|
69
|
+
const mockClient = createMockClient(mockSend);
|
|
70
|
+
const deps = createMockDeps({
|
|
71
|
+
connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
|
|
72
|
+
});
|
|
73
|
+
await resizeElements({
|
|
74
|
+
elementIds: ['el-1'],
|
|
75
|
+
top: 10,
|
|
76
|
+
bottom: 20,
|
|
77
|
+
left: 30,
|
|
78
|
+
right: 40,
|
|
79
|
+
}, deps);
|
|
80
|
+
const callParams = mockSend.mock.calls[0][0].params;
|
|
81
|
+
expect(callParams.elementIds).toEqual(['el-1']);
|
|
82
|
+
expect(callParams.top).toBe(10);
|
|
83
|
+
expect(callParams.bottom).toBe(20);
|
|
84
|
+
expect(callParams.left).toBe(30);
|
|
85
|
+
expect(callParams.right).toBe(40);
|
|
86
|
+
});
|
|
87
|
+
it('should default unspecified directions to 0', async () => {
|
|
88
|
+
const mockSend = vi.fn(() => Promise.resolve({ success: true, resizedCount: 1 }));
|
|
89
|
+
const mockClient = createMockClient(mockSend);
|
|
90
|
+
const deps = createMockDeps({
|
|
91
|
+
connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
|
|
92
|
+
});
|
|
93
|
+
await resizeElements({
|
|
94
|
+
elementIds: ['el-1'],
|
|
95
|
+
left: 25,
|
|
96
|
+
right: -10,
|
|
97
|
+
}, deps);
|
|
98
|
+
const callParams = mockSend.mock.calls[0][0].params;
|
|
99
|
+
expect(callParams.top).toBe(0);
|
|
100
|
+
expect(callParams.bottom).toBe(0);
|
|
101
|
+
expect(callParams.left).toBe(25);
|
|
102
|
+
expect(callParams.right).toBe(-10);
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
// ==================== Response Handling Tests ====================
|
|
106
|
+
describe('response handling', () => {
|
|
107
|
+
it('should log success message with count', async () => {
|
|
108
|
+
const mockSend = vi.fn(() => Promise.resolve({ success: true, resizedCount: 3 }));
|
|
109
|
+
const mockClient = createMockClient(mockSend);
|
|
110
|
+
const deps = createMockDeps({
|
|
111
|
+
connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
|
|
112
|
+
});
|
|
113
|
+
await resizeElements({ elementIds: ['el-1', 'el-2', 'el-3'], top: 10 }, deps);
|
|
114
|
+
expect(deps.log).toHaveBeenCalledWith('Resized 3 element(s)');
|
|
115
|
+
});
|
|
116
|
+
it('should error and exit on failure response', async () => {
|
|
117
|
+
const mockSend = vi.fn(() => Promise.resolve({
|
|
118
|
+
success: false,
|
|
119
|
+
error: 'Invalid element ID',
|
|
120
|
+
}));
|
|
121
|
+
const mockClient = createMockClient(mockSend);
|
|
122
|
+
const deps = createMockDeps({
|
|
123
|
+
connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
|
|
124
|
+
});
|
|
125
|
+
await resizeElements({ elementIds: ['invalid'], bottom: 5 }, deps);
|
|
126
|
+
expect(deps.error).toHaveBeenCalledWith('Failed: Invalid element ID');
|
|
127
|
+
expect(deps.exit).toHaveBeenCalledWith(1);
|
|
128
|
+
});
|
|
129
|
+
it('should close client after success', async () => {
|
|
130
|
+
const mockClose = vi.fn();
|
|
131
|
+
const mockSend = vi.fn(() => Promise.resolve({ success: true, resizedCount: 1 }));
|
|
132
|
+
const mockClient = { send: mockSend, close: mockClose };
|
|
133
|
+
const deps = createMockDeps({
|
|
134
|
+
connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
|
|
135
|
+
});
|
|
136
|
+
await resizeElements({ elementIds: ['el-1'], top: 10 }, deps);
|
|
137
|
+
expect(mockClose).toHaveBeenCalled();
|
|
138
|
+
});
|
|
139
|
+
it('should close client after failure', async () => {
|
|
140
|
+
const mockClose = vi.fn();
|
|
141
|
+
const mockSend = vi.fn(() => Promise.resolve({ success: false, error: 'error' }));
|
|
142
|
+
const mockClient = { send: mockSend, close: mockClose };
|
|
143
|
+
const deps = createMockDeps({
|
|
144
|
+
connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
|
|
145
|
+
});
|
|
146
|
+
await resizeElements({ elementIds: ['el-1'], top: 10 }, deps);
|
|
147
|
+
expect(mockClose).toHaveBeenCalled();
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
2
|
+
import { rotateElements } from '../rotate-elements';
|
|
3
|
+
function createMockClient(sendFn) {
|
|
4
|
+
return {
|
|
5
|
+
send: sendFn ?? vi.fn(() => Promise.resolve({ success: true, rotatedCount: 2 })),
|
|
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('rotateElements', () => {
|
|
20
|
+
// ==================== Parameter Assembly Tests ====================
|
|
21
|
+
describe('parameter assembly', () => {
|
|
22
|
+
it('should parse comma-separated element IDs correctly', async () => {
|
|
23
|
+
const mockSend = vi.fn(() => Promise.resolve({ success: true, rotatedCount: 2 }));
|
|
24
|
+
const mockClient = createMockClient(mockSend);
|
|
25
|
+
const deps = createMockDeps({
|
|
26
|
+
connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
|
|
27
|
+
});
|
|
28
|
+
await rotateElements({ elementIds: 'id1, id2', angle: 45 }, deps);
|
|
29
|
+
expect(mockSend).toHaveBeenCalledWith(expect.objectContaining({
|
|
30
|
+
type: 'rotateElements',
|
|
31
|
+
id: 'test-id',
|
|
32
|
+
params: {
|
|
33
|
+
elementIds: ['id1', 'id2'],
|
|
34
|
+
angle: 45,
|
|
35
|
+
},
|
|
36
|
+
}));
|
|
37
|
+
});
|
|
38
|
+
it('should pass angle correctly', async () => {
|
|
39
|
+
const mockSend = vi.fn(() => Promise.resolve({ success: true, rotatedCount: 1 }));
|
|
40
|
+
const mockClient = createMockClient(mockSend);
|
|
41
|
+
const deps = createMockDeps({
|
|
42
|
+
connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
|
|
43
|
+
});
|
|
44
|
+
await rotateElements({ elementIds: 'id1', angle: 90 }, deps);
|
|
45
|
+
const callParams = mockSend.mock.calls[0][0].params;
|
|
46
|
+
expect(callParams.angle).toBe(90);
|
|
47
|
+
});
|
|
48
|
+
it('should handle negative angle', async () => {
|
|
49
|
+
const mockSend = vi.fn(() => Promise.resolve({ success: true, rotatedCount: 1 }));
|
|
50
|
+
const mockClient = createMockClient(mockSend);
|
|
51
|
+
const deps = createMockDeps({
|
|
52
|
+
connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
|
|
53
|
+
});
|
|
54
|
+
await rotateElements({ elementIds: 'id1', angle: -45 }, deps);
|
|
55
|
+
const callParams = mockSend.mock.calls[0][0].params;
|
|
56
|
+
expect(callParams.angle).toBe(-45);
|
|
57
|
+
});
|
|
58
|
+
it('should trim whitespace from element IDs', async () => {
|
|
59
|
+
const mockSend = vi.fn(() => Promise.resolve({ success: true, rotatedCount: 2 }));
|
|
60
|
+
const mockClient = createMockClient(mockSend);
|
|
61
|
+
const deps = createMockDeps({
|
|
62
|
+
connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
|
|
63
|
+
});
|
|
64
|
+
await rotateElements({ elementIds: ' id1 , id2 ', angle: 30 }, deps);
|
|
65
|
+
const callParams = mockSend.mock.calls[0][0].params;
|
|
66
|
+
expect(callParams.elementIds).toEqual(['id1', 'id2']);
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
// ==================== Response Handling Tests ====================
|
|
70
|
+
describe('response handling', () => {
|
|
71
|
+
it('should log success message with rotated count', async () => {
|
|
72
|
+
const mockSend = vi.fn(() => Promise.resolve({ success: true, rotatedCount: 3 }));
|
|
73
|
+
const mockClient = createMockClient(mockSend);
|
|
74
|
+
const deps = createMockDeps({
|
|
75
|
+
connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
|
|
76
|
+
});
|
|
77
|
+
await rotateElements({ elementIds: 'id1,id2,id3', angle: 45 }, deps);
|
|
78
|
+
expect(deps.log).toHaveBeenCalledWith('Rotated 3 element(s)');
|
|
79
|
+
});
|
|
80
|
+
it('should error and exit on failure response', async () => {
|
|
81
|
+
const mockSend = vi.fn(() => Promise.resolve({
|
|
82
|
+
success: false,
|
|
83
|
+
error: 'Cannot rotate text element',
|
|
84
|
+
}));
|
|
85
|
+
const mockClient = createMockClient(mockSend);
|
|
86
|
+
const deps = createMockDeps({
|
|
87
|
+
connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
|
|
88
|
+
});
|
|
89
|
+
await rotateElements({ elementIds: 'text-id', angle: 45 }, deps);
|
|
90
|
+
expect(deps.error).toHaveBeenCalledWith('Failed: Cannot rotate text element');
|
|
91
|
+
expect(deps.exit).toHaveBeenCalledWith(1);
|
|
92
|
+
});
|
|
93
|
+
it('should close client after success', async () => {
|
|
94
|
+
const mockClose = vi.fn();
|
|
95
|
+
const mockSend = vi.fn(() => Promise.resolve({ success: true, rotatedCount: 1 }));
|
|
96
|
+
const mockClient = { send: mockSend, close: mockClose };
|
|
97
|
+
const deps = createMockDeps({
|
|
98
|
+
connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
|
|
99
|
+
});
|
|
100
|
+
await rotateElements({ elementIds: 'id1', angle: 90 }, deps);
|
|
101
|
+
expect(mockClose).toHaveBeenCalled();
|
|
102
|
+
});
|
|
103
|
+
it('should close client after failure', async () => {
|
|
104
|
+
const mockClose = vi.fn();
|
|
105
|
+
const mockSend = vi.fn(() => Promise.resolve({ success: false, error: 'error' }));
|
|
106
|
+
const mockClient = { send: mockSend, close: mockClose };
|
|
107
|
+
const deps = createMockDeps({
|
|
108
|
+
connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
|
|
109
|
+
});
|
|
110
|
+
await rotateElements({ elementIds: 'id1', angle: 45 }, deps);
|
|
111
|
+
expect(mockClose).toHaveBeenCalled();
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
2
|
+
import { save } from '../save';
|
|
3
|
+
function createMockClient(sendFn) {
|
|
4
|
+
return {
|
|
5
|
+
send: sendFn ?? vi.fn(() => Promise.resolve({ success: true, data: { elements: [] } })),
|
|
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
|
+
writeFile: vi.fn(),
|
|
14
|
+
log: vi.fn(),
|
|
15
|
+
error: vi.fn(),
|
|
16
|
+
exit: vi.fn(),
|
|
17
|
+
...overrides,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
describe('save', () => {
|
|
21
|
+
// ==================== Parameter/Logic Tests ====================
|
|
22
|
+
describe('filepath handling', () => {
|
|
23
|
+
it('should auto-add .excalidraw extension if not present', async () => {
|
|
24
|
+
const mockWriteFile = vi.fn();
|
|
25
|
+
const mockSend = vi.fn(() => Promise.resolve({ success: true, data: { elements: [] } }));
|
|
26
|
+
const mockClient = createMockClient(mockSend);
|
|
27
|
+
const deps = createMockDeps({
|
|
28
|
+
connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
|
|
29
|
+
writeFile: mockWriteFile,
|
|
30
|
+
});
|
|
31
|
+
await save('mycanvas', deps);
|
|
32
|
+
expect(mockWriteFile).toHaveBeenCalledWith('mycanvas.excalidraw', expect.any(String));
|
|
33
|
+
expect(deps.log).toHaveBeenCalledWith('Saved to mycanvas.excalidraw');
|
|
34
|
+
});
|
|
35
|
+
it('should not add extension if .excalidraw already present', async () => {
|
|
36
|
+
const mockWriteFile = vi.fn();
|
|
37
|
+
const mockSend = vi.fn(() => Promise.resolve({ success: true, data: { elements: [] } }));
|
|
38
|
+
const mockClient = createMockClient(mockSend);
|
|
39
|
+
const deps = createMockDeps({
|
|
40
|
+
connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
|
|
41
|
+
writeFile: mockWriteFile,
|
|
42
|
+
});
|
|
43
|
+
await save('mycanvas.excalidraw', deps);
|
|
44
|
+
expect(mockWriteFile).toHaveBeenCalledWith('mycanvas.excalidraw', expect.any(String));
|
|
45
|
+
expect(deps.log).toHaveBeenCalledWith('Saved to mycanvas.excalidraw');
|
|
46
|
+
});
|
|
47
|
+
it('should write JSON data correctly', async () => {
|
|
48
|
+
const mockWriteFile = vi.fn();
|
|
49
|
+
const sceneData = { elements: [{ id: 'el-1' }], appState: {} };
|
|
50
|
+
const mockSend = vi.fn(() => Promise.resolve({ success: true, data: sceneData }));
|
|
51
|
+
const mockClient = createMockClient(mockSend);
|
|
52
|
+
const deps = createMockDeps({
|
|
53
|
+
connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
|
|
54
|
+
writeFile: mockWriteFile,
|
|
55
|
+
});
|
|
56
|
+
await save('test', deps);
|
|
57
|
+
expect(mockWriteFile).toHaveBeenCalledWith('test.excalidraw', JSON.stringify(sceneData, null, 2));
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
// ==================== Response Handling Tests ====================
|
|
61
|
+
describe('response handling', () => {
|
|
62
|
+
it('should log success message on success', async () => {
|
|
63
|
+
const mockSend = vi.fn(() => Promise.resolve({ success: true, data: { elements: [] } }));
|
|
64
|
+
const mockClient = createMockClient(mockSend);
|
|
65
|
+
const deps = createMockDeps({
|
|
66
|
+
connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
|
|
67
|
+
});
|
|
68
|
+
await save('output', deps);
|
|
69
|
+
expect(deps.log).toHaveBeenCalledWith('Saved to output.excalidraw');
|
|
70
|
+
});
|
|
71
|
+
it('should error and exit on failure response', async () => {
|
|
72
|
+
const mockSend = vi.fn(() => Promise.resolve({
|
|
73
|
+
success: false,
|
|
74
|
+
error: 'Connection lost',
|
|
75
|
+
}));
|
|
76
|
+
const mockClient = createMockClient(mockSend);
|
|
77
|
+
const deps = createMockDeps({
|
|
78
|
+
connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
|
|
79
|
+
});
|
|
80
|
+
await save('output', deps);
|
|
81
|
+
expect(deps.error).toHaveBeenCalledWith('Failed: Connection lost');
|
|
82
|
+
expect(deps.exit).toHaveBeenCalledWith(1);
|
|
83
|
+
});
|
|
84
|
+
it('should close client after success', async () => {
|
|
85
|
+
const mockClose = vi.fn();
|
|
86
|
+
const mockSend = vi.fn(() => Promise.resolve({ success: true, data: { elements: [] } }));
|
|
87
|
+
const mockClient = { send: mockSend, close: mockClose };
|
|
88
|
+
const deps = createMockDeps({
|
|
89
|
+
connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
|
|
90
|
+
});
|
|
91
|
+
await save('output', deps);
|
|
92
|
+
expect(mockClose).toHaveBeenCalled();
|
|
93
|
+
});
|
|
94
|
+
it('should close client after failure', async () => {
|
|
95
|
+
const mockClose = vi.fn();
|
|
96
|
+
const mockSend = vi.fn(() => Promise.resolve({ success: false, error: 'error' }));
|
|
97
|
+
const mockClient = { send: mockSend, close: mockClose };
|
|
98
|
+
const deps = createMockDeps({
|
|
99
|
+
connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
|
|
100
|
+
});
|
|
101
|
+
await save('output', deps);
|
|
102
|
+
expect(mockClose).toHaveBeenCalled();
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
2
|
+
import { ungroupElement } from '../ungroup-element';
|
|
3
|
+
function createMockClient(sendFn) {
|
|
4
|
+
return {
|
|
5
|
+
send: sendFn ?? vi.fn(() => Promise.resolve({ success: true })),
|
|
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('ungroupElement', () => {
|
|
20
|
+
// ==================== Parameter Assembly Tests ====================
|
|
21
|
+
describe('parameter assembly', () => {
|
|
22
|
+
it('should send correct params with elementId', async () => {
|
|
23
|
+
const mockSend = vi.fn(() => Promise.resolve({ success: true }));
|
|
24
|
+
const mockClient = createMockClient(mockSend);
|
|
25
|
+
const deps = createMockDeps({
|
|
26
|
+
connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
|
|
27
|
+
});
|
|
28
|
+
await ungroupElement({ elementId: 'el-123' }, deps);
|
|
29
|
+
expect(mockSend).toHaveBeenCalledWith(expect.objectContaining({
|
|
30
|
+
type: 'ungroupElement',
|
|
31
|
+
id: 'test-id',
|
|
32
|
+
params: {
|
|
33
|
+
elementId: 'el-123',
|
|
34
|
+
},
|
|
35
|
+
}));
|
|
36
|
+
});
|
|
37
|
+
it('should pass elementId correctly', async () => {
|
|
38
|
+
const mockSend = vi.fn(() => Promise.resolve({ success: true }));
|
|
39
|
+
const mockClient = createMockClient(mockSend);
|
|
40
|
+
const deps = createMockDeps({
|
|
41
|
+
connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
|
|
42
|
+
});
|
|
43
|
+
await ungroupElement({ elementId: 'complex-element-id-abc' }, deps);
|
|
44
|
+
const callParams = mockSend.mock.calls[0][0].params;
|
|
45
|
+
expect(callParams.elementId).toBe('complex-element-id-abc');
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
// ==================== Response Handling Tests ====================
|
|
49
|
+
describe('response handling', () => {
|
|
50
|
+
it('should log success message', async () => {
|
|
51
|
+
const mockSend = vi.fn(() => Promise.resolve({ success: true }));
|
|
52
|
+
const mockClient = createMockClient(mockSend);
|
|
53
|
+
const deps = createMockDeps({
|
|
54
|
+
connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
|
|
55
|
+
});
|
|
56
|
+
await ungroupElement({ elementId: 'el-1' }, deps);
|
|
57
|
+
expect(deps.log).toHaveBeenCalledWith('Element ungrouped');
|
|
58
|
+
});
|
|
59
|
+
it('should error and exit on failure response', async () => {
|
|
60
|
+
const mockSend = vi.fn(() => Promise.resolve({
|
|
61
|
+
success: false,
|
|
62
|
+
error: 'Element not found',
|
|
63
|
+
}));
|
|
64
|
+
const mockClient = createMockClient(mockSend);
|
|
65
|
+
const deps = createMockDeps({
|
|
66
|
+
connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
|
|
67
|
+
});
|
|
68
|
+
await ungroupElement({ elementId: 'non-existent' }, deps);
|
|
69
|
+
expect(deps.error).toHaveBeenCalledWith('Failed: Element not found');
|
|
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 }));
|
|
75
|
+
const mockClient = { send: mockSend, close: mockClose };
|
|
76
|
+
const deps = createMockDeps({
|
|
77
|
+
connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
|
|
78
|
+
});
|
|
79
|
+
await ungroupElement({ elementId: 'el-1' }, 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 ungroupElement({ elementId: 'el-1' }, deps);
|
|
90
|
+
expect(mockClose).toHaveBeenCalled();
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
2
|
+
import { useCanvas } from '../use-canvas';
|
|
3
|
+
function createMockClient(sendFn) {
|
|
4
|
+
return {
|
|
5
|
+
send: sendFn ?? vi.fn(() => Promise.resolve({ success: true, canvas: { name: 'Test' } })),
|
|
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('useCanvas', () => {
|
|
20
|
+
// ==================== Parameter Assembly Tests ====================
|
|
21
|
+
describe('parameter assembly', () => {
|
|
22
|
+
it('should send correct params with name', async () => {
|
|
23
|
+
const mockSend = vi.fn(() => Promise.resolve({ success: true, canvas: { name: 'Target Canvas' } }));
|
|
24
|
+
const mockClient = createMockClient(mockSend);
|
|
25
|
+
const deps = createMockDeps({
|
|
26
|
+
connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
|
|
27
|
+
});
|
|
28
|
+
await useCanvas({ name: 'Target Canvas' }, deps);
|
|
29
|
+
expect(mockSend).toHaveBeenCalledWith(expect.objectContaining({
|
|
30
|
+
type: 'switchCanvas',
|
|
31
|
+
id: 'test-id',
|
|
32
|
+
params: {
|
|
33
|
+
name: 'Target Canvas',
|
|
34
|
+
},
|
|
35
|
+
}));
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
// ==================== Response Handling Tests ====================
|
|
39
|
+
describe('response handling', () => {
|
|
40
|
+
it('should log success message with canvas name', async () => {
|
|
41
|
+
const mockSend = vi.fn(() => Promise.resolve({
|
|
42
|
+
success: true,
|
|
43
|
+
canvas: { name: 'My Canvas' },
|
|
44
|
+
}));
|
|
45
|
+
const mockClient = createMockClient(mockSend);
|
|
46
|
+
const deps = createMockDeps({
|
|
47
|
+
connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
|
|
48
|
+
});
|
|
49
|
+
await useCanvas({ name: 'My Canvas' }, deps);
|
|
50
|
+
expect(deps.log).toHaveBeenCalledWith('Switched to canvas "My Canvas"');
|
|
51
|
+
});
|
|
52
|
+
it('should error and exit on failure response', async () => {
|
|
53
|
+
const mockSend = vi.fn(() => Promise.resolve({
|
|
54
|
+
success: false,
|
|
55
|
+
error: 'Canvas not found',
|
|
56
|
+
}));
|
|
57
|
+
const mockClient = createMockClient(mockSend);
|
|
58
|
+
const deps = createMockDeps({
|
|
59
|
+
connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
|
|
60
|
+
});
|
|
61
|
+
await useCanvas({ name: 'Non-existent' }, deps);
|
|
62
|
+
expect(deps.error).toHaveBeenCalledWith('Failed: Canvas not found');
|
|
63
|
+
expect(deps.exit).toHaveBeenCalledWith(1);
|
|
64
|
+
});
|
|
65
|
+
it('should close client after success', async () => {
|
|
66
|
+
const mockClose = vi.fn();
|
|
67
|
+
const mockSend = vi.fn(() => Promise.resolve({ success: true, canvas: { name: 'Test' } }));
|
|
68
|
+
const mockClient = { send: mockSend, close: mockClose };
|
|
69
|
+
const deps = createMockDeps({
|
|
70
|
+
connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
|
|
71
|
+
});
|
|
72
|
+
await useCanvas({ name: 'Test' }, deps);
|
|
73
|
+
expect(mockClose).toHaveBeenCalled();
|
|
74
|
+
});
|
|
75
|
+
it('should close client after failure', async () => {
|
|
76
|
+
const mockClose = vi.fn();
|
|
77
|
+
const mockSend = vi.fn(() => Promise.resolve({ success: false, error: 'error' }));
|
|
78
|
+
const mockClient = { send: mockSend, close: mockClose };
|
|
79
|
+
const deps = createMockDeps({
|
|
80
|
+
connectToCanvas: vi.fn(() => Promise.resolve(mockClient)),
|
|
81
|
+
});
|
|
82
|
+
await useCanvas({ name: 'Test' }, deps);
|
|
83
|
+
expect(mockClose).toHaveBeenCalled();
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
});
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export interface AddArrowOptions {
|
|
2
|
+
x: number;
|
|
3
|
+
y: number;
|
|
4
|
+
endX: number;
|
|
5
|
+
endY: number;
|
|
6
|
+
strokeColor?: string;
|
|
7
|
+
strokeWidth?: number;
|
|
8
|
+
strokeStyle?: 'solid' | 'dashed' | 'dotted';
|
|
9
|
+
startArrowhead?: 'arrow' | 'bar' | 'dot' | 'triangle' | 'diamond' | 'none';
|
|
10
|
+
endArrowhead?: 'arrow' | 'bar' | 'dot' | 'triangle' | 'diamond' | 'none';
|
|
11
|
+
arrowType?: 'sharp' | 'round' | 'elbow';
|
|
12
|
+
via?: string;
|
|
13
|
+
note?: string;
|
|
14
|
+
}
|
|
15
|
+
export interface ArrowClient {
|
|
16
|
+
send: <T>(request: {
|
|
17
|
+
type: string;
|
|
18
|
+
id: string;
|
|
19
|
+
params?: unknown;
|
|
20
|
+
}) => Promise<T>;
|
|
21
|
+
close: () => void;
|
|
22
|
+
}
|
|
23
|
+
export interface AddArrowDeps {
|
|
24
|
+
connectToCanvas: () => Promise<ArrowClient>;
|
|
25
|
+
generateId: () => string;
|
|
26
|
+
log: (msg: string) => void;
|
|
27
|
+
error: (msg: string) => void;
|
|
28
|
+
exit: (code: number) => never | void;
|
|
29
|
+
}
|
|
30
|
+
export declare const defaultDeps: AddArrowDeps;
|
|
31
|
+
/**
|
|
32
|
+
* Parse via points string into midpoints array
|
|
33
|
+
* @param via - Points string in format "x1,y1;x2,y2;..."
|
|
34
|
+
* @returns Array of point objects
|
|
35
|
+
*/
|
|
36
|
+
export declare function parseViaPoints(via: string): Array<{
|
|
37
|
+
x: number;
|
|
38
|
+
y: number;
|
|
39
|
+
}>;
|
|
40
|
+
export declare function addArrow(options: AddArrowOptions, deps?: AddArrowDeps): Promise<void>;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { connectToCanvas, generateId } from '../lib/ws-client.js';
|
|
2
|
+
export const defaultDeps = {
|
|
3
|
+
connectToCanvas,
|
|
4
|
+
generateId,
|
|
5
|
+
log: console.log,
|
|
6
|
+
error: console.error,
|
|
7
|
+
exit: process.exit,
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Parse via points string into midpoints array
|
|
11
|
+
* @param via - Points string in format "x1,y1;x2,y2;..."
|
|
12
|
+
* @returns Array of point objects
|
|
13
|
+
*/
|
|
14
|
+
export function parseViaPoints(via) {
|
|
15
|
+
return via.split(';').map((pt) => {
|
|
16
|
+
const [x, y] = pt.split(',').map(Number);
|
|
17
|
+
return { x, y };
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
export async function addArrow(options, deps = defaultDeps) {
|
|
21
|
+
const client = await deps.connectToCanvas();
|
|
22
|
+
// Parse --via option into midpoints array
|
|
23
|
+
const midpoints = options.via ? parseViaPoints(options.via) : undefined;
|
|
24
|
+
// Build params
|
|
25
|
+
const params = {
|
|
26
|
+
x: options.x,
|
|
27
|
+
y: options.y,
|
|
28
|
+
endX: options.endX,
|
|
29
|
+
endY: options.endY,
|
|
30
|
+
strokeColor: options.strokeColor,
|
|
31
|
+
strokeWidth: options.strokeWidth,
|
|
32
|
+
strokeStyle: options.strokeStyle,
|
|
33
|
+
startArrowhead: options.startArrowhead,
|
|
34
|
+
endArrowhead: options.endArrowhead,
|
|
35
|
+
arrowType: options.arrowType,
|
|
36
|
+
midpoints,
|
|
37
|
+
customData: options.note ? { note: options.note } : undefined,
|
|
38
|
+
};
|
|
39
|
+
const result = await client.send({
|
|
40
|
+
type: 'addArrow',
|
|
41
|
+
id: deps.generateId(),
|
|
42
|
+
params,
|
|
43
|
+
});
|
|
44
|
+
if (result.success) {
|
|
45
|
+
deps.log(`Arrow created (id: ${result.elementId})`);
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
deps.error(`Failed: ${result.error}`);
|
|
49
|
+
deps.exit(1);
|
|
50
|
+
}
|
|
51
|
+
client.close();
|
|
52
|
+
}
|