@@ -3,6 +3,7 @@ import { resolve, dirname } from 'node:path';
33import { fileURLToPath } from 'node:url' ;
44import { afterEach , beforeAll , describe , expect , it , vi } from 'vitest' ;
55import { Doc as YDoc } from 'yjs' ;
6+ import { yXmlFragmentToProseMirrorRootNode } from 'y-prosemirror' ;
67
78const { seedPartsFromEditorSpy } = vi . hoisted ( ( ) => ( {
89 seedPartsFromEditorSpy : vi . fn ( ) ,
@@ -33,6 +34,13 @@ function createProviderStub() {
3334 } ;
3435
3536 const provider = {
37+ awareness : {
38+ getStates ( ) {
39+ return new Map ( ) ;
40+ } ,
41+ on ( ) { } ,
42+ off ( ) { } ,
43+ } ,
3644 synced : false ,
3745 isSynced : false ,
3846 on ( event : 'sync' | 'synced' , handler : SyncHandler ) {
@@ -64,11 +72,13 @@ function createTestEditor(options: Partial<Parameters<(typeof Editor)['prototype
6472
6573describe ( 'Editor.replaceFile' , ( ) => {
6674 let blankDocData : { docx : unknown ; mediaFiles : unknown ; fonts : unknown } ;
75+ let initialCollaborativeBuffer : Buffer ;
6776 let replacementBuffer : Buffer ;
6877 let multiSectionReplacementBuffer : Buffer ;
6978
7079 beforeAll ( async ( ) => {
7180 blankDocData = await loadTestDataForEditorTests ( 'blank-doc.docx' ) ;
81+ initialCollaborativeBuffer = await getTestDataAsFileBuffer ( 'advanced-text.docx' ) ;
7282 replacementBuffer = await getTestDataAsFileBuffer ( 'Hello docx world.docx' ) ;
7383 multiSectionReplacementBuffer = await getTestDataAsFileBuffer ( 'multi_section_doc.docx' ) ;
7484 } ) ;
@@ -207,6 +217,54 @@ describe('Editor.replaceFile', () => {
207217 }
208218 } ) ;
209219
220+ it ( 'replaces an already-seeded collaborative room cleanly' , async ( ) => {
221+ const provider = createProviderStub ( ) ;
222+ const ydoc = new YDoc ( ) ;
223+
224+ const editor = createTestEditor ( {
225+ ydoc,
226+ collaborationProvider : provider ,
227+ } ) ;
228+ const expectedEditor = createTestEditor ( ) ;
229+ try {
230+ await editor . open ( initialCollaborativeBuffer , {
231+ mode : 'docx' ,
232+ isNewFile : true ,
233+ } ) ;
234+
235+ provider . emit ( 'synced' , true ) ;
236+ await new Promise ( ( resolve ) => setTimeout ( resolve , 0 ) ) ;
237+
238+ const roomFragmentBeforeReplace = ydoc . getXmlFragment ( 'supereditor' ) ;
239+ expect ( roomFragmentBeforeReplace . length ) . toBeGreaterThan ( 0 ) ;
240+
241+ const initialText = editor . state . doc . textContent ;
242+
243+ await expectedEditor . open ( replacementBuffer , { mode : 'docx' } ) ;
244+ const expectedText = expectedEditor . state . doc . textContent ;
245+
246+ const replacePromise = editor . replaceFile ( replacementBuffer ) ;
247+ await Promise . resolve ( ) ;
248+
249+ provider . emit ( 'synced' , true ) ;
250+ await replacePromise ;
251+
252+ const sharedRoot = yXmlFragmentToProseMirrorRootNode ( ydoc . getXmlFragment ( 'supereditor' ) , editor . schema ) ;
253+ expect ( sharedRoot . textContent ) . toBe ( expectedText ) ;
254+ expect ( editor . state . doc . textContent ) . toBe ( expectedText ) ;
255+ expect ( editor . state . doc . textContent ) . not . toBe ( initialText ) ;
256+ } finally {
257+ if ( editor . lifecycleState === 'ready' ) {
258+ editor . close ( ) ;
259+ }
260+ if ( expectedEditor . lifecycleState === 'ready' ) {
261+ expectedEditor . close ( ) ;
262+ }
263+ editor . destroy ( ) ;
264+ expectedEditor . destroy ( ) ;
265+ }
266+ } ) ;
267+
210268 it ( 'runs collaborative replace side effects once when the provider is already synced' , async ( ) => {
211269 const provider = createProviderStub ( ) ;
212270 provider . synced = true ;
0 commit comments