changeset.test.ts
1import { expect, test } from "vitest";
2import * as Y from "yjs";
3import { Changeset } from "./changeset";
4import {
5 getByTypeAndAttr,
6 MAIN_DOCUMENT,
7 queryByType,
8 queryByTypeAndAttr,
9} from "./filter.ts";
10
11const makeDoc = (...elems: Array<Y.XmlText | Y.XmlElement>): Y.Doc => {
12 const doc = new Y.Doc();
13 const array = doc.getArray(MAIN_DOCUMENT);
14 array.insert(0, elems);
15 return doc;
16};
17
18const paragraph = (...elems: Array<Y.XmlElement | Y.XmlText>): Y.XmlElement => {
19 const p = new Y.XmlElement("paragraph");
20 p.insert(0, elems);
21 return p;
22};
23
24const text = (s: string): Y.XmlText => {
25 const e = new Y.XmlText();
26 e.insert(0, s);
27 return e;
28};
29
30const waypoint = (attrs: Record<string, string> = {}): Y.XmlElement => {
31 const e = new Y.XmlElement("waypoint");
32 for (const [key, value] of Object.entries(attrs)) {
33 e.setAttribute(key, value);
34 }
35 return e;
36};
37
38test("it can apply a changeset", () => {
39 const cs = new Changeset();
40 const doc = makeDoc(
41 paragraph(text("test")),
42 paragraph(waypoint({ id: "1" })),
43 );
44 const elem = getByTypeAndAttr("waypoint", ["id", "1"], doc).unwrapOr(null);
45 cs.updateAttributes(elem, { test: "yes" });
46 const result = cs.apply(doc);
47 expect(result.isOk()).toBe(true);
48
49 const updatedElem = getByTypeAndAttr("waypoint", ["id", "1"], doc).unwrapOr(
50 null,
51 );
52 expect(updatedElem.getAttribute("test")).toBe("yes");
53});
54
55test("it can insert before and update text", () => {
56 const cs = new Changeset();
57 const doc = makeDoc(
58 paragraph(text("test")),
59 paragraph(waypoint({ id: "1" })),
60 );
61 const elem = getByTypeAndAttr("waypoint", ["id", "1"], doc).unwrapOr(null);
62 cs.insertBefore(elem, text("inserted text"));
63 const result = cs.apply(doc);
64 expect(result.isOk()).toBe(true);
65
66 const updatedPs = queryByType("paragraph", doc);
67 expect(updatedPs.length).toBe(2);
68 expect(updatedPs[1].toString()).toBe(
69 '<paragraph>inserted text<waypoint id="1"></waypoint></paragraph>',
70 );
71
72 const cs2 = new Changeset();
73 cs2.appendText(" again", elem.prevSibling);
74 cs2.apply(doc);
75 expect(updatedPs[1].toString()).toBe(
76 '<paragraph>inserted text again<waypoint id="1"></waypoint></paragraph>',
77 );
78
79 const cs3 = new Changeset();
80 cs3.prependText("again ", elem.prevSibling);
81 cs3.apply(doc);
82 expect(updatedPs[1].toString()).toBe(
83 '<paragraph>again inserted text again<waypoint id="1"></waypoint></paragraph>',
84 );
85});
86
87test("it can insert after", () => {
88 const cs = new Changeset();
89 const doc = makeDoc(
90 paragraph(text("test")),
91 paragraph(waypoint({ id: "1" })),
92 );
93 const elem = getByTypeAndAttr("waypoint", ["id", "1"], doc).unwrapOr(null);
94 cs.insertAfter(elem, text("inserted text"));
95 const result = cs.apply(doc);
96 expect(result.isOk()).toBe(true);
97
98 const updatedPs = queryByType("paragraph", doc);
99 expect(updatedPs.length).toBe(2);
100 expect(updatedPs[1].toString()).toBe(
101 '<paragraph><waypoint id="1"></waypoint>inserted text</paragraph>',
102 );
103});
104
105test("it can insert paragraphs after", () => {
106 const cs = new Changeset();
107 const doc = makeDoc(paragraph(text("1")), paragraph(text("2")));
108 const paras = queryByType("paragraph", doc);
109 cs.insertAfter(paras[0], paragraph(text("1.5")));
110 const result = cs.apply(doc);
111 expect(result.isOk()).toBe(true);
112
113 const updatedPs = queryByType("paragraph", doc);
114 expect(updatedPs.length).toBe(3);
115 expect(updatedPs[1].toString()).toBe("<paragraph>1.5</paragraph>");
116});
117
118test("it can insert paragraphs before", () => {
119 const cs = new Changeset();
120 const doc = makeDoc(paragraph(text("1")), paragraph(text("2")));
121 const paras = queryByType("paragraph", doc);
122 cs.insertBefore(paras[0], paragraph(text("0")));
123 const result = cs.apply(doc);
124 expect(result.isOk()).toBe(true);
125
126 const updatedPs = queryByType("paragraph", doc);
127 expect(updatedPs.length).toBe(3);
128 expect(updatedPs[0].toString()).toBe("<paragraph>0</paragraph>");
129});