| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| import { describe, it, expect } from "vitest"; |
| import * as Y from "yjs"; |
| import { createEmbedStore } from "../src/editor/embeds/embed-store"; |
|
|
| function makeStore() { |
| const ydoc = new Y.Doc(); |
| return { ydoc, store: createEmbedStore(ydoc) }; |
| } |
|
|
| describe("embed-store — basic CRUD", () => { |
| it("get returns empty string when key missing", () => { |
| const { store } = makeStore(); |
| expect(store.get("nope.html")).toBe(""); |
| expect(store.has("nope.html")).toBe(false); |
| }); |
|
|
| it("set + get round-trips html content", () => { |
| const { store } = makeStore(); |
| store.set("chart.html", "<div>hi</div>"); |
| expect(store.get("chart.html")).toBe("<div>hi</div>"); |
| expect(store.has("chart.html")).toBe(true); |
| }); |
|
|
| it("remove deletes the entry", () => { |
| const { store } = makeStore(); |
| store.set("chart.html", "<div/>"); |
| store.remove("chart.html"); |
| expect(store.has("chart.html")).toBe(false); |
| expect(store.get("chart.html")).toBe(""); |
| }); |
|
|
| it("keys returns all inserted keys", () => { |
| const { store } = makeStore(); |
| store.set("a.html", "A"); |
| store.set("b.html", "B"); |
| expect(store.keys().sort()).toEqual(["a.html", "b.html"]); |
| }); |
|
|
| it("getAll returns a plain object snapshot", () => { |
| const { store } = makeStore(); |
| store.set("a.html", "A"); |
| store.set("b.html", "B"); |
| expect(store.getAll()).toEqual({ "a.html": "A", "b.html": "B" }); |
| }); |
| }); |
|
|
| describe("embed-store — rename", () => { |
| it("moves content to the new key and deletes the old one", () => { |
| const { store } = makeStore(); |
| store.set("old.html", "<svg/>"); |
| store.rename("old.html", "new.html"); |
| expect(store.has("old.html")).toBe(false); |
| expect(store.get("new.html")).toBe("<svg/>"); |
| }); |
|
|
| it("is a no-op when the source key does not exist", () => { |
| const { store } = makeStore(); |
| store.rename("missing.html", "target.html"); |
| expect(store.has("target.html")).toBe(false); |
| }); |
| }); |
|
|
| describe("embed-store — patch", () => { |
| it("returns false and does nothing when search text is missing", () => { |
| const { store } = makeStore(); |
| store.set("chart.html", "<div>hello</div>"); |
| expect(store.patch("chart.html", "notfound", "bye")).toBe(false); |
| expect(store.get("chart.html")).toBe("<div>hello</div>"); |
| }); |
|
|
| it("replaces first occurrence when search text is present", () => { |
| const { store } = makeStore(); |
| store.set("chart.html", "<div>hello hello</div>"); |
| const ok = store.patch("chart.html", "hello", "bye"); |
| expect(ok).toBe(true); |
| expect(store.get("chart.html")).toBe("<div>bye hello</div>"); |
| }); |
|
|
| it("returns false for missing keys", () => { |
| const { store } = makeStore(); |
| expect(store.patch("missing.html", "a", "b")).toBe(false); |
| }); |
| }); |
|
|
| describe("embed-store — observe", () => { |
| it("observe() fires on any change", () => { |
| const { store } = makeStore(); |
| let count = 0; |
| const unsub = store.observe(() => { count++; }); |
| store.set("a.html", "A"); |
| store.set("b.html", "B"); |
| expect(count).toBe(2); |
| unsub(); |
| store.set("c.html", "C"); |
| expect(count).toBe(2); |
| }); |
|
|
| it("observeKey() only fires for the matching key", () => { |
| const { store } = makeStore(); |
| const aCalls: string[] = []; |
| const unsub = store.observeKey("a.html", (html) => { aCalls.push(html); }); |
| store.set("a.html", "A1"); |
| store.set("b.html", "B1"); |
| store.set("a.html", "A2"); |
| expect(aCalls).toEqual(["A1", "A2"]); |
| unsub(); |
| }); |
| }); |
|
|
| describe("embed-store — collaboration", () => { |
| it("concurrent sets on different keys merge correctly", () => { |
| const docA = new Y.Doc(); |
| const docB = new Y.Doc(); |
| const storeA = createEmbedStore(docA); |
| const storeB = createEmbedStore(docB); |
|
|
| storeA.set("a.html", "<A/>"); |
| storeB.set("b.html", "<B/>"); |
|
|
| Y.applyUpdate(docA, Y.encodeStateAsUpdate(docB)); |
| Y.applyUpdate(docB, Y.encodeStateAsUpdate(docA)); |
|
|
| expect(storeA.getAll()).toEqual({ "a.html": "<A/>", "b.html": "<B/>" }); |
| expect(storeB.getAll()).toEqual({ "a.html": "<A/>", "b.html": "<B/>" }); |
| }); |
| }); |
|
|