/** * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved. * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license */ /* globals document */ import ClassicTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/classictesteditor'; import Typing from '../src/typing'; import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph'; import Undo from '@ckeditor/ckeditor5-undo/src/undo'; import Bold from '@ckeditor/ckeditor5-basic-styles/src/bold'; import Italic from '@ckeditor/ckeditor5-basic-styles/src/italic'; import Enter from '@ckeditor/ckeditor5-enter/src/enter'; import { getData as getModelData, setData as setModelData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model'; import { getData as getViewData } from '@ckeditor/ckeditor5-engine/src/dev-utils/view'; describe( 'Typing – InputCommand integration', () => { let editor, model, doc, viewDocument, boldView, italicView, editorElement; beforeEach( () => { editorElement = document.createElement( 'div' ); document.body.appendChild( editorElement ); return ClassicTestEditor .create( editorElement, { plugins: [ Typing, Paragraph, Undo, Bold, Italic, Enter ], typing: { undoStep: 3 } } ) .then( newEditor => { editor = newEditor; model = editor.model; doc = model.document; viewDocument = editor.editing.view; boldView = editor.ui.componentFactory.create( 'bold' ); italicView = editor.ui.componentFactory.create( 'italic' ); } ); } ); afterEach( () => { editorElement.remove(); return editor.destroy(); } ); function expectOutput( modelOutput, viewOutput ) { expect( getModelData( model ) ).to.equal( modelOutput ); expect( getViewData( viewDocument ) ).to.equal( viewOutput ); } function simulateTyping( text ) { // While typing, every character is an atomic change. text.split( '' ).forEach( character => { editor.execute( 'input', { text: character } ); } ); } function simulateBatches( batches ) { // Use longer text at once in input command. batches.forEach( batch => { editor.execute( 'input', { text: batch } ); } ); } function setSelection( pathA, pathB ) { model.change( writer => { writer.setSelection( writer.createRange( writer.createPositionFromPath( doc.getRoot(), pathA ), writer.createPositionFromPath( doc.getRoot(), pathB ) ) ); } ); } describe( 'InputCommand integration', () => { it( 'resets the buffer on typing respecting typing.undoStep', () => { setModelData( model, '0[]' ); simulateTyping( '123456789' ); expectOutput( '0123456789[]', '

0123456789{}

' ); editor.execute( 'undo' ); expectOutput( '0123456[]', '

0123456{}

' ); editor.execute( 'undo' ); expectOutput( '0123[]', '

0123{}

' ); editor.execute( 'redo' ); expectOutput( '0123456[]', '

0123456{}

' ); } ); it( 'resets the buffer on text insertion respecting typing.undoStep', () => { setModelData( model, '0[]' ); simulateBatches( [ '1234', '5', '678', '9' ] ); expectOutput( '0123456789[]', '

0123456789{}

' ); editor.execute( 'undo' ); expectOutput( '012345678[]', '

012345678{}

' ); editor.execute( 'undo' ); expectOutput( '01234[]', '

01234{}

' ); editor.execute( 'redo' ); expectOutput( '012345678[]', '

012345678{}

' ); } ); it( 'resets the buffer when selection changes', () => { setModelData( model, 'Foo[] Bar' ); setSelection( [ 0, 5 ], [ 0, 5 ] ); simulateTyping( '1' ); setSelection( [ 0, 7 ], [ 0, 8 ] ); simulateTyping( '2' ); expectOutput( 'Foo B1a2[]', '

Foo B1a2{}

' ); editor.execute( 'undo' ); expectOutput( 'Foo B1a[r]', '

Foo B1a{r}

' ); editor.execute( 'undo' ); expectOutput( 'Foo B[]ar', '

Foo B{}ar

' ); editor.execute( 'redo' ); expectOutput( 'Foo B1[]ar', '

Foo B1{}ar

' ); } ); it( 'resets the buffer when selection changes (with enter)', () => { setModelData( model, 'Foo[]Bar' ); simulateTyping( '1' ); editor.execute( 'enter' ); setSelection( [ 1, 3 ], [ 1, 3 ] ); simulateTyping( '2' ); editor.execute( 'enter' ); simulateTyping( 'Baz' ); expectOutput( 'Foo1Bar2Baz[]', '

Foo1

Bar2

Baz{}

' ); editor.execute( 'undo' ); expectOutput( 'Foo1Bar2[]', '

Foo1

Bar2

[]

' ); editor.execute( 'undo' ); expectOutput( 'Foo1Bar2[]', '

Foo1

Bar2{}

' ); editor.execute( 'undo' ); expectOutput( 'Foo1Bar[]', '

Foo1

Bar{}

' ); editor.execute( 'redo' ); expectOutput( 'Foo1Bar2[]', '

Foo1

Bar2{}

' ); } ); it( 'resets the buffer when attribute changes', () => { setModelData( model, 'Foo[] Bar' ); simulateTyping( ' ' ); boldView.fire( 'execute' ); simulateTyping( 'B' ); italicView.fire( 'execute' ); simulateTyping( 'a' ); boldView.fire( 'execute' ); italicView.fire( 'execute' ); simulateTyping( 'z' ); expectOutput( 'Foo <$text bold="true">B<$text bold="true" italic="true">az[] Bar', '

Foo Baz{} Bar

' ); editor.execute( 'undo' ); expectOutput( 'Foo <$text bold="true">B<$text bold="true" italic="true">a[] Bar', '

Foo Ba{} Bar

' ); editor.execute( 'undo' ); expectOutput( 'Foo <$text bold="true">B[] Bar', '

Foo B{} Bar

' ); } ); } ); } );