From b871d4ceb34796736113e09551e53b1a520e19a1 Mon Sep 17 00:00:00 2001 From: Ryan Di Date: Wed, 25 Mar 2026 18:04:22 +1100 Subject: [PATCH] test: update coverage and snapshots for per-track schemaState --- excalidraw-app/tests/collab.test.tsx | 61 +- .../__snapshots__/transform.test.ts.snap | 248 ++- .../actions/actionProperties.test.tsx | 8 + packages/excalidraw/clipboard.test.ts | 17 +- packages/excalidraw/data/schema.test.ts | 199 ++- .../__snapshots__/contextmenu.test.tsx.snap | 328 +++- .../__snapshots__/dragCreate.test.tsx.snap | 20 +- .../tests/__snapshots__/export.test.tsx.snap | 2 +- .../tests/__snapshots__/history.test.tsx.snap | 1448 ++++++++++++++--- .../tests/__snapshots__/move.test.tsx.snap | 24 +- .../multiPointCreate.test.tsx.snap | 8 +- .../regressionTests.test.tsx.snap | 766 +++++++-- .../__snapshots__/selection.test.tsx.snap | 20 +- .../data/__snapshots__/restore.test.ts.snap | 40 +- .../excalidraw/tests/data/restore.test.ts | 4 +- .../tests/fixtures/elementFixture.ts | 3 + packages/excalidraw/tests/helpers/api.ts | 3 + packages/excalidraw/tests/lasso.test.tsx | 3 + .../scene/__snapshots__/export.test.ts.snap | 2 +- 19 files changed, 2623 insertions(+), 581 deletions(-) diff --git a/excalidraw-app/tests/collab.test.tsx b/excalidraw-app/tests/collab.test.tsx index d2f5051958..7b0e1e4686 100644 --- a/excalidraw-app/tests/collab.test.tsx +++ b/excalidraw-app/tests/collab.test.tsx @@ -84,10 +84,15 @@ describe("collaboration", () => { const frameWithFutureFields = { ...frame, - schemaVersion: 2, + schemaState: { + tracks: { + ...frame.schemaState.tracks, + "host.myapp.frame": 1, + }, + }, futureField: "keep-me", } as typeof frame & { - schemaVersion: number; + schemaState: { tracks: Record }; futureField: string; }; @@ -98,7 +103,9 @@ describe("collaboration", () => { await waitFor(() => { expect((h.elements[0] as any).futureField).toBe("keep-me"); - expect((h.elements[0] as any).schemaVersion).toBe(2); + expect((h.elements[0] as any).schemaState).toEqual( + frameWithFutureFields.schemaState, + ); expect(h.elements[0].backgroundColor).toBe("#ff0000"); }); @@ -119,7 +126,9 @@ describe("collaboration", () => { }), ); expect((reconciled[0] as any).futureField).toBe("keep-me"); - expect((reconciled[0] as any).schemaVersion).toBe(2); + expect((reconciled[0] as any).schemaState).toEqual( + frameWithFutureFields.schemaState, + ); }); it("should preserve future element fields on local edits before broadcast", async () => { @@ -136,10 +145,15 @@ describe("collaboration", () => { const rectWithFutureFields = { ...rect, - schemaVersion: 2, + schemaState: { + tracks: { + ...rect.schemaState.tracks, + "host.myapp.rect": 1, + }, + }, futureField: { value: "keep-me" }, } as typeof rect & { - schemaVersion: number; + schemaState: { tracks: Record }; futureField: { value: string }; }; @@ -156,7 +170,9 @@ describe("collaboration", () => { await waitFor(() => { expect((h.elements[0] as any).futureField).toEqual({ value: "keep-me" }); - expect((h.elements[0] as any).schemaVersion).toBe(2); + expect((h.elements[0] as any).schemaState).toEqual( + rectWithFutureFields.schemaState, + ); expect(h.elements[0]).toEqual(expect.objectContaining({ x: 200 })); }); }); @@ -175,14 +191,18 @@ describe("collaboration", () => { } }); - // eslint-disable-next-line dot-notation - expect(h.store["scheduledMicroActions"].length).toBe(0); - expect(durableIncrements.length).toBe(0); - expect(ephemeralIncrements.length).toBe(0); + // Ensure this test starts from a deterministic scene regardless of previous + // test state restored from persistence. + API.updateScene({ + elements: [], + captureUpdate: CaptureUpdateAction.NEVER, + }); + + const durableBaseline = durableIncrements.length; + const ephemeralBaseline = ephemeralIncrements.length; const rectProps = { type: "rectangle", - id: "A", height: 200, width: 100, x: 0, @@ -197,8 +217,7 @@ describe("collaboration", () => { }); await waitFor(() => { - // expect(commitSpy).toHaveBeenCalledTimes(1); - expect(durableIncrements.length).toBe(1); + expect(durableIncrements.length).toBe(durableBaseline + 1); }); // simulate two batched remote updates @@ -222,13 +241,13 @@ describe("collaboration", () => { // altough the updates get batched, // we expect two ephemeral increments for each update, // and each such update should have the expected change - expect(ephemeralIncrements.length).toBe(2); - expect(ephemeralIncrements[0].change.elements.A).toEqual( - expect.objectContaining({ x: 100 }), - ); - expect(ephemeralIncrements[1].change.elements.A).toEqual( - expect.objectContaining({ x: 200 }), - ); + expect(ephemeralIncrements.length).toBe(ephemeralBaseline + 2); + expect( + ephemeralIncrements[ephemeralBaseline].change.elements[rect.id], + ).toEqual(expect.objectContaining({ x: 100 })); + expect( + ephemeralIncrements[ephemeralBaseline + 1].change.elements[rect.id], + ).toEqual(expect.objectContaining({ x: 200 })); // eslint-disable-next-line dot-notation expect(h.store["scheduledMicroActions"].length).toBe(0); }); diff --git a/packages/element/src/__tests__/__snapshots__/transform.test.ts.snap b/packages/element/src/__tests__/__snapshots__/transform.test.ts.snap index 96658c8694..c2e6ff0071 100644 --- a/packages/element/src/__tests__/__snapshots__/transform.test.ts.snap +++ b/packages/element/src/__tests__/__snapshots__/transform.test.ts.snap @@ -27,7 +27,9 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to existing s "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": Any, "strokeColor": "#66a80f", "strokeStyle": "solid", @@ -65,7 +67,9 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to existing s "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": Any, "strokeColor": "#9c36b5", "strokeStyle": "solid", @@ -118,7 +122,9 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to existing s ], "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": Any, "startArrowhead": null, "startBinding": { @@ -180,7 +186,9 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to existing s ], "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": Any, "startArrowhead": null, "startBinding": { @@ -227,7 +235,9 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to existing s "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": Any, "strokeColor": "#1e1e1e", "strokeStyle": "solid", @@ -271,7 +281,9 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to existing t "originalText": "HEYYYYY", "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": Any, "strokeColor": "#c2255c", "strokeStyle": "solid", @@ -318,7 +330,9 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to existing t "originalText": "Whats up ?", "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": Any, "strokeColor": "#1e1e1e", "strokeStyle": "solid", @@ -379,7 +393,9 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to existing t ], "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": Any, "startArrowhead": null, "startBinding": { @@ -427,7 +443,9 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to existing t "originalText": "HELLO WORLD!!", "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": Any, "strokeColor": "#1e1e1e", "strokeStyle": "solid", @@ -488,7 +506,9 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to shapes whe ], "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": Any, "startArrowhead": null, "startBinding": { @@ -536,7 +556,9 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to shapes whe "originalText": "HELLO WORLD!!", "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": Any, "strokeColor": "#1e1e1e", "strokeStyle": "solid", @@ -577,7 +599,9 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to shapes whe "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": Any, "strokeColor": "#1e1e1e", "strokeStyle": "solid", @@ -615,7 +639,9 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to shapes whe "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": Any, "strokeColor": "#1e1e1e", "strokeStyle": "solid", @@ -673,7 +699,9 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to text when ], "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": Any, "startArrowhead": null, "startBinding": { @@ -721,7 +749,9 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to text when "originalText": "HELLO WORLD!!", "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": Any, "strokeColor": "#1e1e1e", "strokeStyle": "solid", @@ -768,7 +798,9 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to text when "originalText": "HEYYYYY", "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": Any, "strokeColor": "#1e1e1e", "strokeStyle": "solid", @@ -815,7 +847,9 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to text when "originalText": "WHATS UP ?", "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": Any, "strokeColor": "#1e1e1e", "strokeStyle": "solid", @@ -851,7 +885,9 @@ exports[`Test Transform > should not allow duplicate ids 1`] = ` "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": Any, "strokeColor": "#1e1e1e", "strokeStyle": "solid", @@ -897,7 +933,9 @@ exports[`Test Transform > should transform linear elements 1`] = ` ], "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": Any, "startArrowhead": null, "startBinding": null, @@ -945,7 +983,9 @@ exports[`Test Transform > should transform linear elements 2`] = ` ], "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": Any, "startArrowhead": "dot", "startBinding": null, @@ -993,7 +1033,9 @@ exports[`Test Transform > should transform linear elements 3`] = ` "polygon": false, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": Any, "startArrowhead": null, "startBinding": null, @@ -1041,7 +1083,9 @@ exports[`Test Transform > should transform linear elements 4`] = ` "polygon": false, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": Any, "startArrowhead": null, "startBinding": null, @@ -1076,7 +1120,9 @@ exports[`Test Transform > should transform regular shapes 1`] = ` "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": Any, "strokeColor": "#1e1e1e", "strokeStyle": "solid", @@ -1109,7 +1155,9 @@ exports[`Test Transform > should transform regular shapes 2`] = ` "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": Any, "strokeColor": "#1e1e1e", "strokeStyle": "solid", @@ -1142,7 +1190,9 @@ exports[`Test Transform > should transform regular shapes 3`] = ` "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": Any, "strokeColor": "#1e1e1e", "strokeStyle": "solid", @@ -1175,7 +1225,9 @@ exports[`Test Transform > should transform regular shapes 4`] = ` "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": Any, "strokeColor": "#1e1e1e", "strokeStyle": "solid", @@ -1208,7 +1260,9 @@ exports[`Test Transform > should transform regular shapes 5`] = ` "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": Any, "strokeColor": "#1e1e1e", "strokeStyle": "dotted", @@ -1241,7 +1295,9 @@ exports[`Test Transform > should transform regular shapes 6`] = ` "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": Any, "strokeColor": "#1971c2", "strokeStyle": "dashed", @@ -1280,7 +1336,9 @@ exports[`Test Transform > should transform text element 1`] = ` "originalText": "HELLO WORLD!", "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": Any, "strokeColor": "#1e1e1e", "strokeStyle": "solid", @@ -1322,7 +1380,9 @@ exports[`Test Transform > should transform text element 2`] = ` "originalText": "STYLED HELLO WORLD!", "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": Any, "strokeColor": "#5f3dc4", "strokeStyle": "solid", @@ -1369,7 +1429,9 @@ exports[`Test Transform > should transform the elements correctly when linear el "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": Any, "strokeColor": "#1e1e1e", "strokeStyle": "solid", @@ -1409,7 +1471,9 @@ exports[`Test Transform > should transform the elements correctly when linear el "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": Any, "strokeColor": "#1e1e1e", "strokeStyle": "solid", @@ -1453,7 +1517,9 @@ exports[`Test Transform > should transform the elements correctly when linear el "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": Any, "strokeColor": "#1e1e1e", "strokeStyle": "solid", @@ -1501,7 +1567,9 @@ exports[`Test Transform > should transform the elements correctly when linear el "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": Any, "strokeColor": "#1e1e1e", "strokeStyle": "solid", @@ -1561,7 +1629,9 @@ exports[`Test Transform > should transform the elements correctly when linear el "roundness": { "type": 2, }, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": Any, "startArrowhead": null, "startBinding": { @@ -1626,7 +1696,9 @@ exports[`Test Transform > should transform the elements correctly when linear el "roundness": { "type": 2, }, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": Any, "startArrowhead": null, "startBinding": { @@ -1676,7 +1748,9 @@ exports[`Test Transform > should transform the elements correctly when linear el "originalText": "B", "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": Any, "strokeColor": "#1e1e1e", "strokeStyle": "solid", @@ -1720,7 +1794,9 @@ exports[`Test Transform > should transform the elements correctly when linear el "originalText": "A", "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": Any, "strokeColor": "#1e1e1e", "strokeStyle": "solid", @@ -1764,7 +1840,9 @@ exports[`Test Transform > should transform the elements correctly when linear el "originalText": "Alice", "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": Any, "strokeColor": "#1e1e1e", "strokeStyle": "solid", @@ -1808,7 +1886,9 @@ exports[`Test Transform > should transform the elements correctly when linear el "originalText": "Bob", "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": Any, "strokeColor": "#1e1e1e", "strokeStyle": "solid", @@ -1850,7 +1930,9 @@ exports[`Test Transform > should transform the elements correctly when linear el "originalText": "How are you?", "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": Any, "strokeColor": "#1e1e1e", "strokeStyle": "solid", @@ -1892,7 +1974,9 @@ exports[`Test Transform > should transform the elements correctly when linear el "originalText": "Friendship", "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": Any, "strokeColor": "#1e1e1e", "strokeStyle": "solid", @@ -1946,7 +2030,9 @@ exports[`Test Transform > should transform to labelled arrows when label provide ], "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": Any, "startArrowhead": null, "startBinding": null, @@ -1999,7 +2085,9 @@ exports[`Test Transform > should transform to labelled arrows when label provide ], "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": Any, "startArrowhead": null, "startBinding": null, @@ -2052,7 +2140,9 @@ exports[`Test Transform > should transform to labelled arrows when label provide ], "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": Any, "startArrowhead": null, "startBinding": null, @@ -2105,7 +2195,9 @@ exports[`Test Transform > should transform to labelled arrows when label provide ], "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": Any, "startArrowhead": null, "startBinding": null, @@ -2146,7 +2238,9 @@ exports[`Test Transform > should transform to labelled arrows when label provide "originalText": "LABELED ARROW", "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": Any, "strokeColor": "#1e1e1e", "strokeStyle": "solid", @@ -2188,7 +2282,9 @@ exports[`Test Transform > should transform to labelled arrows when label provide "originalText": "STYLED LABELED ARROW", "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": Any, "strokeColor": "#099268", "strokeStyle": "solid", @@ -2230,7 +2326,9 @@ exports[`Test Transform > should transform to labelled arrows when label provide "originalText": "ANOTHER STYLED LABELLED ARROW", "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": Any, "strokeColor": "#1098ad", "strokeStyle": "solid", @@ -2273,7 +2371,9 @@ exports[`Test Transform > should transform to labelled arrows when label provide "originalText": "ANOTHER STYLED LABELLED ARROW", "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": Any, "strokeColor": "#099268", "strokeStyle": "solid", @@ -2315,7 +2415,9 @@ exports[`Test Transform > should transform to text containers when label provide "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": Any, "strokeColor": "#1e1e1e", "strokeStyle": "solid", @@ -2353,7 +2455,9 @@ exports[`Test Transform > should transform to text containers when label provide "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": Any, "strokeColor": "#1e1e1e", "strokeStyle": "solid", @@ -2391,7 +2495,9 @@ exports[`Test Transform > should transform to text containers when label provide "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": Any, "strokeColor": "#1e1e1e", "strokeStyle": "solid", @@ -2429,7 +2535,9 @@ exports[`Test Transform > should transform to text containers when label provide "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": Any, "strokeColor": "#1e1e1e", "strokeStyle": "solid", @@ -2467,7 +2575,9 @@ exports[`Test Transform > should transform to text containers when label provide "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": Any, "strokeColor": "#c2255c", "strokeStyle": "solid", @@ -2505,7 +2615,9 @@ exports[`Test Transform > should transform to text containers when label provide "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": Any, "strokeColor": "#f08c00", "strokeStyle": "solid", @@ -2544,7 +2656,9 @@ exports[`Test Transform > should transform to text containers when label provide "originalText": "RECTANGLE TEXT CONTAINER", "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": Any, "strokeColor": "#1e1e1e", "strokeStyle": "solid", @@ -2586,7 +2700,9 @@ exports[`Test Transform > should transform to text containers when label provide "originalText": "ELLIPSE TEXT CONTAINER", "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": Any, "strokeColor": "#1e1e1e", "strokeStyle": "solid", @@ -2630,7 +2746,9 @@ exports[`Test Transform > should transform to text containers when label provide TEXT CONTAINER", "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": Any, "strokeColor": "#1e1e1e", "strokeStyle": "solid", @@ -2674,7 +2792,9 @@ exports[`Test Transform > should transform to text containers when label provide "originalText": "STYLED DIAMOND TEXT CONTAINER", "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": Any, "strokeColor": "#099268", "strokeStyle": "solid", @@ -2717,7 +2837,9 @@ exports[`Test Transform > should transform to text containers when label provide "originalText": "TOP LEFT ALIGNED RECTANGLE TEXT CONTAINER", "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": Any, "strokeColor": "#c2255c", "strokeStyle": "solid", @@ -2761,7 +2883,9 @@ exports[`Test Transform > should transform to text containers when label provide "originalText": "STYLED ELLIPSE TEXT CONTAINER", "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": Any, "strokeColor": "#c2255c", "strokeStyle": "solid", diff --git a/packages/excalidraw/actions/actionProperties.test.tsx b/packages/excalidraw/actions/actionProperties.test.tsx index a84ceebc89..f339e214a3 100644 --- a/packages/excalidraw/actions/actionProperties.test.tsx +++ b/packages/excalidraw/actions/actionProperties.test.tsx @@ -6,6 +6,10 @@ import { FONT_FAMILY, STROKE_WIDTH, } from "@excalidraw/common"; +import { + CORE_FRAME_SCHEMA_TRACK, + CORE_SUPPORTED_TRACKS, +} from "@excalidraw/element"; import { Excalidraw } from "../index"; import { API } from "../tests/helpers/api"; @@ -196,6 +200,7 @@ describe("element locking", () => { it("should not update text background when changing background in mixed frame selection", () => { const frame = API.createElement({ type: "frame", + schemaState: { tracks: {} }, }); const text = API.createElement({ type: "text", @@ -215,6 +220,9 @@ describe("element locking", () => { expect(API.getElement(text).backgroundColor).toBe( COLOR_PALETTE.transparent, ); + expect( + API.getElement(frame).schemaState.tracks[CORE_FRAME_SCHEMA_TRACK], + ).toBe(CORE_SUPPORTED_TRACKS[CORE_FRAME_SCHEMA_TRACK]); }); it("should not update frame stroke width when changing stroke width in mixed selection", () => { diff --git a/packages/excalidraw/clipboard.test.ts b/packages/excalidraw/clipboard.test.ts index 2dfd342141..9fe4e38923 100644 --- a/packages/excalidraw/clipboard.test.ts +++ b/packages/excalidraw/clipboard.test.ts @@ -4,7 +4,6 @@ import { parseDataTransferEvent, serializeAsClipboardJSON, } from "./clipboard"; -import { SCHEMA_VERSIONS } from "./data/schema"; import { API } from "./tests/helpers/api"; describe("parseClipboard()", () => { @@ -59,7 +58,7 @@ describe("parseClipboard()", () => { expect.objectContaining({ id: rect.id, type: rect.type, - schemaVersion: SCHEMA_VERSIONS.latest, + schemaState: rect.schemaState, }), ]); }); @@ -84,7 +83,7 @@ describe("parseClipboard()", () => { expect.objectContaining({ id: rect.id, type: rect.type, - schemaVersion: SCHEMA_VERSIONS.latest, + schemaState: rect.schemaState, }), ]); // ------------------------------------------------------------------------- @@ -102,7 +101,7 @@ describe("parseClipboard()", () => { expect.objectContaining({ id: rect.id, type: rect.type, - schemaVersion: SCHEMA_VERSIONS.latest, + schemaState: rect.schemaState, }), ]); // ------------------------------------------------------------------------- @@ -127,15 +126,15 @@ describe("parseClipboard()", () => { expect(clipboardData.elements?.[0]).toEqual( expect.objectContaining({ id: rect.id, - schemaVersion: SCHEMA_VERSIONS.latest, + schemaState: rect.schemaState, }), ); }); it("should not upcast legacy elements to latest schema on clipboard serialize", async () => { const rect = API.createElement({ type: "rectangle" }); - const legacyRect = { ...rect } as typeof rect & { schemaVersion?: number }; - delete legacyRect.schemaVersion; + const legacyRect = { ...(rect as any) }; + delete legacyRect.schemaState; const clipboardPayload = JSON.parse( serializeAsClipboardJSON({ @@ -143,7 +142,7 @@ describe("parseClipboard()", () => { files: null, }), ); - expect(clipboardPayload.elements[0]).not.toHaveProperty("schemaVersion"); + expect(clipboardPayload.elements[0]).not.toHaveProperty("schemaState"); const clipboardData = await parseClipboard( await parseDataTransferEvent( @@ -155,7 +154,7 @@ describe("parseClipboard()", () => { ), ); - expect(clipboardData.elements?.[0]).not.toHaveProperty("schemaVersion"); + expect(clipboardData.elements?.[0]).not.toHaveProperty("schemaState"); }); it("should parse `src` urls out of text/html", async () => { diff --git a/packages/excalidraw/data/schema.test.ts b/packages/excalidraw/data/schema.test.ts index b33564ce40..ad4104f51b 100644 --- a/packages/excalidraw/data/schema.test.ts +++ b/packages/excalidraw/data/schema.test.ts @@ -3,11 +3,13 @@ import { DEFAULT_ELEMENT_PROPS } from "@excalidraw/common"; import { API } from "../tests/helpers/api"; import { + CORE_FRAME_SCHEMA_TRACK, type SchemaMigration, + CORE_SUPPORTED_TRACKS, migrateElements, - resolveSchemaVersion, + resolveTrackVersion, + SCHEMA_INITIAL_TRACK_VERSION, SCHEMA_MIGRATIONS, - SCHEMA_VERSIONS, validateSchemaMigrations, } from "./schema"; @@ -18,7 +20,7 @@ describe("schema migration", () => { type: "frame", backgroundColor: "#ffc9c9", }), - schemaVersion: undefined, + schemaState: { tracks: {} }, }; const migrated = migrateElements([frame])!; @@ -26,23 +28,31 @@ describe("schema migration", () => { expect(migrated[0].backgroundColor).toBe( DEFAULT_ELEMENT_PROPS.backgroundColor, ); - expect(migrated[0].schemaVersion).toBe(SCHEMA_VERSIONS.latest); + expect(migrated[0].schemaState.tracks[CORE_FRAME_SCHEMA_TRACK]).toBe( + CORE_SUPPORTED_TRACKS[CORE_FRAME_SCHEMA_TRACK], + ); }); - it("should keep latest-schema frame backgrounds unchanged", () => { - const frame = API.createElement({ - type: "frame", - backgroundColor: "#ffc9c9", - }); - const latestFrame = { - ...frame, - schemaVersion: SCHEMA_VERSIONS.latest, - } as typeof frame & { schemaVersion: number }; + it("should keep latest-track frame backgrounds unchanged", () => { + const frame = { + ...API.createElement({ + type: "frame", + backgroundColor: "#ffc9c9", + }), + schemaState: { + tracks: { + [CORE_FRAME_SCHEMA_TRACK]: + CORE_SUPPORTED_TRACKS[CORE_FRAME_SCHEMA_TRACK], + }, + }, + }; - const migrated = migrateElements([latestFrame])!; + const migrated = migrateElements([frame])!; expect(migrated[0].backgroundColor).toBe("#ffc9c9"); - expect(migrated[0].schemaVersion).toBe(SCHEMA_VERSIONS.latest); + expect(migrated[0].schemaState.tracks[CORE_FRAME_SCHEMA_TRACK]).toBe( + CORE_SUPPORTED_TRACKS[CORE_FRAME_SCHEMA_TRACK], + ); }); it("should normalize legacy frame backgrounds", () => { @@ -51,7 +61,11 @@ describe("schema migration", () => { type: "frame", backgroundColor: "#a5d8ff", }), - schemaVersion: undefined, + schemaState: { + tracks: { + [CORE_FRAME_SCHEMA_TRACK]: SCHEMA_INITIAL_TRACK_VERSION, + }, + }, }; const migrated = migrateElements([frame])!; @@ -60,10 +74,10 @@ describe("schema migration", () => { ); }); - it("should resolve invalid schema versions to initial", () => { - expect(resolveSchemaVersion(undefined)).toBe(SCHEMA_VERSIONS.initial); - expect(resolveSchemaVersion(0)).toBe(SCHEMA_VERSIONS.initial); - expect(resolveSchemaVersion(2)).toBe(2); + it("should resolve invalid track versions to initial", () => { + expect(resolveTrackVersion(undefined)).toBe(SCHEMA_INITIAL_TRACK_VERSION); + expect(resolveTrackVersion(0)).toBe(SCHEMA_INITIAL_TRACK_VERSION); + expect(resolveTrackVersion(2)).toBe(2); }); it("should have a valid migration registry configuration", () => { @@ -73,16 +87,34 @@ describe("schema migration", () => { it("should reject invalid migration metadata", () => { const invalidMigrations: SchemaMigration[] = [ { - version: 2.1, + id: "", + namespace: "core", + track: CORE_FRAME_SCHEMA_TRACK, + toVersion: 2.1, title: "", description: " ", - apply: (elements) => elements, + targetTypes: [], + apply: (element) => element, }, { - version: 2.1, + id: "dup", + namespace: "core", + track: CORE_FRAME_SCHEMA_TRACK, + toVersion: 2.1, title: "duplicate", description: "duplicate version", - apply: (elements) => elements, + targetTypes: ["frame"], + apply: (element) => element, + }, + { + id: "dup", + namespace: "core", + track: CORE_FRAME_SCHEMA_TRACK, + toVersion: 3, + title: "duplicate id", + description: "duplicate id", + targetTypes: ["frame"], + apply: (element) => element, }, ]; @@ -92,34 +124,62 @@ describe("schema migration", () => { expect(errors.join("\n")).toContain("integer version"); expect(errors.join("\n")).toContain("title must be non-empty"); expect(errors.join("\n")).toContain("non-empty description"); - expect(errors.join("\n")).toContain("Duplicate schema migration version"); + expect(errors.join("\n")).toContain("Duplicate schema migration id"); + expect(errors.join("\n")).toContain("at least one target type"); }); it("should reject versions at or below initial", () => { const errors = validateSchemaMigrations([ { - version: SCHEMA_VERSIONS.initial, + id: "invalid-start", + namespace: "core", + track: CORE_FRAME_SCHEMA_TRACK, + toVersion: SCHEMA_INITIAL_TRACK_VERSION, title: "invalid start", description: "bad version", - apply: (elements) => elements, + targetTypes: ["frame"], + apply: (element) => element, }, ]); - expect(errors.join("\n")).toContain("greater than schema initial version"); + expect(errors.join("\n")).toContain("must be greater than 1"); }); - it("should reject latest-version mismatch", () => { + it("should reject core track/version mismatch", () => { const errors = validateSchemaMigrations([ { - version: SCHEMA_VERSIONS.latest + 1, + id: "frame-v3", + namespace: "core", + track: CORE_FRAME_SCHEMA_TRACK, + toVersion: CORE_SUPPORTED_TRACKS[CORE_FRAME_SCHEMA_TRACK] + 1, title: "future migration", description: "future migration for test", - apply: (elements) => elements, + targetTypes: ["frame"], + apply: (element) => element, }, ]); expect(errors.join("\n")).toContain( - "SCHEMA_VERSIONS.latest (2) must match last migration version", + `Core supported track "${CORE_FRAME_SCHEMA_TRACK}" (${CORE_SUPPORTED_TRACKS[CORE_FRAME_SCHEMA_TRACK]}) must match last migration version`, + ); + }); + + it("should reject undeclared core tracks", () => { + const errors = validateSchemaMigrations([ + { + id: "unknown-core-track", + namespace: "core", + track: "excalidraw.shape.unknown", + toVersion: 2, + title: "unknown core track", + description: "should require supported-track declaration", + targetTypes: ["rectangle"], + apply: (element) => element, + }, + ]); + + expect(errors.join("\n")).toContain( + "must be declared in CORE_SUPPORTED_TRACKS", ); }); @@ -129,7 +189,7 @@ describe("schema migration", () => { type: "frame", backgroundColor: "#a5d8ff", }), - schemaVersion: undefined, + schemaState: { tracks: {} }, }; const withTempField = { ...frame, @@ -147,15 +207,20 @@ describe("schema migration", () => { ); }); - it("should use per-element schema hints", () => { + it("should use per-element track hints", () => { const frame = API.createElement({ type: "frame", backgroundColor: "#ff0000", }); const frameFromModernSource = { ...frame, - schemaVersion: SCHEMA_VERSIONS.latest, - } as typeof frame & { schemaVersion: number }; + schemaState: { + tracks: { + [CORE_FRAME_SCHEMA_TRACK]: + CORE_SUPPORTED_TRACKS[CORE_FRAME_SCHEMA_TRACK], + }, + }, + }; const migrated = migrateElements([frameFromModernSource])!; @@ -168,18 +233,23 @@ describe("schema migration", () => { type: "frame", backgroundColor: "#ff0000", }), - schemaVersion: undefined, + schemaState: { tracks: {} }, }; const modernFrame = API.createElement({ type: "frame", backgroundColor: "#00ff00", }); - const modernFrameWithHint = { + const modernFrameWithTrack = { ...modernFrame, - schemaVersion: SCHEMA_VERSIONS.latest, - } as typeof modernFrame & { schemaVersion: number }; + schemaState: { + tracks: { + [CORE_FRAME_SCHEMA_TRACK]: + CORE_SUPPORTED_TRACKS[CORE_FRAME_SCHEMA_TRACK], + }, + }, + }; - const migrated = migrateElements([legacyFrame, modernFrameWithHint])!; + const migrated = migrateElements([legacyFrame, modernFrameWithTrack])!; expect(migrated[0].backgroundColor).toBe( DEFAULT_ELEMENT_PROPS.backgroundColor, @@ -187,20 +257,43 @@ describe("schema migration", () => { expect(migrated[1].backgroundColor).toBe("#00ff00"); }); - it("should stamp schemaVersion to latest after migration", () => { - const rect = API.createElement({ type: "rectangle" }); - const migrated = migrateElements([rect])!; - expect(migrated[0].schemaVersion).toBe(SCHEMA_VERSIONS.latest); + it("should preserve higher-than-supported track versions", () => { + const frame = API.createElement({ + type: "frame", + backgroundColor: "#ff0000", + }); + const futureFrame = { + ...frame, + schemaState: { + tracks: { + [CORE_FRAME_SCHEMA_TRACK]: + CORE_SUPPORTED_TRACKS[CORE_FRAME_SCHEMA_TRACK] + 1, + }, + }, + }; + + const migrated = migrateElements([futureFrame])!; + expect(migrated[0].schemaState.tracks[CORE_FRAME_SCHEMA_TRACK]).toBe( + CORE_SUPPORTED_TRACKS[CORE_FRAME_SCHEMA_TRACK] + 1, + ); + expect(migrated[0].backgroundColor).toBe("#ff0000"); }); - it("should preserve higher-than-latest schema versions", () => { - const rect = API.createElement({ type: "rectangle" }); - const futureRect = { - ...rect, - schemaVersion: SCHEMA_VERSIONS.latest + 1, - } as typeof rect & { schemaVersion: number }; + it("should normalize invalid schema state and preserve unknown tracks", () => { + const rect = { + ...API.createElement({ type: "rectangle" }), + schemaState: { + tracks: { + "host.myapp.card": 4, + [CORE_FRAME_SCHEMA_TRACK]: 0, + }, + }, + }; - const migrated = migrateElements([futureRect])!; - expect(migrated[0].schemaVersion).toBe(SCHEMA_VERSIONS.latest + 1); + const migrated = migrateElements([rect])!; + expect(migrated[0].schemaState.tracks[CORE_FRAME_SCHEMA_TRACK]).toBe( + SCHEMA_INITIAL_TRACK_VERSION, + ); + expect(migrated[0].schemaState.tracks["host.myapp.card"]).toBe(4); }); }); diff --git a/packages/excalidraw/tests/__snapshots__/contextmenu.test.tsx.snap b/packages/excalidraw/tests/__snapshots__/contextmenu.test.tsx.snap index 6382ec5c80..9647d83c45 100644 --- a/packages/excalidraw/tests/__snapshots__/contextmenu.test.tsx.snap +++ b/packages/excalidraw/tests/__snapshots__/contextmenu.test.tsx.snap @@ -1020,7 +1020,9 @@ exports[`contextMenu element > right-clicking on a group should select whole gro "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": 1, "strokeColor": "#1e1e1e", "strokeStyle": "solid", @@ -1055,7 +1057,9 @@ exports[`contextMenu element > right-clicking on a group should select whole gro "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": 1, "strokeColor": "#1e1e1e", "strokeStyle": "solid", @@ -1218,7 +1222,9 @@ exports[`contextMenu element > selecting 'Add to library' in context menu adds e "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": 1278240551, "strokeColor": "#1e1e1e", "strokeStyle": "solid", @@ -1274,7 +1280,9 @@ exports[`contextMenu element > selecting 'Add to library' in context menu adds e "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 2, @@ -1435,7 +1443,9 @@ exports[`contextMenu element > selecting 'Bring forward' in context menu brings "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": 1014066025, "strokeColor": "#1e1e1e", "strokeStyle": "solid", @@ -1468,7 +1478,9 @@ exports[`contextMenu element > selecting 'Bring forward' in context menu brings "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": 1278240551, "strokeColor": "#1e1e1e", "strokeStyle": "solid", @@ -1524,7 +1536,9 @@ exports[`contextMenu element > selecting 'Bring forward' in context menu brings "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 2, @@ -1579,7 +1593,9 @@ exports[`contextMenu element > selecting 'Bring forward' in context menu brings "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 2, @@ -1621,10 +1637,16 @@ exports[`contextMenu element > selecting 'Bring forward' in context menu brings "id0": { "deleted": { "index": "a2", + "schemaState": { + "tracks": {}, + }, "version": 4, }, "inserted": { "index": "a0", + "schemaState": { + "tracks": {}, + }, "version": 3, }, }, @@ -1773,7 +1795,9 @@ exports[`contextMenu element > selecting 'Bring to front' in context menu brings "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": 1014066025, "strokeColor": "#1e1e1e", "strokeStyle": "solid", @@ -1806,7 +1830,9 @@ exports[`contextMenu element > selecting 'Bring to front' in context menu brings "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": 1278240551, "strokeColor": "#1e1e1e", "strokeStyle": "solid", @@ -1862,7 +1888,9 @@ exports[`contextMenu element > selecting 'Bring to front' in context menu brings "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 2, @@ -1917,7 +1945,9 @@ exports[`contextMenu element > selecting 'Bring to front' in context menu brings "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 2, @@ -1959,10 +1989,16 @@ exports[`contextMenu element > selecting 'Bring to front' in context menu brings "id0": { "deleted": { "index": "a2", + "schemaState": { + "tracks": {}, + }, "version": 4, }, "inserted": { "index": "a0", + "schemaState": { + "tracks": {}, + }, "version": 3, }, }, @@ -2113,7 +2149,9 @@ exports[`contextMenu element > selecting 'Copy styles' in context menu copies st "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": 1278240551, "strokeColor": "#1e1e1e", "strokeStyle": "solid", @@ -2169,7 +2207,9 @@ exports[`contextMenu element > selecting 'Copy styles' in context menu copies st "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 2, @@ -2328,7 +2368,9 @@ exports[`contextMenu element > selecting 'Delete' in context menu deletes elemen "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": 1278240551, "strokeColor": "#1e1e1e", "strokeStyle": "solid", @@ -2384,7 +2426,9 @@ exports[`contextMenu element > selecting 'Delete' in context menu deletes elemen "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 2, @@ -2422,10 +2466,16 @@ exports[`contextMenu element > selecting 'Delete' in context menu deletes elemen "id0": { "deleted": { "isDeleted": true, + "schemaState": { + "tracks": {}, + }, "version": 4, }, "inserted": { "isDeleted": false, + "schemaState": { + "tracks": {}, + }, "version": 3, }, }, @@ -2576,7 +2626,9 @@ exports[`contextMenu element > selecting 'Duplicate' in context menu duplicates "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": 1278240551, "strokeColor": "#1e1e1e", "strokeStyle": "solid", @@ -2609,7 +2661,9 @@ exports[`contextMenu element > selecting 'Duplicate' in context menu duplicates "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": 1014066025, "strokeColor": "#1e1e1e", "strokeStyle": "solid", @@ -2665,7 +2719,9 @@ exports[`contextMenu element > selecting 'Duplicate' in context menu duplicates "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 2, @@ -2720,7 +2776,9 @@ exports[`contextMenu element > selecting 'Duplicate' in context menu duplicates "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 2, @@ -2888,7 +2946,9 @@ exports[`contextMenu element > selecting 'Group selection' in context menu group "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": 1278240551, "strokeColor": "#1e1e1e", "strokeStyle": "solid", @@ -2923,7 +2983,9 @@ exports[`contextMenu element > selecting 'Group selection' in context menu group "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": 1014066025, "strokeColor": "#1e1e1e", "strokeStyle": "solid", @@ -2979,7 +3041,9 @@ exports[`contextMenu element > selecting 'Group selection' in context menu group "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 2, @@ -3034,7 +3098,9 @@ exports[`contextMenu element > selecting 'Group selection' in context menu group "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 2, @@ -3096,10 +3162,16 @@ exports[`contextMenu element > selecting 'Group selection' in context menu group "groupIds": [ "id9", ], + "schemaState": { + "tracks": {}, + }, "version": 4, }, "inserted": { "groupIds": [], + "schemaState": { + "tracks": {}, + }, "version": 3, }, }, @@ -3108,10 +3180,16 @@ exports[`contextMenu element > selecting 'Group selection' in context menu group "groupIds": [ "id9", ], + "schemaState": { + "tracks": {}, + }, "version": 4, }, "inserted": { "groupIds": [], + "schemaState": { + "tracks": {}, + }, "version": 3, }, }, @@ -3262,7 +3340,9 @@ exports[`contextMenu element > selecting 'Paste styles' in context menu pastes s "opacity": 60, "roughness": 2, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": 1278240551, "strokeColor": "#e03131", "strokeStyle": "dotted", @@ -3295,7 +3375,9 @@ exports[`contextMenu element > selecting 'Paste styles' in context menu pastes s "opacity": 60, "roughness": 2, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": 1898319239, "strokeColor": "#e03131", "strokeStyle": "dotted", @@ -3351,7 +3433,9 @@ exports[`contextMenu element > selecting 'Paste styles' in context menu pastes s "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 2, @@ -3406,7 +3490,9 @@ exports[`contextMenu element > selecting 'Paste styles' in context menu pastes s "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 2, @@ -3439,10 +3525,16 @@ exports[`contextMenu element > selecting 'Paste styles' in context menu pastes s "updated": { "id3": { "deleted": { + "schemaState": { + "tracks": {}, + }, "strokeColor": "#e03131", "version": 4, }, "inserted": { + "schemaState": { + "tracks": {}, + }, "strokeColor": "#1e1e1e", "version": 3, }, @@ -3465,10 +3557,16 @@ exports[`contextMenu element > selecting 'Paste styles' in context menu pastes s "id3": { "deleted": { "backgroundColor": "#a5d8ff", + "schemaState": { + "tracks": {}, + }, "version": 5, }, "inserted": { "backgroundColor": "transparent", + "schemaState": { + "tracks": {}, + }, "version": 4, }, }, @@ -3490,10 +3588,16 @@ exports[`contextMenu element > selecting 'Paste styles' in context menu pastes s "id3": { "deleted": { "fillStyle": "cross-hatch", + "schemaState": { + "tracks": {}, + }, "version": 6, }, "inserted": { "fillStyle": "solid", + "schemaState": { + "tracks": {}, + }, "version": 5, }, }, @@ -3514,10 +3618,16 @@ exports[`contextMenu element > selecting 'Paste styles' in context menu pastes s "updated": { "id3": { "deleted": { + "schemaState": { + "tracks": {}, + }, "strokeStyle": "dotted", "version": 7, }, "inserted": { + "schemaState": { + "tracks": {}, + }, "strokeStyle": "solid", "version": 6, }, @@ -3540,10 +3650,16 @@ exports[`contextMenu element > selecting 'Paste styles' in context menu pastes s "id3": { "deleted": { "roughness": 2, + "schemaState": { + "tracks": {}, + }, "version": 8, }, "inserted": { "roughness": 1, + "schemaState": { + "tracks": {}, + }, "version": 7, }, }, @@ -3565,10 +3681,16 @@ exports[`contextMenu element > selecting 'Paste styles' in context menu pastes s "id3": { "deleted": { "opacity": 60, + "schemaState": { + "tracks": {}, + }, "version": 9, }, "inserted": { "opacity": 100, + "schemaState": { + "tracks": {}, + }, "version": 8, }, }, @@ -3601,6 +3723,9 @@ exports[`contextMenu element > selecting 'Paste styles' in context menu pastes s "fillStyle": "cross-hatch", "opacity": 60, "roughness": 2, + "schemaState": { + "tracks": {}, + }, "strokeColor": "#e03131", "strokeStyle": "dotted", "version": 4, @@ -3610,6 +3735,9 @@ exports[`contextMenu element > selecting 'Paste styles' in context menu pastes s "fillStyle": "solid", "opacity": 100, "roughness": 1, + "schemaState": { + "tracks": {}, + }, "strokeColor": "#1e1e1e", "strokeStyle": "solid", "version": 3, @@ -3760,7 +3888,9 @@ exports[`contextMenu element > selecting 'Send backward' in context menu sends e "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": 238820263, "strokeColor": "#1e1e1e", "strokeStyle": "solid", @@ -3793,7 +3923,9 @@ exports[`contextMenu element > selecting 'Send backward' in context menu sends e "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": 1278240551, "strokeColor": "#1e1e1e", "strokeStyle": "solid", @@ -3849,7 +3981,9 @@ exports[`contextMenu element > selecting 'Send backward' in context menu sends e "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 2, @@ -3904,7 +4038,9 @@ exports[`contextMenu element > selecting 'Send backward' in context menu sends e "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 2, @@ -3938,10 +4074,16 @@ exports[`contextMenu element > selecting 'Send backward' in context menu sends e "id3": { "deleted": { "index": "Zz", + "schemaState": { + "tracks": {}, + }, "version": 4, }, "inserted": { "index": "a1", + "schemaState": { + "tracks": {}, + }, "version": 3, }, }, @@ -4090,7 +4232,9 @@ exports[`contextMenu element > selecting 'Send to back' in context menu sends el "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": 1014066025, "strokeColor": "#1e1e1e", "strokeStyle": "solid", @@ -4123,7 +4267,9 @@ exports[`contextMenu element > selecting 'Send to back' in context menu sends el "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": 1278240551, "strokeColor": "#1e1e1e", "strokeStyle": "solid", @@ -4179,7 +4325,9 @@ exports[`contextMenu element > selecting 'Send to back' in context menu sends el "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 2, @@ -4234,7 +4382,9 @@ exports[`contextMenu element > selecting 'Send to back' in context menu sends el "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 2, @@ -4268,10 +4418,16 @@ exports[`contextMenu element > selecting 'Send to back' in context menu sends el "id3": { "deleted": { "index": "Zz", + "schemaState": { + "tracks": {}, + }, "version": 4, }, "inserted": { "index": "a1", + "schemaState": { + "tracks": {}, + }, "version": 3, }, }, @@ -4423,7 +4579,9 @@ exports[`contextMenu element > selecting 'Ungroup selection' in context menu ung "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": 1278240551, "strokeColor": "#1e1e1e", "strokeStyle": "solid", @@ -4456,7 +4614,9 @@ exports[`contextMenu element > selecting 'Ungroup selection' in context menu ung "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": 238820263, "strokeColor": "#1e1e1e", "strokeStyle": "solid", @@ -4512,7 +4672,9 @@ exports[`contextMenu element > selecting 'Ungroup selection' in context menu ung "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 2, @@ -4567,7 +4729,9 @@ exports[`contextMenu element > selecting 'Ungroup selection' in context menu ung "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 2, @@ -4629,10 +4793,16 @@ exports[`contextMenu element > selecting 'Ungroup selection' in context menu ung "groupIds": [ "id9", ], + "schemaState": { + "tracks": {}, + }, "version": 4, }, "inserted": { "groupIds": [], + "schemaState": { + "tracks": {}, + }, "version": 3, }, }, @@ -4641,10 +4811,16 @@ exports[`contextMenu element > selecting 'Ungroup selection' in context menu ung "groupIds": [ "id9", ], + "schemaState": { + "tracks": {}, + }, "version": 4, }, "inserted": { "groupIds": [], + "schemaState": { + "tracks": {}, + }, "version": 3, }, }, @@ -4672,24 +4848,36 @@ exports[`contextMenu element > selecting 'Ungroup selection' in context menu ung "id0": { "deleted": { "groupIds": [], + "schemaState": { + "tracks": {}, + }, "version": 5, }, "inserted": { "groupIds": [ "id9", ], + "schemaState": { + "tracks": {}, + }, "version": 4, }, }, "id3": { "deleted": { "groupIds": [], + "schemaState": { + "tracks": {}, + }, "version": 5, }, "inserted": { "groupIds": [ "id9", ], + "schemaState": { + "tracks": {}, + }, "version": 4, }, }, @@ -5715,7 +5903,9 @@ exports[`contextMenu element > shows 'Group selection' in context menu for multi "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": 1278240551, "strokeColor": "#1e1e1e", "strokeStyle": "solid", @@ -5748,7 +5938,9 @@ exports[`contextMenu element > shows 'Group selection' in context menu for multi "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": 400692809, "strokeColor": "#1e1e1e", "strokeStyle": "solid", @@ -5804,7 +5996,9 @@ exports[`contextMenu element > shows 'Group selection' in context menu for multi "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 2, @@ -5859,7 +6053,9 @@ exports[`contextMenu element > shows 'Group selection' in context menu for multi "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 2, @@ -6943,7 +7139,9 @@ exports[`contextMenu element > shows 'Ungroup selection' in context menu for gro "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": 1278240551, "strokeColor": "#1e1e1e", "strokeStyle": "solid", @@ -6978,7 +7176,9 @@ exports[`contextMenu element > shows 'Ungroup selection' in context menu for gro "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": 238820263, "strokeColor": "#1e1e1e", "strokeStyle": "solid", @@ -7034,7 +7234,9 @@ exports[`contextMenu element > shows 'Ungroup selection' in context menu for gro "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 2, @@ -7089,7 +7291,9 @@ exports[`contextMenu element > shows 'Ungroup selection' in context menu for gro "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 2, @@ -7173,10 +7377,16 @@ exports[`contextMenu element > shows 'Ungroup selection' in context menu for gro "groupIds": [ "id12", ], + "schemaState": { + "tracks": {}, + }, "version": 4, }, "inserted": { "groupIds": [], + "schemaState": { + "tracks": {}, + }, "version": 3, }, }, @@ -7185,10 +7395,16 @@ exports[`contextMenu element > shows 'Ungroup selection' in context menu for gro "groupIds": [ "id12", ], + "schemaState": { + "tracks": {}, + }, "version": 4, }, "inserted": { "groupIds": [], + "schemaState": { + "tracks": {}, + }, "version": 3, }, }, @@ -9878,7 +10094,9 @@ exports[`contextMenu element > shows context menu for element > [end of test] el "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": 1278240551, "strokeColor": "#1e1e1e", "strokeStyle": "solid", @@ -9911,7 +10129,9 @@ exports[`contextMenu element > shows context menu for element > [end of test] el "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": 1, "strokeColor": "#1e1e1e", "strokeStyle": "solid", @@ -9944,7 +10164,9 @@ exports[`contextMenu element > shows context menu for element > [end of test] el "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": 1, "strokeColor": "#1e1e1e", "strokeStyle": "solid", @@ -10006,7 +10228,9 @@ exports[`contextMenu element > shows context menu for element > [end of test] un "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 2, diff --git a/packages/excalidraw/tests/__snapshots__/dragCreate.test.tsx.snap b/packages/excalidraw/tests/__snapshots__/dragCreate.test.tsx.snap index e363d6330e..5b98012988 100644 --- a/packages/excalidraw/tests/__snapshots__/dragCreate.test.tsx.snap +++ b/packages/excalidraw/tests/__snapshots__/dragCreate.test.tsx.snap @@ -35,7 +35,9 @@ exports[`Test dragCreate > add element to the scene when pointer dragging long e "roundness": { "type": 2, }, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": 1278240551, "startArrowhead": null, "startBinding": null, @@ -72,7 +74,9 @@ exports[`Test dragCreate > add element to the scene when pointer dragging long e "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": 1278240551, "strokeColor": "#1e1e1e", "strokeStyle": "solid", @@ -107,7 +111,9 @@ exports[`Test dragCreate > add element to the scene when pointer dragging long e "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": 1278240551, "strokeColor": "#1e1e1e", "strokeStyle": "solid", @@ -153,7 +159,9 @@ exports[`Test dragCreate > add element to the scene when pointer dragging long e "polygon": false, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": 1278240551, "startArrowhead": null, "startBinding": null, @@ -190,7 +198,9 @@ exports[`Test dragCreate > add element to the scene when pointer dragging long e "opacity": 100, "roughness": 1, "roundness": null, - "schemaVersion": 2, + "schemaState": { + "tracks": {}, + }, "seed": 1278240551, "strokeColor": "#1e1e1e", "strokeStyle": "solid", diff --git a/packages/excalidraw/tests/__snapshots__/export.test.tsx.snap b/packages/excalidraw/tests/__snapshots__/export.test.tsx.snap index 166fd59fcf..fe9f78fb1f 100644 --- a/packages/excalidraw/tests/__snapshots__/export.test.tsx.snap +++ b/packages/excalidraw/tests/__snapshots__/export.test.tsx.snap @@ -1,7 +1,7 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html exports[`export > export svg-embedded scene > svg-embdedded scene export output 1`] = ` -"eyJ2ZXJzaW9uIjoiMSIsImVuY29kaW5nIjoiYnN0cmluZyIsImNvbXByZXNzZWQiOnRydWUsImVuY29kZWQiOiJ4nHVTwW7bMFxmvfcrXGb3WqxOiu6QW7t1WFx1MDAwZu2hXHUwMDE51sPQg2oxNlx1MDAxMUVcdTAwMTIkuklcdTAwMTZcdTAwMDTYZ/S2X9wnjFI8K3K7XHUwMDA0MKBHUnx8fNqdXHUwMDE0RUlbXHUwMDBi5awoYVNcdTAwMGKF0ol1eVx1MDAxNvBcdTAwMTdwXHUwMDFljebQNJ696VxcXHUwMDFkM1tcIjs7P1eGXHUwMDBiWuNpdlFV1aFcYlx1MDAxNKxAk+e0XHUwMDFmfC6KXfxyXHUwMDA0ZSi9imlcdTAwMTH415dgQ1x03TBUXHKnbXZao6SWkcnHXHUwMDAxalx1MDAwMZuWckzoRkFW6MmZJXwyyrjQ8XRcdTAwMDLhn5o+i3rZONNpOeSQXHUwMDEz2lvheJiUt0Cl5rSNt7NcdTAwMWWsVjnq8dhTnI7w/1Vx06bV4INgk1x1MDAwMTVW1Ehh+EmVplxiXGbtrYzaPiVOTqzgNoirO6VcdTAwMDZcdTAwMTi1hM1cdTAwMTiMI/bdsoBcdTAwMDeQXHUwMDE5g7T8hPm6hZX4ntviOPve6DpcdTAwMTdcdTAwMWX9Z3ZcdTAwMDTFy1x1MDAxN0J5SJJcdTAwMDcqN8ktXHUwMDE5nc5KQSNGXG71cpzHXHUwMDBlXFy+c3d0XHUwMDE0a/3n9+uvo+VcdTAwMTlNc/xcdTAwMTlcYk6rXGb9XCJWqILal9lcdTAwMTVXXG6bMGepYHFkXHUwMDAyXHUwMDFllpCdP4TJ2Fx1MDAxNK35PoFcdTAwMWHc25VcdTAwMTiHXHJqob69S090ZFx1MDAxZcBcdTAwMWZcYpLr4Hhy+Dr4/MP0Mlx1MDAwNvb8jS4ohbVzYr04enht7Fx1MDAxNJSjUVx1MDAwZlx1MDAxOIFNY0bozki40eJZjXUsX1x1MDAxMNbXb1x1MDAxZsbpXCL+euL9XG7uOkU451XXxD5cYvvcXHUwMDA1fvvIj19ccvTQ/i+oli93In0=