8
0
Просмотр исходного кода

EditingController automated tests.

Piotr Jasiun 9 лет назад
Родитель
Сommit
abbfa48c44

+ 1 - 0
packages/ckeditor5-engine/tests/__template__.html

@@ -0,0 +1 @@
+<div contenteditable="true" id="editor"></div>

+ 264 - 0
packages/ckeditor5-engine/tests/editingcontroller.js

@@ -0,0 +1,264 @@
+/**
+ * @license Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+/* bender-tags: view */
+
+'use strict';
+
+import EditingController from '/ckeditor5/engine/editingcontroller.js';
+
+import ViewDocument from '/ckeditor5/engine/view/document.js';
+import MutationObserver from '/ckeditor5/engine/view/observer/mutationobserver.js';
+import SelectionObserver from '/ckeditor5/engine/view/observer/selectionobserver.js';
+import FocusObserver from '/ckeditor5/engine/view/observer/focusobserver.js';
+import KeyObserver from '/ckeditor5/engine/view/observer/keyobserver.js';
+
+import Mapper from '/ckeditor5/engine/conversion/mapper.js';
+import ModelConversionDispatcher from '/ckeditor5/engine/conversion/modelconversiondispatcher.js';
+import BuildModelConverterFor from '/ckeditor5/engine/conversion/model-converter-builder.js';
+
+import ModelDocument from '/ckeditor5/engine/model/document.js';
+import ModelPosition from '/ckeditor5/engine/model/position.js';
+import ModelRange from '/ckeditor5/engine/model/range.js';
+import ModelDocumentFragment from '/ckeditor5/engine/model/documentfragment.js';
+
+import createElement from '/ckeditor5/utils/dom/createelement.js';
+
+import { parse, getData as getModelData } from '/tests/engine/_utils/model.js';
+import { getData as getViewData } from '/tests/engine/_utils/view.js';
+
+describe( 'EditingController', () => {
+	describe( 'constructor', () => {
+		let model, editing;
+
+		beforeEach( () => {
+			model = new ModelDocument();
+			editing = new EditingController( model );
+		} );
+
+		it( 'should create controller with properties', () => {
+			expect( editing ).to.have.property( 'model' ).that.equals( model );
+			expect( editing ).to.have.property( 'view' ).that.is.instanceof( ViewDocument );
+			expect( editing ).to.have.property( 'mapper' ).that.is.instanceof( Mapper );
+			expect( editing ).to.have.property( 'modelToView' ).that.is.instanceof( ModelConversionDispatcher );
+		} );
+
+		it( 'should add observers', () => {
+			expect( editing.view.getObserver( MutationObserver ) ).to.be.instanceof( MutationObserver );
+			expect( editing.view.getObserver( SelectionObserver ) ).to.be.instanceof( SelectionObserver );
+			expect( editing.view.getObserver( FocusObserver ) ).to.be.instanceof( FocusObserver );
+			expect( editing.view.getObserver( KeyObserver ) ).to.be.instanceof( KeyObserver );
+		} );
+	} );
+
+	describe( 'createRoot', () => {
+		let model, modelRoot, editing;
+
+		beforeEach( () => {
+			model = new ModelDocument();
+			modelRoot = model.createRoot();
+			model.createRoot( 'header' );
+
+			editing = new EditingController( model );
+		} );
+
+		it( 'should create root', () => {
+			const domRoot = createElement( document, 'div', null, createElement( document, 'p' ) );
+
+			const viewRoot = editing.createRoot( domRoot );
+
+			expect( viewRoot ).to.equal( editing.view.getRoot() );
+			expect( domRoot ).to.equal( editing.view.getDomRoot() );
+
+			expect( editing.view.domConverter.getCorrespondingDom( viewRoot ) ).to.equal( domRoot );
+			expect( editing.view.renderer.markedChildren.has( viewRoot ) ).to.be.true;
+
+			expect( editing.mapper.toModelElement( viewRoot ) ).to.equal( modelRoot );
+			expect( editing.mapper.toViewElement( modelRoot ) ).to.equal( viewRoot );
+		} );
+
+		it( 'should create root with given name', () => {
+			const domRoot = createElement( document, 'div', null, createElement( document, 'p' ) );
+
+			const viewRoot = editing.createRoot( domRoot, 'header' );
+
+			expect( viewRoot ).to.equal( editing.view.getRoot( 'header' ) );
+			expect( domRoot ).to.equal( editing.view.getDomRoot( 'header' ) );
+
+			expect( editing.view.domConverter.getCorrespondingDom( viewRoot ) ).to.equal( domRoot );
+			expect( editing.view.renderer.markedChildren.has( viewRoot ) ).to.be.true;
+
+			expect( editing.mapper.toModelElement( viewRoot ) ).to.equal( model.getRoot( 'header' ) );
+			expect( editing.mapper.toViewElement( model.getRoot( 'header' ) ) ).to.equal( viewRoot );
+		} );
+
+		it( 'should be possible to attach DOM element later', () => {
+			const domRoot = createElement( document, 'div', null, createElement( document, 'p' ) );
+
+			const viewRoot = editing.createRoot( 'div' );
+
+			expect( viewRoot ).to.equal( editing.view.getRoot() );
+			expect( editing.view.getDomRoot() ).to.be.undefined;
+
+			editing.view.attachDomRoot( domRoot );
+
+			expect( domRoot ).to.equal( editing.view.getDomRoot() );
+
+			expect( editing.view.domConverter.getCorrespondingDom( viewRoot ) ).to.equal( domRoot );
+			expect( editing.view.renderer.markedChildren.has( viewRoot ) ).to.be.true;
+
+			expect( editing.mapper.toModelElement( viewRoot ) ).to.equal( modelRoot );
+			expect( editing.mapper.toViewElement( modelRoot ) ).to.equal( viewRoot );
+		} );
+	} );
+
+	describe( 'conversion', () => {
+		let model, modelRoot, viewRoot, domRoot, editing;
+
+		before( () => {
+			model = new ModelDocument();
+			modelRoot = model.createRoot();
+
+			editing = new EditingController( model );
+
+			domRoot = document.getElementById( 'editor' );
+			viewRoot = editing.createRoot( domRoot );
+
+			model.schema.registerItem( 'paragraph', '$block' );
+			BuildModelConverterFor( editing.modelToView ).fromElement( 'paragraph' ).toElement( 'p' );
+		} );
+
+		beforeEach( () => {
+			model.selection.removeAllRanges();
+			modelRoot.removeChildren( 0, modelRoot.getChildCount() );
+
+			viewRoot.removeChildren( 0, viewRoot.getChildCount() );
+
+			const modelData = new ModelDocumentFragment( parse(
+				'<paragraph>foo</paragraph>' +
+				'<paragraph></paragraph>' +
+				'<paragraph>bar</paragraph>'
+			)._children );
+
+			model.enqueueChanges( () => {
+				model.batch().insert( ModelPosition.createAt( model.getRoot(), 0 ), modelData );
+				model.selection.addRange( ModelRange.createFromParentsAndOffsets(
+					modelRoot.getChild( 0 ), 1, modelRoot.getChild( 0 ), 1 ) );
+			} );
+		} );
+
+		it( 'should convert insertion', () => {
+			expect( getViewData( editing.view ) ).to.equal( '<p>f{}oo</p><p></p><p>bar</p>' );
+		} );
+
+		it( 'should convert split', () => {
+			expect( getViewData( editing.view ) ).to.equal( '<p>f{}oo</p><p></p><p>bar</p>' );
+
+			model.enqueueChanges( () => {
+				model.batch().split( model.selection.getFirstPosition() );
+				model.selection.setRanges( [
+					ModelRange.createFromParentsAndOffsets(	modelRoot.getChild( 1 ), 0, modelRoot.getChild( 1 ), 0 )
+				] );
+			} );
+
+			expect( getViewData( editing.view ) ).to.equal( '<p>f</p><p>{}oo</p><p></p><p>bar</p>' );
+		} );
+
+		it( 'should convert delete', () => {
+			model.enqueueChanges( () => {
+				model.batch().remove(
+					ModelRange.createFromPositionAndShift( model.selection.getFirstPosition(), 1 )
+				);
+				model.selection.setRanges( [
+					ModelRange.createFromParentsAndOffsets( modelRoot.getChild( 0 ), 1, modelRoot.getChild( 0 ), 1 )
+				] );
+			} );
+
+			expect( getViewData( editing.view ) ).to.equal( '<p>f{}o</p><p></p><p>bar</p>' );
+		} );
+
+		it( 'should convert selection from view to model', ( done ) => {
+			editing.view.on( 'selectionChange', () => {
+				setTimeout( () => {
+					expect( getModelData( model ) ).to.equal(
+						'<paragraph>foo</paragraph>' +
+						'<paragraph></paragraph>' +
+						'<paragraph>b<selection>a</selection>r</paragraph>' );
+					done();
+				} );
+			} );
+
+			const domSelection = document.getSelection();
+			domSelection.removeAllRanges();
+			const domBar = domRoot.childNodes[ 2 ].childNodes[ 0 ];
+			const domRange = new Range();
+			domRange.setStart( domBar, 1 );
+			domRange.setEnd( domBar, 2 );
+			domSelection.addRange( domRange );
+		} );
+
+		it( 'should convert collapsed selection', () => {
+			model.enqueueChanges( () => {
+				model.selection.setRanges( [
+					ModelRange.createFromParentsAndOffsets( modelRoot.getChild( 2 ), 1, modelRoot.getChild( 2 ), 1 )
+				] );
+			} );
+
+			expect( getViewData( editing.view ) ).to.equal( '<p>foo</p><p></p><p>b{}ar</p>' );
+		} );
+
+		it( 'should convert not collapsed selection', () => {
+			model.enqueueChanges( () => {
+				model.selection.setRanges( [
+					ModelRange.createFromParentsAndOffsets( modelRoot.getChild( 2 ), 1, modelRoot.getChild( 2 ), 2 )
+				] );
+			} );
+
+			expect( getViewData( editing.view ) ).to.equal( '<p>foo</p><p></p><p>b{a}r</p>' );
+		} );
+
+		it( 'should clear previous selection', () => {
+			model.enqueueChanges( () => {
+				model.selection.setRanges( [
+					ModelRange.createFromParentsAndOffsets( modelRoot.getChild( 2 ), 1, modelRoot.getChild( 2 ), 1 )
+				] );
+			} );
+
+			expect( getViewData( editing.view ) ).to.equal( '<p>foo</p><p></p><p>b{}ar</p>' );
+
+			model.enqueueChanges( () => {
+				model.selection.setRanges( [
+					ModelRange.createFromParentsAndOffsets( modelRoot.getChild( 2 ), 2, modelRoot.getChild( 2 ), 2 )
+				] );
+			} );
+
+			expect( getViewData( editing.view ) ).to.equal( '<p>foo</p><p></p><p>ba{}r</p>' );
+		} );
+	} );
+
+	describe( 'destroy', () => {
+		it( 'should remove listenters', () => {
+			let model, editing;
+
+			model = new ModelDocument();
+			model.createRoot();
+
+			editing = new EditingController( model );
+
+			const spy = sinon.spy();
+
+			editing.modelToView.on( 'insert:$element', spy );
+
+			editing.destroy();
+
+			model.enqueueChanges( () => {
+				const modelData = parse( '<paragraph>foo</paragraph>' ).getChild( 0 );
+				model.batch().insert( ModelPosition.createAt( model.getRoot(), 0 ), modelData );
+			} );
+
+			expect( spy.called ).to.be.false;
+		} );
+	} );
+} );

+ 3 - 3
packages/ckeditor5-engine/tests/manual/editingcontroller.js

@@ -31,9 +31,9 @@ const modelData = new ModelDocumentFragment( parse(
 	'<paragraph>bar</paragraph>'
 )._children );
 
-model.batch().insert( ModelPosition.createAt( model.getRoot(), 0 ), modelData );
-
-editing.view.render();
+model.enqueueChanges( () => {
+	model.batch().insert( ModelPosition.createAt( model.getRoot(), 0 ), modelData );
+} );
 
 // enter
 editing.view.on( 'keydown', ( evt, data ) => {