@@ -28,6 +28,60 @@ function setupTwoWaySync(doc1: Y.Doc, doc2: Y.Doc) {
2828}
2929
3030describe ( "RelativePositionMapping (yjs)" , ( ) => {
31+ it ( "should return the same position when no changes are made" , ( ) => {
32+ const ydoc = new Y . Doc ( ) ;
33+ const remoteYdoc = new Y . Doc ( ) ;
34+
35+ const localEditor = BlockNoteEditor . create (
36+ withCollaboration ( {
37+ collaboration : {
38+ fragment : ydoc . getXmlFragment ( "doc" ) ,
39+ user : { color : "#ff0000" , name : "Local User" } ,
40+ provider : undefined ,
41+ } ,
42+ } ) ,
43+ ) ;
44+ const div = document . createElement ( "div" ) ;
45+ localEditor . mount ( div ) ;
46+
47+ const remoteEditor = BlockNoteEditor . create (
48+ withCollaboration ( {
49+ collaboration : {
50+ fragment : remoteYdoc . getXmlFragment ( "doc" ) ,
51+ user : { color : "#ff0000" , name : "Remote User" } ,
52+ provider : undefined ,
53+ } ,
54+ } ) ,
55+ ) ;
56+
57+ const remoteDiv = document . createElement ( "div" ) ;
58+ remoteEditor . mount ( remoteDiv ) ;
59+ setupTwoWaySync ( ydoc , remoteYdoc ) ;
60+
61+ const nodeSize = localEditor . prosemirrorState . doc . nodeSize ;
62+ const positions : number [ ] = [ ] ;
63+ for ( let i = 0 ; i < nodeSize ; i ++ ) {
64+ positions . push ( trackPosition ( localEditor , i ) ( ) ) ;
65+ }
66+
67+ expect ( positions ) . toMatchInlineSnapshot ( `
68+ [
69+ 0,
70+ 1,
71+ 2,
72+ 3,
73+ 4,
74+ 5,
75+ 6,
76+ 7,
77+ ]
78+ ` ) ;
79+
80+ ydoc . destroy ( ) ;
81+ remoteYdoc . destroy ( ) ;
82+ localEditor . unmount ( ) ;
83+ remoteEditor . unmount ( ) ;
84+ } ) ;
3185 it ( "should update the local position when collaborating" , ( ) => {
3286 const ydoc = new Y . Doc ( ) ;
3387 const remoteYdoc = new Y . Doc ( ) ;
@@ -92,6 +146,80 @@ describe("RelativePositionMapping (yjs)", () => {
92146 remoteEditor . unmount ( ) ;
93147 } ) ;
94148
149+ it ( "should match the same positions" , ( ) => {
150+ const ydoc = new Y . Doc ( ) ;
151+ const remoteYdoc = new Y . Doc ( ) ;
152+
153+ const localEditor = BlockNoteEditor . create (
154+ withCollaboration ( {
155+ collaboration : {
156+ fragment : ydoc . getXmlFragment ( "doc" ) ,
157+ user : { color : "#ff0000" , name : "Local User" } ,
158+ provider : undefined ,
159+ } ,
160+ } ) ,
161+ ) ;
162+ const div = document . createElement ( "div" ) ;
163+ localEditor . mount ( div ) ;
164+
165+ const remoteEditor = BlockNoteEditor . create (
166+ withCollaboration ( {
167+ collaboration : {
168+ fragment : remoteYdoc . getXmlFragment ( "doc" ) ,
169+ user : { color : "#ff0000" , name : "Remote User" } ,
170+ provider : undefined ,
171+ } ,
172+ } ) ,
173+ ) ;
174+
175+ const remoteDiv = document . createElement ( "div" ) ;
176+ remoteEditor . mount ( remoteDiv ) ;
177+ setupTwoWaySync ( ydoc , remoteYdoc ) ;
178+
179+ localEditor . replaceBlocks ( localEditor . document , [
180+ {
181+ type : "paragraph" ,
182+ content : "Hello World" ,
183+ } ,
184+ ] ) ;
185+
186+ const nodeSize = localEditor . prosemirrorState . doc . nodeSize ;
187+ const positions : ( ( ) => number ) [ ] = [ ] ;
188+ for ( let i = 0 ; i < nodeSize ; i ++ ) {
189+ positions . push ( trackPosition ( localEditor , i ) ) ;
190+ }
191+
192+ localEditor . _tiptapEditor . commands . insertContentAt ( 3 , "Test " ) ;
193+
194+ expect ( positions . map ( ( getPos ) => getPos ( ) ) ) . toMatchInlineSnapshot ( `
195+ [
196+ 0,
197+ 1,
198+ 2,
199+ 3,
200+ 9,
201+ 10,
202+ 11,
203+ 12,
204+ 13,
205+ 14,
206+ 15,
207+ 16,
208+ 17,
209+ 18,
210+ 19,
211+ 20,
212+ 21,
213+ 22,
214+ 23,
215+ ]
216+ ` ) ;
217+ ydoc . destroy ( ) ;
218+ remoteYdoc . destroy ( ) ;
219+ localEditor . unmount ( ) ;
220+ remoteEditor . unmount ( ) ;
221+ } ) ;
222+
95223 it ( "should handle multiple transactions when collaborating" , ( ) => {
96224 const ydoc = new Y . Doc ( ) ;
97225 const remoteYdoc = new Y . Doc ( ) ;
@@ -208,8 +336,8 @@ describe("RelativePositionMapping (yjs)", () => {
208336 // Store position at "H|ello World" (but on the right side)
209337 const getPosAfterRightPos = trackPosition ( localEditor , 4 , "right" ) ;
210338
211- // Insert text at the beginning
212- localEditor . _tiptapEditor . commands . insertContentAt ( 3 , "Test " ) ;
339+ // Insert text at the beginning (via remote editor to exercise remote-origin updates)
340+ remoteEditor . _tiptapEditor . commands . insertContentAt ( 3 , "Test " ) ;
213341
214342 // Position should be updated
215343 expect ( getCursorPos ( ) ) . toBe ( 11 ) ; // 6 + 5 ("Test " length)
0 commit comments