import { Client, syncClients, expectClients, clearBuffer } from './utils.js'; describe( 'transform', () => { let john, kate; beforeEach( () => { return Promise.all( [ Client.get( 'john' ).then( client => ( john = client ) ), Client.get( 'kate' ).then( client => ( kate = client ) ) ] ); } ); afterEach( () => { clearBuffer(); return Promise.all( [ john.destroy(), kate.destroy() ] ); } ); describe( 'insert', () => { describe( 'by insert', () => { it( 'elements at same position #1', () => { john.setData( '[]Foo' ); kate.setData( '[]Foo' ); john.insert( 'Abc' ); kate.insert( 'Xyz' ); syncClients(); expectClients( 'Abc' + 'Xyz' + 'Foo' ); } ); it( 'elements at same position #2', () => { john.setData( '[]Foo' ); kate.setData( '[]Foo' ); kate.insert( 'Xyz' ); john.insert( 'Abc' ); syncClients(); expectClients( 'Abc' + 'Xyz' + 'Foo' ); } ); it( 'elements in same parent', () => { john.setData( '[]Foo' ); kate.setData( 'Foo[]' ); john.insert( 'Abc' ); kate.insert( 'Xyz' ); syncClients(); expectClients( 'Abc' + 'Foo' + 'Xyz' ); } ); it( 'elements in same path', () => { john.setData( '[]
Foo
' ); kate.setData( '
[]Foo
' ); john.insert( 'Abc' ); kate.insert( 'Xyz' ); syncClients(); expectClients( 'Abc' + '
' + 'Xyz' + 'Foo' + '
' ); } ); it( 'text at different paths', () => { john.setData( 'Abc[]Xyz' ); kate.setData( 'Abc[]Xyz' ); john.type( 'Foo' ); kate.type( 'Bar' ); syncClients(); expectClients( 'AbcFoo' + 'BarXyz' ); } ); it( 'text, then wrap and undo', () => { john.setData( 'Foo[]' ); kate.setData( 'Foo[]' ); john.type( 'Bar' ); kate.type( 'Abc' ); syncClients(); john.setSelection( [ 0 ], [ 1 ] ); john.wrap( 'blockQuote' ); kate.undo(); syncClients(); expectClients( '
' + 'FooBar' + '
' ); } ); it( 'text, then insert element and merge', () => { john.setData( '[]Abc' ); kate.setData( '[]Abc' ); john.type( 'Foo' ); kate.type( ' Bar' ); syncClients(); expectClients( 'Foo Bar' + 'Abc' ); john.setSelection( [ 1 ] ); kate.setSelection( [ 1 ] ); john.insert( 'Xyz' ); kate.merge(); syncClients(); expectClients( 'Foo BarAbc' + 'Xyz' ); } ); it( 'text, then split and undo', () => { john.setData( '[]' ); kate.setData( '[]' ); john.type( 'Foo' ); kate.type( ' Bar' ); syncClients(); john.setSelection( [ 0, 1 ] ); kate.setSelection( [ 0, 4 ] ); john.split(); kate.split(); syncClients(); john.undo(); kate.undo(); syncClients(); john.undo(); kate.undo(); syncClients(); expectClients( '' ); } ); } ); describe( 'by move', () => { it( 'element at different paths #1', () => { john.setData( '[]FooBar' ); kate.setData( 'FooB[ar]' ); john.insert( 'Abc' ); kate.move( [ 1, 0 ] ); syncClients(); expectClients( 'Abc' + 'Foo' + 'arB' ); } ); it( 'element at different paths #2', () => { john.setData( '
Foo[]
Bar' ); kate.setData( '
Foo
B[ar]' ); john.insert( 'Abc' ); kate.move( [ 0, 0, 0 ] ); syncClients(); expectClients( '
' + 'arFoo' + 'Abc' + '
' + 'B' ); } ); it( 'text at different paths', () => { john.setData( '[]FooBar' ); kate.setData( 'FooB[ar]' ); john.type( 'Abc' ); kate.move( [ 1, 0 ] ); syncClients(); expectClients( 'AbcFoo' + 'arB' ); } ); it( 'text at same path', () => { john.setData( 'F[]oo Bar' ); kate.setData( 'Foo B[ar]' ); john.type( 'Abc' ); kate.move( [ 0, 0 ] ); syncClients(); expectClients( 'arFAbcoo B' ); } ); it( 'text at same position #1', () => { john.setData( 'Foo[] Bar' ); kate.setData( 'Foo [Bar]' ); john.type( 'Abc' ); kate.move( [ 0, 3 ] ); syncClients(); expectClients( 'FooBarAbc ' ); } ); it( 'text at same position #2', () => { john.setData( 'Foo []Bar' ); kate.setData( 'Foo [Bar]' ); john.type( 'Abc' ); kate.move( [ 0, 0 ] ); syncClients(); expectClients( 'BarFoo Abc' ); } ); } ); describe( 'by wrap', () => { it( 'element in same path #1', () => { john.setData( 'Foo Bar[]' ); kate.setData( '[Foo Bar]' ); john.insert( 'Abc' ); kate.wrap( 'blockQuote' ); syncClients(); expectClients( '
' + 'Foo Bar' + '
' + 'Abc' ); } ); // Incorrect result due to wrap/unwrap being represented by inserts and moves. it.skip( 'element in same path #2', () => { john.setData( 'Foo[]' ); kate.setData( '[Foo]' ); john.type( ' Bar' ); kate.wrap( 'blockQuote' ); syncClients(); expectClients( '
' + 'Foo Bar' + '
' ); } ); it( 'element in different paths #1', () => { john.setData( 'Foo[]Bar' ); kate.setData( 'Foo[Bar]' ); john.insert( 'Abc' ); kate.wrap( 'blockQuote' ); syncClients(); expectClients( 'Foo' + 'Abc' + '
' + 'Bar' + '
' ); } ); it( 'element in different paths #2', () => { john.setData( 'FooBar[]' ); kate.setData( '[Foo]Bar' ); john.type( 'Abc' ); kate.wrap( 'blockQuote' ); syncClients(); expectClients( '
' + 'Foo' + '
' + 'BarAbc' ); } ); it( 'element, then unwrap and split', () => { john.setData( 'Foo[]' ); kate.setData( '[Foo]' ); john.type( ' Bar' ); kate.wrap( 'blockQuote' ); syncClients(); expectClients( '
Foo Bar
' ); john.setSelection( [ 0, 0 ] ); kate.setSelection( [ 0, 0, 2 ] ); john.unwrap(); kate.split(); syncClients(); expectClients( 'Fo' + 'o Bar' ); } ); it( 'element, then add marker and split', () => { john.setData( 'Foo[]' ); kate.setData( '[Foo]' ); john.type( ' Bar' ); kate.wrap( 'blockQuote' ); syncClients(); john.setSelection( [ 0, 0, 0 ], [ 0, 0, 3 ] ); kate.setSelection( [ 0, 0, 2 ] ); john.setMarker( 'm1' ); kate.split(); syncClients(); expectClients( '
' + 'Fo' + 'o Bar' + '
' ); } ); it( 'element, then split at the same position and undo', () => { john.setData( 'Foo[]' ); kate.setData( '[Foo]' ); john.type( ' Bar' ); kate.wrap( 'blockQuote' ); syncClients(); expectClients( '
Foo Bar
' ); john.setSelection( [ 0, 0, 3 ] ); kate.setSelection( [ 0, 0, 3 ] ); john.split(); kate.split(); syncClients(); expectClients( '
' + 'Foo' + ' Bar' + '
' ); kate.undo(); syncClients(); // Below is not the best result ever but it is acceptable. expectClients( '
' + 'Foo Bar' + '
' ); } ); } ); describe( 'by unwrap', () => { it( 'element in different path', () => { john.setData( 'Foo[]
Bar
' ); kate.setData( 'Foo
[Bar]
' ); john.type( 'Abc' ); kate.unwrap(); syncClients(); expectClients( 'FooAbcBar' ); } ); it( 'text in different path', () => { john.setData( 'Foo[]
Bar
' ); kate.setData( 'Foo
[]Bar
' ); john.type( 'Abc' ); kate.unwrap(); syncClients(); expectClients( 'FooAbc
Bar
' ); } ); it( 'element in same path #1', () => { john.setData( '
Foo[]
' ); kate.setData( '
[Foo]
' ); john.type( ' Bar' ); kate.unwrap(); syncClients(); expectClients( 'Foo Bar' ); } ); it( 'element in same path #2', () => { john.setData( '
Foo[]
' ); kate.setData( '
[Foo]
' ); john.insert( 'Bar' ); kate.unwrap(); syncClients(); // Below would be the expected effect with correct wrap transformation. // expectClients( // 'Foo' + // 'Bar' // ); expectClients( 'Foo' ); } ); it( 'element, then wrap and undo on both clients', () => { john.setData( '
Foo[]
' ); kate.setData( '
[Foo]
' ); john.insert( 'Bar' ); kate.unwrap(); syncClients(); kate.setSelection( [ 0 ], [ 1 ] ); kate.wrap( 'blockQuote' ); john.undo(); syncClients(); expectClients( '
' + 'Foo' + '
' ); } ); it( 'element, then wrap, unwrap and undo', () => { john.setData( '
Foo[]
' ); kate.setData( '
[]Foo
' ); john.type( ' Bar' ); kate.unwrap(); syncClients(); expectClients( 'Foo Bar' ); john.setSelection( [ 0 ], [ 1 ] ); john.wrap( 'blockQuote' ); syncClients(); expectClients( '
Foo Bar
' ); john.undo(); kate.setSelection( [ 0, 0 ], [ 0, 1 ] ); kate.unwrap(); syncClients(); expectClients( 'Foo Bar' ); } ); } ); describe( 'by split', () => { it( 'text in same path #1', () => { john.setData( 'Foo[]' ); kate.setData( 'F[]oo' ); john.insert( 'Bar' ); kate.split(); syncClients(); expectClients( 'F' + 'oo' + 'Bar' ); } ); it( 'text in same path #2', () => { john.setData( 'Fo[]o' ); kate.setData( 'F[]oo' ); john.type( 'Bar' ); kate.split(); syncClients(); expectClients( 'FoBaro' ); } ); it( 'text in different paths #1', () => { john.setData( '[]FooBar' ); kate.setData( 'FooB[]ar' ); john.insert( 'Abc' ); kate.split(); syncClients(); expectClients( 'Abc' + 'Foo' + 'B' + 'ar' ); } ); it( 'text in different paths #2', () => { john.setData( 'Foo[]Bar' ); kate.setData( 'FooB[]ar' ); john.type( 'Abc' ); kate.split(); syncClients(); expectClients( 'FooAbc' + 'B' + 'ar' ); } ); it( 'text at same position', () => { john.setData( 'F[]oo' ); kate.setData( 'F[]oo' ); john.type( 'Bar' ); kate.split(); syncClients(); expectClients( 'FBaroo' ); } ); it( 'text at same position #2', () => { john.setData( 'Foo[]' ); kate.setData( 'Foo[]' ); john.type( 'Bar' ); kate.split(); syncClients(); expectClients( 'FooBar' ); } ); it( 'text, then insert element and split', () => { john.setData( '[]Foo' ); kate.setData( 'F[]oo' ); john.type( 'Bar' ); kate.split(); syncClients(); john.setSelection( [ 1 ] ); kate.setSelection( [ 1, 1 ] ); john.insert( 'Abc' ); kate.split(); syncClients(); expectClients( 'BarF' + 'Abc' + 'o' + 'o' ); } ); } ); describe( 'by remove', () => { it( 'text in different path', () => { john.setData( 'Foo[]Bar' ); kate.setData( 'Foo[Bar]' ); john.type( 'Abc' ); kate.remove(); syncClients(); expectClients( 'FooAbc' ); } ); it( 'text in same path', () => { john.setData( 'Foo[]' ); kate.setData( '[Foo]' ); john.type( 'Bar' ); kate.remove(); syncClients(); expectClients( 'Bar' ); } ); it( 'element in different path', () => { john.setData( 'Foo[]Bar' ); kate.setData( 'Foo[Bar]' ); john.type( 'Abc' ); kate.remove(); syncClients(); expectClients( 'FooAbc' ); } ); it( 'element in same path', () => { john.setData( 'Foo[]Bar' ); kate.setData( '[Foo]Bar' ); john.type( 'Abc' ); kate.remove(); syncClients(); expectClients( 'Bar' ); } ); it( 'text, then rename, split and undo', () => { john.setData( 'Foo Bar[]' ); kate.setData( 'Foo [Bar]' ); john.type( 'Bar' ); kate.remove(); syncClients(); expectClients( 'Foo Bar' ); john.setSelection( [ 0, 0 ] ); kate.setSelection( [ 0, 4 ] ); john.rename( 'heading1' ); kate.split(); syncClients(); expectClients( 'Foo Bar' ); kate.undo(); syncClients(); expectClients( 'Foo Bar' ); } ); it( 'element, then add marker, split and undo with type #1', () => { john.setData( 'Foo[]' ); kate.setData( '[Foo]' ); john.insert( 'Bar' ); kate.remove(); syncClients(); expectClients( 'Bar' ); // Autoparagraphing. john.setSelection( [ 0, 0 ], [ 0, 3 ] ); kate.setSelection( [ 0, 2 ] ); john.setMarker( 'm1' ); kate.split(); syncClients(); expectClients( 'Ba' + 'r' + '' ); john.undo(); john.setSelection( [ 1, 1 ] ); john.type( 'Abc' ); kate.undo(); syncClients(); expectClients( 'BarAbc' ); kate.undo(); syncClients(); expectClients( 'FooBarAbc' ); } ); it( 'element, then add marker, split and undo with type #2', () => { john.setData( 'Foo[]' ); kate.setData( '[Foo]' ); john.insert( 'Bar' ); kate.remove(); syncClients(); expectClients( 'Bar' ); // Autoparagraphing. john.setSelection( [ 0, 0 ], [ 0, 3 ] ); kate.setSelection( [ 0, 2 ] ); john.setMarker( 'm1' ); kate.split(); syncClients(); expectClients( 'Ba' + 'r' + '' ); john.undo(); john.setSelection( [ 1, 1 ] ); john.type( 'Abc' ); kate.undo(); kate.undo(); syncClients(); expectClients( 'FooBarAbc' ); } ); } ); describe( 'by merge', () => { it( 'element into paragraph', () => { john.setData( 'Foo[]' ); kate.setData( 'Foo[]' ); john.type( ' Bar' ); kate.merge(); syncClients(); expectClients( 'Foo Bar' ); } ); } ); describe( 'by marker', () => { it( 'in different path #1', () => { john.setData( '[]FooBar' ); kate.setData( 'Foo[Bar]' ); john.insert( 'Abc' ); kate.setMarker( 'm1' ); syncClients(); expectClients( 'Abc' + 'Foo' + 'Bar' ); } ); it( 'in different path #2', () => { john.setData( 'Foo[]Bar' ); kate.setData( 'Foo[Bar]' ); john.type( 'Abc' ); kate.setMarker( 'm1' ); syncClients(); expectClients( 'FooAbc' + 'Bar' ); } ); it( 'in same path', () => { john.setData( '[]Foo' ); kate.setData( 'Fo[o]' ); john.type( 'Bar' ); kate.setMarker( 'm1' ); syncClients(); expectClients( 'BarFoo' ); } ); } ); describe( 'by rename', () => { it( 'element in different path', () => { john.setData( 'FooBar[]' ); kate.setData( 'F[]ooBar' ); john.insert( 'Abc' ); kate.rename( 'heading1' ); syncClients(); expectClients( 'Foo' + 'Bar' + 'Abc' ); } ); it( 'element in same path', () => { john.setData( 'Foo[]' ); kate.setData( 'F[]oo' ); john.insert( 'Bar' ); kate.rename( 'heading1' ); syncClients(); expectClients( 'Foo' + 'Bar' ); } ); it( 'text in same path', () => { john.setData( 'Foo[] Bar' ); kate.setData( 'F[]oo Bar' ); john.type( 'Abc' ); kate.rename( 'heading1' ); syncClients(); expectClients( 'FooAbc Bar' ); } ); it( 'text in different paths', () => { john.setData( '
Foo
B[]ar' ); kate.setData( '
F[]oo
Bar' ); john.type( 'Abc' ); kate.rename( 'heading1' ); syncClients(); expectClients( '
' + 'Foo' + '
' + 'BAbcar' ); } ); } ); } ); } );