/** * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved. * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license */ import ModelTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/modeltesteditor'; import EnterCommand from '../src/entercommand'; import { getData, setData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model'; describe( 'EnterCommand', () => { let editor, model, doc, schema, command; beforeEach( () => { return ModelTestEditor.create() .then( newEditor => { editor = newEditor; model = editor.model; doc = model.document; command = new EnterCommand( editor ); editor.commands.add( 'enter', command ); schema = model.schema; // Note: We could use real names like 'paragraph', but that would make test patterns too long. // Plus, this is actually a good test that the algorithm can be used for any model. schema.register( 'img', { allowWhere: '$block' } ); schema.register( 'p', { inheritAllFrom: '$block', allowIn: 'blockLimit' } ); schema.register( 'h', { inheritAllFrom: '$block' } ); schema.register( 'inlineLimit', { allowIn: 'p', isLimit: true } ); schema.register( 'blockLimit', { allowIn: '$root', isLimit: true } ); schema.extend( '$text', { allowIn: [ 'inlineLimit', '$root' ] } ); } ); } ); describe( 'EnterCommand', () => { it( 'splits a block using parent batch', () => { setData( model, '
foo[]
' ); model.change( writer => { expect( writer.batch.operations ).to.length( 0 ); editor.execute( 'enter' ); expect( writer.batch.operations ).to.length.above( 0 ); } ); } ); } ); describe( 'execute()', () => { describe( 'collapsed selection', () => { test( 'does nothing in the root', 'foo[]bar', 'foo[]bar' ); test( 'splits block', 'x
foo[]bar
y
', 'x
foo
[]bar
y
' ); test( 'splits block at the end', 'x
foo[]
y
', 'x
foo
[]
y
' ); test( 'splits block at the beginning', 'x
[]foo
y
', 'x
[]foo
y
' ); test( 'inserts new block after empty one', 'x
[]
y
', 'x
[]
y
' ); describe( 'copyOnEnter', () => { beforeEach( () => { schema.extend( '$text', { allowAttributes: [ 'foo', 'bar' ] } ); schema.setAttributeProperties( 'foo', { copyOnEnter: true } ); } ); test( 'allowed attributes are copied', '<$text foo="true">test[]$text>
', '<$text foo="true">test$text>
<$text foo="true">[]$text>
' ); test( 'unknown attributes are not copied', '<$text bar="true">test[]$text>
', '<$text bar="true">test$text>
[]
' ); test( 'only allowed attributes are copied from mix set', '<$text bar="true" foo="true">test[]$text>
', '<$text bar="true" foo="true">test$text>
<$text foo="true">[]$text>
' ); } ); } ); describe( 'non-collapsed selection', () => { test( 'only deletes the content when directly in the root', 'fo[ob]ar', 'fo[]ar' ); test( 'deletes text and splits', 'ab[cd]ef
ghi
', 'ab
[]ef
ghi
' ); test( 'places selection in the 2nd element', 'd]ef
ghi
', '[]ef
ghi
' ); test( 'leaves one empty element after one was fully selected', 'x
[abcdef]
y
', 'x
[]
y
' ); test( 'leaves one empty element after two were fully selected', '[abc
def]
', '[]
' ); test( 'should not break inline limit elements - collapsed', 'f]oo
' ); command.execute(); expect( getData( model ) ).to.equal( 'f]oo
' ); } ); } ); test( 'should break paragraph in blockLimit', 'foo[]bar
foo
[]bar
[abc
def]
' ); // @TODO: Add option for setting selection direction to model utils. doc.selection._lastRangeBackward = true; command.execute(); expect( getData( model ) ).to.equal( '[]
' ); } ); it( 'uses DataController.deleteContent', () => { const spy = sinon.spy(); editor.model.on( 'deleteContent', spy ); setData( model, '[x]
' ); command.execute(); expect( spy.calledOnce ).to.be.true; } ); } ); function test( title, input, output ) { it( title, () => { setData( model, input ); command.execute(); expect( getData( model ) ).to.equal( output ); } ); } } ); } );