Browse Source

Changed view test utils getData/setData to not include root element.

Szymon Kupś 9 years ago
parent
commit
0d155d4889

+ 88 - 2
packages/ckeditor5-engine/tests/_utils-tests/view.js

@@ -5,7 +5,7 @@
 
 'use strict';
 
-import { stringify, parse } from '/tests/engine/_utils/view.js';
+import { parse, stringify, getData, setData }from '/tests/engine/_utils/view.js';
 import DocumentFragment from '/ckeditor5/engine/treeview/documentfragment.js';
 import Position from '/ckeditor5/engine/treeview/position.js';
 import Element from '/ckeditor5/engine/treeview/element.js';
@@ -14,8 +14,94 @@ import ContainerElement from '/ckeditor5/engine/treeview/containerelement.js';
 import Text from '/ckeditor5/engine/treeview/text.js';
 import Selection from '/ckeditor5/engine/treeview/selection.js';
 import Range from '/ckeditor5/engine/treeview/range.js';
+import TreeView from '/ckeditor5/engine/treeview/treeview.js';
 
 describe( 'view test utils', () => {
+	describe( 'getData, setData', () => {
+		let sandbox;
+
+		beforeEach( () => {
+			sandbox = sinon.sandbox.create();
+		} );
+
+		afterEach( () => {
+			sandbox.restore();
+		} );
+
+		describe( 'getData', () => {
+			it( 'should use stringify method', () => {
+				const element = document.createElement( 'div' );
+				const stringifySpy = sandbox.spy( getData, '_stringify' );
+				const treeView = new TreeView();
+				const options = { showType: false, showPriority: false };
+				const root = treeView.createRoot( element );
+				root.appendChildren( new Element( 'p' ) );
+
+				expect( getData( treeView, options ) ).to.equal( '<p></p>' );
+				sinon.assert.calledOnce( stringifySpy );
+				expect( stringifySpy.firstCall.args[ 0 ] ).to.equal( root );
+				expect( stringifySpy.firstCall.args[ 1 ] ).to.equal( null );
+				const stringifyOptions = stringifySpy.firstCall.args[ 2 ];
+				expect( stringifyOptions ).to.have.property( 'showType' ).that.equals( false );
+				expect( stringifyOptions ).to.have.property( 'showPriority' ).that.equals( false );
+				expect( stringifyOptions ).to.have.property( 'ignoreRoot' ).that.equals( true );
+			} );
+
+			it( 'should use stringify method with selection', () => {
+				const element = document.createElement( 'div' );
+				const stringifySpy = sandbox.spy( getData, '_stringify' );
+				const treeView = new TreeView();
+				const options = { withSelection: true, showType: false, showPriority: false };
+				const root = treeView.createRoot( element );
+				root.appendChildren( new Element( 'p' ) );
+
+				treeView.selection.addRange( Range.createFromParentsAndOffsets( root, 0, root, 1 ) );
+
+				expect( getData( treeView, options ) ).to.equal( '[<p></p>]' );
+				sinon.assert.calledOnce( stringifySpy );
+				expect( stringifySpy.firstCall.args[ 0 ] ).to.equal( root );
+				expect( stringifySpy.firstCall.args[ 1 ] ).to.equal( treeView.selection );
+				const stringifyOptions = stringifySpy.firstCall.args[ 2 ];
+				expect( stringifyOptions ).to.have.property( 'showType' ).that.equals( false );
+				expect( stringifyOptions ).to.have.property( 'showPriority' ).that.equals( false );
+				expect( stringifyOptions ).to.have.property( 'ignoreRoot' ).that.equals( true );
+			} );
+		} );
+
+		describe( 'setData', () => {
+			it( 'should use parse method', () => {
+				const treeView = new TreeView();
+				const data = 'foobar<b>baz</b>';
+				const parseSpy = sandbox.spy( setData, '_parse' );
+
+				treeView.createRoot( document.createElement( 'div' ) );
+				setData( treeView, data );
+
+				expect( getData( treeView ) ).to.equal( 'foobar<b>baz</b>' );
+				sinon.assert.calledOnce( parseSpy );
+				const args = parseSpy.firstCall.args;
+				expect( args[ 0 ] ).to.equal( data );
+				expect( args[ 1 ] ).to.be.an( 'object' );
+				expect( args[ 1 ].rootElement ).to.equal( treeView.getRoot() );
+			} );
+
+			it( 'should use parse method with selection', () => {
+				const treeView = new TreeView();
+				const data = '[<b>baz</b>]';
+				const parseSpy = sandbox.spy( setData, '_parse' );
+
+				treeView.createRoot( document.createElement( 'div' ) );
+				setData( treeView, data );
+
+				expect( getData( treeView, { withSelection: true } ) ).to.equal( '[<b>baz</b>]' );
+				const args = parseSpy.firstCall.args;
+				expect( args[ 0 ] ).to.equal( data );
+				expect( args[ 1 ] ).to.be.an( 'object' );
+				expect( args[ 1 ].rootElement ).to.equal( treeView.getRoot() );
+			} );
+		} );
+	} );
+
 	describe( 'stringify', () => {
 		it( 'should write text', () => {
 			const text = new Text( 'foobar' );
@@ -434,4 +520,4 @@ describe( 'view test utils', () => {
 			} ).to.throw( Error );
 		} );
 	} );
-} );
+} );

+ 48 - 25
packages/ckeditor5-engine/tests/_utils/view.js

@@ -28,7 +28,7 @@ const TEXT_RANGE_END_TOKEN = '}';
  *
  * @param {engine.treeView.TreeView} treeView
  * @param {Object} [options]
- * @param {Boolean} [options.withSelection] Whether to write the selection.
+ * @param {Boolean} [options.withSelection=false] Whether to write the selection.
  * @param {Boolean} [options.rootName='main'] Name of the root from which data should be stringified. If not provided
  * default `main` name will be used.
  * @param {Boolean} [options.showType=false] When set to `true` type of elements will be printed (`<container:p>`
@@ -37,14 +37,24 @@ const TEXT_RANGE_END_TOKEN = '}';
  * (`<span:12>`, `<b:10>`).
  * @returns {String} The stringified data.
  */
-export function getData( treeView, options ) {
+export function getData( treeView, options = {} ) {
 	const withSelection = !!options.withSelection;
 	const rootName = options.rootName || 'main';
 	const root = treeView.getRoot( rootName );
-
-	return withSelection ? stringify( root, treeView.selection, options ) : stringify( root, null, options );
+	const stringifyOptions = {
+		showType: options.showType,
+		showPriority: options.showPriority,
+		ignoreRoot: true
+	};
+
+	return withSelection ?
+		getData._stringify( root, treeView.selection, stringifyOptions ) :
+		getData._stringify( root, null, stringifyOptions );
 }
 
+// Set stringify as private method inside getData - needed for testing/spying.
+getData._stringify = stringify;
+
 /**
  * Sets the contents of the {@link engine.treeView.TreeView TreeView} provided as HTML-like string.
  *
@@ -55,26 +65,19 @@ export function getData( treeView, options ) {
  * used.
  */
 export function setData( treeView, data, options = {} ) {
-	let view, selection;
 	const rootName = options.rootName || 'main';
-	const result = parse( data );
-
-	if ( result.view && result.selection ) {
-		selection = result.selection;
-		view = result.view;
-	} else {
-		view = result;
-	}
-
 	const root = treeView.getRoot( rootName );
 	root.removeChildren( 0, root.getChildCount() );
-	root.appendChildren( view instanceof DocumentFragment ? view.getChildren() : view );
+	const result = setData._parse( data, { rootElement: root } );
 
-	if ( selection ) {
-		treeView.selection.setTo( selection );
+	if ( result.view && result.selection ) {
+		treeView.selection.setTo( result.selection );
 	}
 }
 
+// Set stringify as private method inside getData - needed for testing/spying.
+setData._parse = parse;
+
 /**
  * Converts view elements to HTML-like string representation.
  * Root element can be provided as {@link engine.treeView.Text Text}:
@@ -166,6 +169,8 @@ export function setData( treeView, data, options = {} ) {
  * instead of `<p>` and `<attribute:b>` instead of `<b>`).
  * @param {Boolean} [options.showPriority=false] When set to `true` AttributeElement's priority will be printed
  * (`<span:12>`, `<b:10>`).
+ * @param {Boolean} [options.ignoreRoot=false] When set to `true` root's element opening and closing will not be printed.
+ * Mainly used by `getData` function to ignore {@link engine.treeView.TreeView TreeView's} root element.
  * @returns {String} HTML-like string representing the view.
  */
 export function stringify( node, selectionOrPositionOrRange = null, options = {} ) {
@@ -231,6 +236,10 @@ export function stringify( node, selectionOrPositionOrRange = null, options = {}
  * selection instance. For example: `[2, 3, 1]` means that first range will be placed as second, second as third and third as first.
  * @param {Boolean} [options.lastRangeBackward=false] If set to true last range will be added as backward to the returned
  * {@link engine.treeView.Selection Selection} instance.
+ * @param {engine.treeView.Element|engine.treeView.DocumentFragment} [options.rootElement=null] Default root to use when parsing elements.
+ * When set to `null` root element will be created automatically. If set to
+ * {@link engine.treeView.Element Element} or {@link engine.treeView.DocumentFragment DocumentFragment} - this node
+ * will be used as root for all parsed nodes.
  * @returns {engine.treeView.Text|engine.treeView.Element|engine.treeView.DocumentFragment|Object} Returns parsed view node
  * or object with two fields `view` and `selection` when selection ranges were included in data to parse.
  */
@@ -239,7 +248,7 @@ export function parse( data, options = {} ) {
 	const viewParser = new ViewParser();
 	const rangeParser = new RangeParser();
 
-	const view = viewParser.parse( data );
+	const view = viewParser.parse( data, options.rootElement );
 	const ranges = rangeParser.parse( view, options.order );
 
 	// When ranges are present - return object containing view, and selection.
@@ -461,16 +470,20 @@ class ViewParser {
 	 * Parses HTML-like string to view tree elements.
 	 *
 	 * @param {String} data
+	 * @param {engine.treeView.Element|engine.treeView.DocumentFragment} [rootElement=null] Default root to use when parsing elements.
+	 * When set to `null` root element will be created automatically. If set to
+	 * {@link engine.treeView.Element Element} or {@link engine.treeView.DocumentFragment DocumentFragment} - this node
+	 * will be used as root for all parsed nodes.
 	 * @returns {engine.treeView.Node|engine.treeView.DocumentFragment}
 	 */
-	parse( data ) {
+	parse( data, rootElement = null ) {
 		const htmlProcessor = new HtmlDataProcessor();
 
 		// Convert HTML string to DOM.
 		const domRoot = htmlProcessor.toDom( data );
 
 		// Convert DOM to View.
-		return this._walkDom( domRoot );
+		return this._walkDom( domRoot, rootElement );
 	}
 
 	/**
@@ -478,9 +491,11 @@ class ViewParser {
 	 *
 	 * @private
 	 * @param {Node} domNode
+	 * @param {engine.treeView.Element|engine.treeView.DocumentFragment} [rootElement=null] Default root element to use
+	 * when parsing elements.
 	 * @returns {engine.treeView.Node|engine.treeView.DocumentFragment}
 	 */
-	_walkDom( domNode ) {
+	_walkDom( domNode, rootElement = null ) {
 		const isDomElement = domNode instanceof DomElement;
 
 		if ( isDomElement || domNode instanceof DomDocumentFragment ) {
@@ -496,8 +511,12 @@ class ViewParser {
 
 			if ( isDomElement ) {
 				viewElement = this._convertElement( domNode );
+
+				if ( rootElement ) {
+					rootElement.appendChild( viewElement );
+				}
 			} else {
-				viewElement = new ViewDocumentFragment();
+				viewElement = rootElement ? rootElement : new ViewDocumentFragment();
 			}
 
 			for ( let i = 0; i < children.length; i++ ) {
@@ -505,7 +524,7 @@ class ViewParser {
 				viewElement.appendChildren( this._walkDom( child ) );
 			}
 
-			return viewElement;
+			return rootElement ? rootElement : viewElement;
 		}
 
 		return new ViewText( domNode.textContent );
@@ -661,6 +680,8 @@ class ViewStringify {
 	 * @param {Boolean} [options.showType=false] When set to `true` type of elements will be printed ( `<container:p>`
 	 * instead of `<p>` and `<attribute:b>` instead of `<b>`.
 	 * @param {Boolean} [options.showPriority=false] When set to `true` AttributeElement's priority will be printed.
+	 * @param {Boolean} [options.ignoreRoot=false] When set to `true` root's element opening and closing tag will not
+	 * be outputted.
 	 */
 	constructor( root, selection = null, options = {} ) {
 		this.root = root;
@@ -673,6 +694,7 @@ class ViewStringify {
 
 		this.showType = !!options.showType;
 		this.showPriority = !!options.showPriority;
+		this.ignoreRoot = !!options.ignoreRoot;
 	}
 
 	/**
@@ -699,9 +721,10 @@ class ViewStringify {
 	 */
 	_walkView( root, callback ) {
 		const isElement = root instanceof ViewElement;
+		const ignore = this.ignoreRoot && this.root === root;
 
 		if ( isElement || root instanceof ViewDocumentFragment ) {
-			if ( isElement ) {
+			if ( isElement && !ignore ) {
 				callback( this._stringifyElementOpen( root ) );
 			}
 
@@ -714,7 +737,7 @@ class ViewStringify {
 				callback( this._stringifyElementRanges( root, offset ) );
 			}
 
-			if ( isElement ) {
+			if ( isElement && !ignore ) {
 				callback( this._stringifyElementClose( root ) );
 			}
 		}